@obolnetwork/obol-sdk 2.4.4 → 2.4.6
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 +1 -1
- package/dist/cjs/package.json +6 -5
- package/dist/cjs/src/incentiveHelpers.js +2 -4
- package/dist/cjs/src/incentives.js +26 -5
- package/dist/cjs/src/index.js +3 -1
- package/dist/cjs/src/services.js +3 -2
- package/dist/cjs/src/types.js +0 -9
- package/dist/cjs/src/utils.js +4 -4
- package/dist/cjs/src/verification/common.js +12 -9
- package/dist/cjs/src/verification/signature-validator.js +6 -5
- package/dist/cjs/test/incentives.test.js +4 -4
- package/dist/cjs/test/methods.test.js +11 -0
- package/dist/esm/package.json +6 -5
- package/dist/esm/src/incentiveHelpers.js +3 -5
- package/dist/esm/src/incentives.js +26 -5
- package/dist/esm/src/index.js +2 -1
- package/dist/esm/src/services.js +3 -2
- package/dist/esm/src/splitHelpers.js +1 -1
- package/dist/esm/src/types.js +0 -9
- package/dist/esm/src/utils.js +4 -4
- package/dist/esm/src/verification/common.js +12 -9
- package/dist/esm/src/verification/signature-validator.js +6 -5
- package/dist/esm/test/incentives.test.js +4 -4
- package/dist/esm/test/methods.test.js +11 -0
- package/dist/types/src/incentiveHelpers.d.ts +3 -4
- package/dist/types/src/incentives.d.ts +29 -13
- package/dist/types/src/index.d.ts +15 -4
- package/dist/types/src/services.d.ts +3 -2
- package/dist/types/src/splitHelpers.d.ts +7 -8
- package/dist/types/src/types.d.ts +21 -5
- package/dist/types/src/utils.d.ts +5 -5
- package/dist/types/src/verification/common.d.ts +2 -2
- package/dist/types/src/verification/signature-validator.d.ts +5 -2
- package/package.json +6 -5
- package/src/incentiveHelpers.ts +5 -15
- package/src/incentives.ts +37 -33
- package/src/index.ts +27 -23
- package/src/services.ts +4 -2
- package/src/splitHelpers.ts +9 -14
- package/src/types.ts +37 -17
- package/src/utils.ts +11 -8
- package/src/verification/common.ts +13 -1
- package/src/verification/signature-validator.ts +10 -3
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ If you're integrating this SDK with a **backend** (e.g., in Node.js), and you st
|
|
|
19
19
|
|
|
20
20
|
## ⚡️ Integration with Safe Wallet
|
|
21
21
|
|
|
22
|
-
When integrating the Obol SDK with a **Safe Wallet**, you
|
|
22
|
+
When integrating the Obol SDK with a **Safe Wallet**, you can either pass an RPC URL OR provide the `RPC_MAINNET` or `RPC_HOLESKY` or `RPC_GNOSIS` or `RPC_SEPOLIA` environment variable, pointing to the correct network's RPC URL. This is required to interact with Safe kit.
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
## Contributing
|
package/dist/cjs/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obolnetwork/obol-sdk",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.6",
|
|
4
4
|
"description": "A package for creating Distributed Validators using the Obol API.",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/obolnetwork/obol-sdk/issues"
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"lint": "eslint \"{src,test}/**/*.{js,ts}\" --fix",
|
|
24
24
|
"lint-ci": "eslint \"{src,test}/**/*.{js,ts}\"",
|
|
25
25
|
"prettier-ci": "prettier --check \"{src,test}/**/*.{js,ts}\"",
|
|
26
|
-
"prettier": "prettier --write \"{src,test}/**/*.{js,ts}\""
|
|
26
|
+
"prettier": "prettier --write \"{src,test}/**/*.{js,ts}\"",
|
|
27
|
+
"docs": "typedoc"
|
|
27
28
|
},
|
|
28
29
|
"main": "./dist/cjs/src/index.js",
|
|
29
30
|
"module": "./dist/esm/src/index.js",
|
|
@@ -55,7 +56,7 @@
|
|
|
55
56
|
"eslint-plugin-import": "^2.29.1",
|
|
56
57
|
"eslint-plugin-n": "^16.6.2",
|
|
57
58
|
"eslint-plugin-promise": "^6.1.1",
|
|
58
|
-
"ethers": "6.
|
|
59
|
+
"ethers": "^6.13.5",
|
|
59
60
|
"nock": "^13.5.3",
|
|
60
61
|
"pdf-parse": "^1.1.1",
|
|
61
62
|
"semver": "^7.6.0",
|
|
@@ -79,8 +80,8 @@
|
|
|
79
80
|
"release-it": "^17.2.1",
|
|
80
81
|
"ts-jest": "^28.0.8",
|
|
81
82
|
"tsup": "^6.7.0",
|
|
82
|
-
"typedoc": "^0.
|
|
83
|
-
"typedoc-plugin-markdown": "^4.
|
|
83
|
+
"typedoc": "^0.28.0",
|
|
84
|
+
"typedoc-plugin-markdown": "^4.5.2",
|
|
84
85
|
"typescript": "~5.3.3"
|
|
85
86
|
},
|
|
86
87
|
"engines": {
|
|
@@ -12,7 +12,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.isClaimedFromMerkleDistributor = exports.claimIncentivesFromMerkleDistributor = void 0;
|
|
13
13
|
const ethers_1 = require("ethers");
|
|
14
14
|
const MerkleDistributorWithDeadline_1 = require("./abi/MerkleDistributorWithDeadline");
|
|
15
|
-
const utils_1 = require("./utils");
|
|
16
15
|
const claimIncentivesFromMerkleDistributor = (incentivesData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
16
|
try {
|
|
18
17
|
const contract = new ethers_1.Contract(incentivesData.contractAddress, MerkleDistributorWithDeadline_1.MerkleDistributorABI.abi, incentivesData.signer);
|
|
@@ -26,10 +25,9 @@ const claimIncentivesFromMerkleDistributor = (incentivesData) => __awaiter(void
|
|
|
26
25
|
}
|
|
27
26
|
});
|
|
28
27
|
exports.claimIncentivesFromMerkleDistributor = claimIncentivesFromMerkleDistributor;
|
|
29
|
-
const isClaimedFromMerkleDistributor = (
|
|
28
|
+
const isClaimedFromMerkleDistributor = (contractAddress, index, provider) => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
29
|
try {
|
|
31
|
-
const
|
|
32
|
-
const contract = new ethers_1.Contract(contractAddress, MerkleDistributorWithDeadline_1.MerkleDistributorABI.abi, clientProvider);
|
|
30
|
+
const contract = new ethers_1.Contract(contractAddress, MerkleDistributorWithDeadline_1.MerkleDistributorABI.abi, provider);
|
|
33
31
|
const claimed = yield contract.isClaimed(BigInt(index));
|
|
34
32
|
return claimed;
|
|
35
33
|
}
|
|
@@ -14,6 +14,14 @@ const utils_1 = require("./utils");
|
|
|
14
14
|
const types_1 = require("./types");
|
|
15
15
|
const incentiveHelpers_1 = require("./incentiveHelpers");
|
|
16
16
|
const constants_1 = require("./constants");
|
|
17
|
+
/**
|
|
18
|
+
* Incentives can be used for fetching and claiming Obol incentives.
|
|
19
|
+
* @class
|
|
20
|
+
* @internal Access it through Client.incentives.
|
|
21
|
+
* @example
|
|
22
|
+
* const obolClient = new Client(config);
|
|
23
|
+
* await obolClient.incentives.claimIncentives(address);
|
|
24
|
+
*/
|
|
17
25
|
class Incentives {
|
|
18
26
|
constructor(signer, chainId, request, provider) {
|
|
19
27
|
this.signer = signer;
|
|
@@ -22,16 +30,23 @@ class Incentives {
|
|
|
22
30
|
this.provider = provider;
|
|
23
31
|
}
|
|
24
32
|
/**
|
|
25
|
-
* Claims
|
|
26
|
-
*
|
|
33
|
+
* Claims Obol incentives from a Merkle Distributor contract using an address.
|
|
34
|
+
*
|
|
35
|
+
* This method automatically fetches incentive data and verifies whether the incentives have already been claimed.
|
|
36
|
+
* If `txHash` is `null`, it indicates that the incentives were already claimed.
|
|
37
|
+
*
|
|
38
|
+
* Note: This method is not yet enabled and will throw an error if called.
|
|
27
39
|
*
|
|
28
40
|
* @remarks
|
|
29
41
|
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
30
42
|
* and not pushed to version control.
|
|
31
43
|
*
|
|
32
44
|
* @param {string} address - The address to claim incentives for
|
|
33
|
-
* @returns {Promise<
|
|
45
|
+
* @returns {Promise<ClaimIncentivesResponse>} The transaction hash or already claimed status
|
|
34
46
|
* @throws Will throw an error if the incentives data is not found or the claim fails
|
|
47
|
+
*
|
|
48
|
+
* An example of how to use claimIncentives:
|
|
49
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L281)
|
|
35
50
|
*/
|
|
36
51
|
claimIncentives(address) {
|
|
37
52
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -49,7 +64,7 @@ class Incentives {
|
|
|
49
64
|
}
|
|
50
65
|
const claimed = yield this.isClaimed(incentivesData.contract_address, incentivesData.index);
|
|
51
66
|
if (claimed) {
|
|
52
|
-
return {
|
|
67
|
+
return { txHash: null };
|
|
53
68
|
}
|
|
54
69
|
const { txHash } = yield (0, incentiveHelpers_1.claimIncentivesFromMerkleDistributor)({
|
|
55
70
|
signer: this.signer,
|
|
@@ -74,16 +89,22 @@ class Incentives {
|
|
|
74
89
|
* @param {ETH_ADDRESS} index - operator index in merkle tree
|
|
75
90
|
* @returns {Promise<boolean>} true if incentives are already claime
|
|
76
91
|
*
|
|
92
|
+
*
|
|
93
|
+
* An example of how to use isClaimed:
|
|
94
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L266)
|
|
77
95
|
*/
|
|
78
96
|
isClaimed(contractAddress, index) {
|
|
79
97
|
return __awaiter(this, void 0, void 0, function* () {
|
|
80
|
-
return yield (0, incentiveHelpers_1.isClaimedFromMerkleDistributor)(
|
|
98
|
+
return yield (0, incentiveHelpers_1.isClaimedFromMerkleDistributor)(contractAddress, index, this.provider);
|
|
81
99
|
});
|
|
82
100
|
}
|
|
83
101
|
/**
|
|
84
102
|
* @param address - Operator address
|
|
85
103
|
* @returns {Promise<IncentivesType>} The matched incentives from DB
|
|
86
104
|
* @throws On not found if address not found.
|
|
105
|
+
*
|
|
106
|
+
* An example of how to use getIncentivesByAddress:
|
|
107
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L250)
|
|
87
108
|
*/
|
|
88
109
|
getIncentivesByAddress(address) {
|
|
89
110
|
return __awaiter(this, void 0, void 0, function* () {
|
package/dist/cjs/src/index.js
CHANGED
|
@@ -23,7 +23,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
23
23
|
});
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.Client = void 0;
|
|
26
|
+
exports.Client = exports.Incentives = void 0;
|
|
27
27
|
const ethers_1 = require("ethers");
|
|
28
28
|
const uuid_1 = require("uuid");
|
|
29
29
|
const base_js_1 = require("./base.js");
|
|
@@ -39,6 +39,8 @@ __exportStar(require("./types.js"), exports);
|
|
|
39
39
|
__exportStar(require("./services.js"), exports);
|
|
40
40
|
__exportStar(require("./verification/signature-validator.js"), exports);
|
|
41
41
|
__exportStar(require("./verification/common.js"), exports);
|
|
42
|
+
var incentives_js_2 = require("./incentives.js");
|
|
43
|
+
Object.defineProperty(exports, "Incentives", { enumerable: true, get: function () { return incentives_js_2.Incentives; } });
|
|
42
44
|
/**
|
|
43
45
|
* Obol sdk Client can be used for creating, managing and activating distributed validators.
|
|
44
46
|
*/
|
package/dist/cjs/src/services.js
CHANGED
|
@@ -14,15 +14,16 @@ const common_js_1 = require("./verification/common.js");
|
|
|
14
14
|
/**
|
|
15
15
|
* Verifies Cluster Lock's validity.
|
|
16
16
|
* @param lock - cluster lock
|
|
17
|
+
* @param safeRpcUrl - optional safeRpcUrl for safe wallet verification
|
|
17
18
|
* @returns {Promise<{ result: boolean }> } boolean result to indicate if lock is valid
|
|
18
19
|
* @throws on missing keys or values.
|
|
19
20
|
*
|
|
20
21
|
* An example of how to use validateClusterLock:
|
|
21
22
|
* [validateClusterLock](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L127)
|
|
22
23
|
*/
|
|
23
|
-
const validateClusterLock = (lock) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
+
const validateClusterLock = (lock, safeRpcUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
25
|
try {
|
|
25
|
-
const isLockValid = yield (0, common_js_1.isValidClusterLock)(lock);
|
|
26
|
+
const isLockValid = yield (0, common_js_1.isValidClusterLock)(lock, safeRpcUrl);
|
|
26
27
|
return isLockValid;
|
|
27
28
|
}
|
|
28
29
|
catch (err) {
|
package/dist/cjs/src/types.js
CHANGED
|
@@ -19,20 +19,11 @@ var FORK_MAPPING;
|
|
|
19
19
|
/** Hoodi Chain. */
|
|
20
20
|
FORK_MAPPING[FORK_MAPPING["0x10000910"] = 560048] = "0x10000910";
|
|
21
21
|
})(FORK_MAPPING || (exports.FORK_MAPPING = FORK_MAPPING = {}));
|
|
22
|
-
/**
|
|
23
|
-
* Permitted Chain Names
|
|
24
|
-
*/
|
|
25
22
|
exports.FORK_NAMES = {
|
|
26
|
-
/** Mainnet. */
|
|
27
23
|
[FORK_MAPPING['0x00000000']]: 'mainnet',
|
|
28
|
-
/** Goerli/Prater. */
|
|
29
24
|
[FORK_MAPPING['0x00001020']]: 'goerli',
|
|
30
|
-
/** Gnosis Chain. */
|
|
31
25
|
[FORK_MAPPING['0x00000064']]: 'gnosis',
|
|
32
|
-
/** Holesky. */
|
|
33
26
|
[FORK_MAPPING['0x01017000']]: 'holesky',
|
|
34
|
-
/** Sepolia. */
|
|
35
27
|
[FORK_MAPPING['0x90000069']]: 'sepolia',
|
|
36
|
-
/** Hoodi. */
|
|
37
28
|
[FORK_MAPPING['0x10000910']]: 'hoodi',
|
|
38
29
|
};
|
package/dist/cjs/src/utils.js
CHANGED
|
@@ -67,11 +67,11 @@ const isContractAvailable = (contractAddress, provider, bytecode) => __awaiter(v
|
|
|
67
67
|
return !!code && code !== '0x' && code !== '0x0';
|
|
68
68
|
});
|
|
69
69
|
exports.isContractAvailable = isContractAvailable;
|
|
70
|
-
const getProvider = (chainId) => {
|
|
71
|
-
const
|
|
72
|
-
if (!
|
|
70
|
+
const getProvider = (chainId, rpcUrl) => {
|
|
71
|
+
const resolvedRpcUrl = rpcUrl !== null && rpcUrl !== void 0 ? rpcUrl : constants_1.PROVIDER_MAP[chainId];
|
|
72
|
+
if (chainId && (!resolvedRpcUrl || resolvedRpcUrl === 'undefined')) {
|
|
73
73
|
throw new Error(`No provider configured for ${types_1.FORK_NAMES[chainId]}`);
|
|
74
74
|
}
|
|
75
|
-
return new ethers_1.ethers.JsonRpcProvider(
|
|
75
|
+
return new ethers_1.ethers.JsonRpcProvider(resolvedRpcUrl);
|
|
76
76
|
};
|
|
77
77
|
exports.getProvider = getProvider;
|
|
@@ -131,7 +131,7 @@ const clusterLockHash = (clusterLock) => {
|
|
|
131
131
|
exports.clusterLockHash = clusterLockHash;
|
|
132
132
|
// Lock verification
|
|
133
133
|
// cluster-definition signatures verification
|
|
134
|
-
const validatePOSTConfigHashSigner = (address, signature, configHash, chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
134
|
+
const validatePOSTConfigHashSigner = (address, signature, configHash, chainId, safeRpcUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
135
135
|
try {
|
|
136
136
|
const data = (0, constants_js_1.signCreatorConfigHashPayload)({ creator_config_hash: configHash }, chainId);
|
|
137
137
|
return yield (0, signature_validator_js_1.validateAddressSignature)({
|
|
@@ -139,13 +139,14 @@ const validatePOSTConfigHashSigner = (address, signature, configHash, chainId) =
|
|
|
139
139
|
token: signature,
|
|
140
140
|
data,
|
|
141
141
|
chainId,
|
|
142
|
+
safeRpcUrl,
|
|
142
143
|
});
|
|
143
144
|
}
|
|
144
145
|
catch (err) {
|
|
145
146
|
throw err;
|
|
146
147
|
}
|
|
147
148
|
});
|
|
148
|
-
const validatePUTConfigHashSigner = (address, signature, configHash, chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
149
|
+
const validatePUTConfigHashSigner = (address, signature, configHash, chainId, safeRpcUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
149
150
|
try {
|
|
150
151
|
const data = (0, constants_js_1.signOperatorConfigHashPayload)({ operator_config_hash: configHash }, chainId);
|
|
151
152
|
return yield (0, signature_validator_js_1.validateAddressSignature)({
|
|
@@ -153,13 +154,14 @@ const validatePUTConfigHashSigner = (address, signature, configHash, chainId) =>
|
|
|
153
154
|
token: signature,
|
|
154
155
|
data,
|
|
155
156
|
chainId,
|
|
157
|
+
safeRpcUrl,
|
|
156
158
|
});
|
|
157
159
|
}
|
|
158
160
|
catch (err) {
|
|
159
161
|
throw err;
|
|
160
162
|
}
|
|
161
163
|
});
|
|
162
|
-
const validateEnrSigner = (address, signature, payload, chainId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
164
|
+
const validateEnrSigner = (address, signature, payload, chainId, safeRpcUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
163
165
|
try {
|
|
164
166
|
const data = (0, constants_js_1.signEnrPayload)({ enr: payload }, chainId);
|
|
165
167
|
return yield (0, signature_validator_js_1.validateAddressSignature)({
|
|
@@ -167,18 +169,19 @@ const validateEnrSigner = (address, signature, payload, chainId) => __awaiter(vo
|
|
|
167
169
|
token: signature,
|
|
168
170
|
data,
|
|
169
171
|
chainId,
|
|
172
|
+
safeRpcUrl,
|
|
170
173
|
});
|
|
171
174
|
}
|
|
172
175
|
catch (err) {
|
|
173
176
|
throw err;
|
|
174
177
|
}
|
|
175
178
|
});
|
|
176
|
-
const verifyDefinitionSignatures = (clusterDefinition, definitionType) => __awaiter(void 0, void 0, void 0, function* () {
|
|
179
|
+
const verifyDefinitionSignatures = (clusterDefinition, definitionType, safeRpcUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
177
180
|
if (definitionType === constants_js_1.DefinitionFlow.Charon) {
|
|
178
181
|
return true;
|
|
179
182
|
}
|
|
180
183
|
else {
|
|
181
|
-
const isPOSTConfigHashSignerValid = yield validatePOSTConfigHashSigner(clusterDefinition.creator.address, clusterDefinition.creator.config_signature, clusterDefinition.config_hash, types_js_1.FORK_MAPPING[clusterDefinition.fork_version]);
|
|
184
|
+
const isPOSTConfigHashSignerValid = yield validatePOSTConfigHashSigner(clusterDefinition.creator.address, clusterDefinition.creator.config_signature, clusterDefinition.config_hash, types_js_1.FORK_MAPPING[clusterDefinition.fork_version], safeRpcUrl);
|
|
182
185
|
if (!isPOSTConfigHashSignerValid) {
|
|
183
186
|
return false;
|
|
184
187
|
}
|
|
@@ -186,8 +189,8 @@ const verifyDefinitionSignatures = (clusterDefinition, definitionType) => __awai
|
|
|
186
189
|
return true;
|
|
187
190
|
}
|
|
188
191
|
for (const operator of clusterDefinition.operators) {
|
|
189
|
-
const isPUTConfigHashSignerValid = yield validatePUTConfigHashSigner(operator.address, operator.config_signature, clusterDefinition.config_hash, types_js_1.FORK_MAPPING[clusterDefinition.fork_version]);
|
|
190
|
-
const isENRSignerValid = yield validateEnrSigner(operator.address, operator.enr_signature, operator.enr, types_js_1.FORK_MAPPING[clusterDefinition.fork_version]);
|
|
192
|
+
const isPUTConfigHashSignerValid = yield validatePUTConfigHashSigner(operator.address, operator.config_signature, clusterDefinition.config_hash, types_js_1.FORK_MAPPING[clusterDefinition.fork_version], safeRpcUrl);
|
|
193
|
+
const isENRSignerValid = yield validateEnrSigner(operator.address, operator.enr_signature, operator.enr, types_js_1.FORK_MAPPING[clusterDefinition.fork_version], safeRpcUrl);
|
|
191
194
|
if (!isPUTConfigHashSignerValid || !isENRSignerValid) {
|
|
192
195
|
return false;
|
|
193
196
|
}
|
|
@@ -322,13 +325,13 @@ const verifyLockData = (clusterLock) => __awaiter(void 0, void 0, void 0, functi
|
|
|
322
325
|
}
|
|
323
326
|
return false;
|
|
324
327
|
});
|
|
325
|
-
const isValidClusterLock = (clusterLock) => __awaiter(void 0, void 0, void 0, function* () {
|
|
328
|
+
const isValidClusterLock = (clusterLock, safeRpcUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
326
329
|
try {
|
|
327
330
|
const definitionType = (0, utils_js_1.definitionFlow)(clusterLock.cluster_definition);
|
|
328
331
|
if (definitionType == null) {
|
|
329
332
|
return false;
|
|
330
333
|
}
|
|
331
|
-
const isValidDefinitionData = yield verifyDefinitionSignatures(clusterLock.cluster_definition, definitionType);
|
|
334
|
+
const isValidDefinitionData = yield verifyDefinitionSignatures(clusterLock.cluster_definition, definitionType, safeRpcUrl);
|
|
332
335
|
if (!isValidDefinitionData) {
|
|
333
336
|
return false;
|
|
334
337
|
}
|
|
@@ -20,9 +20,9 @@ const protocol_kit_1 = __importDefault(require("@safe-global/protocol-kit"));
|
|
|
20
20
|
const constants_1 = require("../constants");
|
|
21
21
|
const utils_1 = require("@safe-global/protocol-kit/dist/src/utils");
|
|
22
22
|
const utils_2 = require("../utils");
|
|
23
|
-
const validateAddressSignature = ({ address, token, data, chainId, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
+
const validateAddressSignature = ({ address, token, data, chainId, safeRpcUrl, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
24
|
try {
|
|
25
|
-
const provider = (0, utils_2.getProvider)(chainId);
|
|
25
|
+
const provider = (0, utils_2.getProvider)(chainId, safeRpcUrl);
|
|
26
26
|
if (provider) {
|
|
27
27
|
const contractAddress = yield (0, utils_2.isContractAvailable)(address, provider);
|
|
28
28
|
if (contractAddress) {
|
|
@@ -31,6 +31,7 @@ const validateAddressSignature = ({ address, token, data, chainId, }) => __await
|
|
|
31
31
|
data: data,
|
|
32
32
|
address,
|
|
33
33
|
chainId,
|
|
34
|
+
safeRpcUrl,
|
|
34
35
|
});
|
|
35
36
|
}
|
|
36
37
|
}
|
|
@@ -54,11 +55,11 @@ const validateEOASignature = ({ token, data, address, }) => {
|
|
|
54
55
|
}
|
|
55
56
|
};
|
|
56
57
|
exports.validateEOASignature = validateEOASignature;
|
|
57
|
-
const validateSmartContractSignature = ({ token, data, address, chainId, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
58
|
+
const validateSmartContractSignature = ({ token, data, address, chainId, safeRpcUrl, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
58
59
|
try {
|
|
59
|
-
const
|
|
60
|
+
const safeProvider = safeRpcUrl !== null && safeRpcUrl !== void 0 ? safeRpcUrl : constants_1.PROVIDER_MAP[chainId];
|
|
60
61
|
const protocolKit = yield protocol_kit_1.default.init({
|
|
61
|
-
provider,
|
|
62
|
+
provider: safeProvider,
|
|
62
63
|
safeAddress: address,
|
|
63
64
|
});
|
|
64
65
|
const messageHash = (0, utils_1.hashTypedData)(data);
|
|
@@ -104,13 +104,13 @@ global.fetch = globals_1.jest.fn();
|
|
|
104
104
|
merkleProof: mockIncentivesData.merkle_proof,
|
|
105
105
|
});
|
|
106
106
|
}));
|
|
107
|
-
(0, globals_1.test)('claimIncentives should return
|
|
107
|
+
(0, globals_1.test)('claimIncentives should return txHash as null when incentives are already claimed', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
108
108
|
globals_1.jest
|
|
109
109
|
.spyOn(clientInstance.incentives, 'getIncentivesByAddress')
|
|
110
110
|
.mockResolvedValue(mockIncentivesData);
|
|
111
111
|
globals_1.jest.spyOn(clientInstance.incentives, 'isClaimed').mockResolvedValue(true);
|
|
112
112
|
const result = yield clientInstance.incentives.claimIncentives(mockIncentivesData.operator_address);
|
|
113
|
-
(0, globals_1.expect)(result).toEqual({
|
|
113
|
+
(0, globals_1.expect)(result).toEqual({ txHash: null });
|
|
114
114
|
(0, globals_1.expect)(incentivesHelpers.claimIncentivesFromMerkleDistributor).not.toHaveBeenCalled();
|
|
115
115
|
}));
|
|
116
116
|
(0, globals_1.test)('claimIncentives should throw an error if no incentives found for address', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -145,7 +145,7 @@ global.fetch = globals_1.jest.fn();
|
|
|
145
145
|
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
|
|
146
146
|
const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contract_address, mockIncentivesData.index);
|
|
147
147
|
(0, globals_1.expect)(result).toBe(true);
|
|
148
|
-
(0, globals_1.expect)(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(
|
|
148
|
+
(0, globals_1.expect)(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(mockIncentivesData.contract_address, mockIncentivesData.index, {});
|
|
149
149
|
}));
|
|
150
150
|
(0, globals_1.test)('isClaimed should return false when incentive is not claimed', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
151
151
|
globals_1.jest
|
|
@@ -172,7 +172,7 @@ global.fetch = globals_1.jest.fn();
|
|
|
172
172
|
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
|
|
173
173
|
const result = yield clientWithoutSigner.incentives.isClaimed(mockIncentivesData.contract_address, mockIncentivesData.index);
|
|
174
174
|
(0, globals_1.expect)(result).toBe(true);
|
|
175
|
-
(0, globals_1.expect)(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(
|
|
175
|
+
(0, globals_1.expect)(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(mockIncentivesData.contract_address, mockIncentivesData.index, provider);
|
|
176
176
|
}));
|
|
177
177
|
(0, globals_1.test)('getIncentivesByAddress should make the correct API request', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
178
178
|
const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
|
|
@@ -165,6 +165,9 @@ describe('Cluster Client without a signer', () => {
|
|
|
165
165
|
beforeAll(() => {
|
|
166
166
|
jest.restoreAllMocks();
|
|
167
167
|
});
|
|
168
|
+
beforeEach(() => {
|
|
169
|
+
jest.resetModules();
|
|
170
|
+
});
|
|
168
171
|
test('createClusterDefinition should throw an error without signer', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
169
172
|
try {
|
|
170
173
|
yield clientInstance.createClusterDefinition(fixtures_js_1.clusterConfigV1X8);
|
|
@@ -219,6 +222,14 @@ describe('Cluster Client without a signer', () => {
|
|
|
219
222
|
const isValidLock = yield (0, index_1.validateClusterLock)(clusterLock);
|
|
220
223
|
expect(isValidLock).toEqual(true);
|
|
221
224
|
}));
|
|
225
|
+
test('should return true on verified cluster lock with Safe wallet and safe rpc url', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
226
|
+
process.env.RPC_HOLESKY = undefined;
|
|
227
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
228
|
+
const { validateClusterLock: validateLockWithRpcUrl, } = require('../src/index');
|
|
229
|
+
const safeRpcUrl = 'https://ethereum-holesky-rpc.publicnode.com';
|
|
230
|
+
const isValidLock = yield validateLockWithRpcUrl(fixtures_js_1.clusterLockWithSafe, safeRpcUrl);
|
|
231
|
+
expect(isValidLock).toEqual(true);
|
|
232
|
+
}));
|
|
222
233
|
test('validateCluster should return false for cluster with null deposit_amounts and incorrect partial_deposits', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
223
234
|
const partialDeposit = fixtures_js_1.nullDepositAmountsClusterLockV1X8.distributed_validators[0]
|
|
224
235
|
.partial_deposit_data[0];
|
package/dist/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obolnetwork/obol-sdk",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.6",
|
|
4
4
|
"description": "A package for creating Distributed Validators using the Obol API.",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/obolnetwork/obol-sdk/issues"
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"lint": "eslint \"{src,test}/**/*.{js,ts}\" --fix",
|
|
24
24
|
"lint-ci": "eslint \"{src,test}/**/*.{js,ts}\"",
|
|
25
25
|
"prettier-ci": "prettier --check \"{src,test}/**/*.{js,ts}\"",
|
|
26
|
-
"prettier": "prettier --write \"{src,test}/**/*.{js,ts}\""
|
|
26
|
+
"prettier": "prettier --write \"{src,test}/**/*.{js,ts}\"",
|
|
27
|
+
"docs": "typedoc"
|
|
27
28
|
},
|
|
28
29
|
"main": "./dist/cjs/src/index.js",
|
|
29
30
|
"module": "./dist/esm/src/index.js",
|
|
@@ -55,7 +56,7 @@
|
|
|
55
56
|
"eslint-plugin-import": "^2.29.1",
|
|
56
57
|
"eslint-plugin-n": "^16.6.2",
|
|
57
58
|
"eslint-plugin-promise": "^6.1.1",
|
|
58
|
-
"ethers": "6.
|
|
59
|
+
"ethers": "^6.13.5",
|
|
59
60
|
"nock": "^13.5.3",
|
|
60
61
|
"pdf-parse": "^1.1.1",
|
|
61
62
|
"semver": "^7.6.0",
|
|
@@ -79,8 +80,8 @@
|
|
|
79
80
|
"release-it": "^17.2.1",
|
|
80
81
|
"ts-jest": "^28.0.8",
|
|
81
82
|
"tsup": "^6.7.0",
|
|
82
|
-
"typedoc": "^0.
|
|
83
|
-
"typedoc-plugin-markdown": "^4.
|
|
83
|
+
"typedoc": "^0.28.0",
|
|
84
|
+
"typedoc-plugin-markdown": "^4.5.2",
|
|
84
85
|
"typescript": "~5.3.3"
|
|
85
86
|
},
|
|
86
87
|
"engines": {
|
|
@@ -7,9 +7,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { Contract
|
|
10
|
+
import { Contract } from 'ethers';
|
|
11
11
|
import { MerkleDistributorABI } from './abi/MerkleDistributorWithDeadline';
|
|
12
|
-
import { getProvider } from './utils';
|
|
13
12
|
export const claimIncentivesFromMerkleDistributor = (incentivesData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
13
|
try {
|
|
15
14
|
const contract = new Contract(incentivesData.contractAddress, MerkleDistributorABI.abi, incentivesData.signer);
|
|
@@ -22,10 +21,9 @@ export const claimIncentivesFromMerkleDistributor = (incentivesData) => __awaite
|
|
|
22
21
|
throw new Error(`Failed to claim incentives: ${error.message}`);
|
|
23
22
|
}
|
|
24
23
|
});
|
|
25
|
-
export const isClaimedFromMerkleDistributor = (
|
|
24
|
+
export const isClaimedFromMerkleDistributor = (contractAddress, index, provider) => __awaiter(void 0, void 0, void 0, function* () {
|
|
26
25
|
try {
|
|
27
|
-
const
|
|
28
|
-
const contract = new Contract(contractAddress, MerkleDistributorABI.abi, clientProvider);
|
|
26
|
+
const contract = new Contract(contractAddress, MerkleDistributorABI.abi, provider);
|
|
29
27
|
const claimed = yield contract.isClaimed(BigInt(index));
|
|
30
28
|
return claimed;
|
|
31
29
|
}
|
|
@@ -11,6 +11,14 @@ import { isContractAvailable } from './utils';
|
|
|
11
11
|
import { FORK_NAMES, } from './types';
|
|
12
12
|
import { claimIncentivesFromMerkleDistributor, isClaimedFromMerkleDistributor, } from './incentiveHelpers';
|
|
13
13
|
import { DEFAULT_BASE_VERSION } from './constants';
|
|
14
|
+
/**
|
|
15
|
+
* Incentives can be used for fetching and claiming Obol incentives.
|
|
16
|
+
* @class
|
|
17
|
+
* @internal Access it through Client.incentives.
|
|
18
|
+
* @example
|
|
19
|
+
* const obolClient = new Client(config);
|
|
20
|
+
* await obolClient.incentives.claimIncentives(address);
|
|
21
|
+
*/
|
|
14
22
|
export class Incentives {
|
|
15
23
|
constructor(signer, chainId, request, provider) {
|
|
16
24
|
this.signer = signer;
|
|
@@ -19,16 +27,23 @@ export class Incentives {
|
|
|
19
27
|
this.provider = provider;
|
|
20
28
|
}
|
|
21
29
|
/**
|
|
22
|
-
* Claims
|
|
23
|
-
*
|
|
30
|
+
* Claims Obol incentives from a Merkle Distributor contract using an address.
|
|
31
|
+
*
|
|
32
|
+
* This method automatically fetches incentive data and verifies whether the incentives have already been claimed.
|
|
33
|
+
* If `txHash` is `null`, it indicates that the incentives were already claimed.
|
|
34
|
+
*
|
|
35
|
+
* Note: This method is not yet enabled and will throw an error if called.
|
|
24
36
|
*
|
|
25
37
|
* @remarks
|
|
26
38
|
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
27
39
|
* and not pushed to version control.
|
|
28
40
|
*
|
|
29
41
|
* @param {string} address - The address to claim incentives for
|
|
30
|
-
* @returns {Promise<
|
|
42
|
+
* @returns {Promise<ClaimIncentivesResponse>} The transaction hash or already claimed status
|
|
31
43
|
* @throws Will throw an error if the incentives data is not found or the claim fails
|
|
44
|
+
*
|
|
45
|
+
* An example of how to use claimIncentives:
|
|
46
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L281)
|
|
32
47
|
*/
|
|
33
48
|
claimIncentives(address) {
|
|
34
49
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -46,7 +61,7 @@ export class Incentives {
|
|
|
46
61
|
}
|
|
47
62
|
const claimed = yield this.isClaimed(incentivesData.contract_address, incentivesData.index);
|
|
48
63
|
if (claimed) {
|
|
49
|
-
return {
|
|
64
|
+
return { txHash: null };
|
|
50
65
|
}
|
|
51
66
|
const { txHash } = yield claimIncentivesFromMerkleDistributor({
|
|
52
67
|
signer: this.signer,
|
|
@@ -71,16 +86,22 @@ export class Incentives {
|
|
|
71
86
|
* @param {ETH_ADDRESS} index - operator index in merkle tree
|
|
72
87
|
* @returns {Promise<boolean>} true if incentives are already claime
|
|
73
88
|
*
|
|
89
|
+
*
|
|
90
|
+
* An example of how to use isClaimed:
|
|
91
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L266)
|
|
74
92
|
*/
|
|
75
93
|
isClaimed(contractAddress, index) {
|
|
76
94
|
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
-
return yield isClaimedFromMerkleDistributor(
|
|
95
|
+
return yield isClaimedFromMerkleDistributor(contractAddress, index, this.provider);
|
|
78
96
|
});
|
|
79
97
|
}
|
|
80
98
|
/**
|
|
81
99
|
* @param address - Operator address
|
|
82
100
|
* @returns {Promise<IncentivesType>} The matched incentives from DB
|
|
83
101
|
* @throws On not found if address not found.
|
|
102
|
+
*
|
|
103
|
+
* An example of how to use getIncentivesByAddress:
|
|
104
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L250)
|
|
84
105
|
*/
|
|
85
106
|
getIncentivesByAddress(address) {
|
|
86
107
|
return __awaiter(this, void 0, void 0, function* () {
|
package/dist/esm/src/index.js
CHANGED
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { ZeroAddress
|
|
10
|
+
import { ZeroAddress } from 'ethers';
|
|
11
11
|
import { v4 as uuidv4 } from 'uuid';
|
|
12
12
|
import { Base } from './base.js';
|
|
13
13
|
import { CONFLICT_ERROR_MSG, CreatorConfigHashSigningTypes, Domain, DKG_ALGORITHM, CONFIG_VERSION, OperatorConfigHashSigningTypes, EnrSigningTypes, TERMS_AND_CONDITIONS_VERSION, TermsAndConditionsSigningTypes, DEFAULT_BASE_VERSION, TERMS_AND_CONDITIONS_HASH, AVAILABLE_SPLITTER_CHAINS, CHAIN_CONFIGURATION, DEFAULT_RETROACTIVE_FUNDING_REWARDS_ONLY_SPLIT, DEFAULT_RETROACTIVE_FUNDING_TOTAL_SPLIT, OBOL_SDK_EMAIL, } from './constants.js';
|
|
@@ -22,6 +22,7 @@ export * from './types.js';
|
|
|
22
22
|
export * from './services.js';
|
|
23
23
|
export * from './verification/signature-validator.js';
|
|
24
24
|
export * from './verification/common.js';
|
|
25
|
+
export { Incentives } from './incentives.js';
|
|
25
26
|
/**
|
|
26
27
|
* Obol sdk Client can be used for creating, managing and activating distributed validators.
|
|
27
28
|
*/
|
package/dist/esm/src/services.js
CHANGED
|
@@ -11,15 +11,16 @@ import { isValidClusterLock } from './verification/common.js';
|
|
|
11
11
|
/**
|
|
12
12
|
* Verifies Cluster Lock's validity.
|
|
13
13
|
* @param lock - cluster lock
|
|
14
|
+
* @param safeRpcUrl - optional safeRpcUrl for safe wallet verification
|
|
14
15
|
* @returns {Promise<{ result: boolean }> } boolean result to indicate if lock is valid
|
|
15
16
|
* @throws on missing keys or values.
|
|
16
17
|
*
|
|
17
18
|
* An example of how to use validateClusterLock:
|
|
18
19
|
* [validateClusterLock](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L127)
|
|
19
20
|
*/
|
|
20
|
-
export const validateClusterLock = (lock) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
+
export const validateClusterLock = (lock, safeRpcUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
22
|
try {
|
|
22
|
-
const isLockValid = yield isValidClusterLock(lock);
|
|
23
|
+
const isLockValid = yield isValidClusterLock(lock, safeRpcUrl);
|
|
23
24
|
return isLockValid;
|
|
24
25
|
}
|
|
25
26
|
catch (err) {
|
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { Contract, Interface, parseEther, ZeroAddress
|
|
10
|
+
import { Contract, Interface, parseEther, ZeroAddress } from 'ethers';
|
|
11
11
|
import { OWRContract, OWRFactoryContract } from './abi/OWR';
|
|
12
12
|
import { splitMainEthereumAbi } from './abi/SplitMain';
|
|
13
13
|
import { MultiCallContract } from './abi/Multicall';
|
package/dist/esm/src/types.js
CHANGED
|
@@ -16,20 +16,11 @@ export var FORK_MAPPING;
|
|
|
16
16
|
/** Hoodi Chain. */
|
|
17
17
|
FORK_MAPPING[FORK_MAPPING["0x10000910"] = 560048] = "0x10000910";
|
|
18
18
|
})(FORK_MAPPING || (FORK_MAPPING = {}));
|
|
19
|
-
/**
|
|
20
|
-
* Permitted Chain Names
|
|
21
|
-
*/
|
|
22
19
|
export const FORK_NAMES = {
|
|
23
|
-
/** Mainnet. */
|
|
24
20
|
[FORK_MAPPING['0x00000000']]: 'mainnet',
|
|
25
|
-
/** Goerli/Prater. */
|
|
26
21
|
[FORK_MAPPING['0x00001020']]: 'goerli',
|
|
27
|
-
/** Gnosis Chain. */
|
|
28
22
|
[FORK_MAPPING['0x00000064']]: 'gnosis',
|
|
29
|
-
/** Holesky. */
|
|
30
23
|
[FORK_MAPPING['0x01017000']]: 'holesky',
|
|
31
|
-
/** Sepolia. */
|
|
32
24
|
[FORK_MAPPING['0x90000069']]: 'sepolia',
|
|
33
|
-
/** Hoodi. */
|
|
34
25
|
[FORK_MAPPING['0x10000910']]: 'hoodi',
|
|
35
26
|
};
|
package/dist/esm/src/utils.js
CHANGED
|
@@ -59,10 +59,10 @@ export const isContractAvailable = (contractAddress, provider, bytecode) => __aw
|
|
|
59
59
|
}
|
|
60
60
|
return !!code && code !== '0x' && code !== '0x0';
|
|
61
61
|
});
|
|
62
|
-
export const getProvider = (chainId) => {
|
|
63
|
-
const
|
|
64
|
-
if (!
|
|
62
|
+
export const getProvider = (chainId, rpcUrl) => {
|
|
63
|
+
const resolvedRpcUrl = rpcUrl !== null && rpcUrl !== void 0 ? rpcUrl : PROVIDER_MAP[chainId];
|
|
64
|
+
if (chainId && (!resolvedRpcUrl || resolvedRpcUrl === 'undefined')) {
|
|
65
65
|
throw new Error(`No provider configured for ${FORK_NAMES[chainId]}`);
|
|
66
66
|
}
|
|
67
|
-
return new ethers.JsonRpcProvider(
|
|
67
|
+
return new ethers.JsonRpcProvider(resolvedRpcUrl);
|
|
68
68
|
};
|