@obolnetwork/obol-sdk 2.9.0 → 2.10.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/cjs/package.json +1 -1
- package/dist/cjs/src/ajv.js +0 -1
- package/dist/cjs/src/constants.js +9 -0
- package/dist/cjs/src/eoa/eoa.js +83 -0
- package/dist/cjs/src/eoa/eoaHelpers.js +37 -0
- package/dist/cjs/src/index.js +5 -1
- package/dist/cjs/src/schema.js +24 -2
- package/dist/cjs/src/splits/splitHelpers.js +6 -4
- package/dist/cjs/src/splits/splits.js +1 -0
- package/dist/cjs/test/client/ajv.spec.js +20 -1
- package/dist/cjs/test/eoa/eoa.spec.js +87 -0
- package/dist/cjs/test/splits/splits.spec.js +5 -0
- package/dist/esm/package.json +1 -1
- package/dist/esm/src/ajv.js +0 -1
- package/dist/esm/src/constants.js +9 -0
- package/dist/esm/src/eoa/eoa.js +79 -0
- package/dist/esm/src/eoa/eoaHelpers.js +33 -0
- package/dist/esm/src/index.js +3 -0
- package/dist/esm/src/schema.js +23 -1
- package/dist/esm/src/splits/splitHelpers.js +7 -5
- package/dist/esm/src/splits/splits.js +1 -0
- package/dist/esm/test/client/ajv.spec.js +20 -1
- package/dist/esm/test/eoa/eoa.spec.js +85 -0
- package/dist/esm/test/splits/splits.spec.js +5 -0
- package/dist/types/src/eoa/eoa.d.ts +42 -0
- package/dist/types/src/eoa/eoaHelpers.d.ts +16 -0
- package/dist/types/src/index.d.ts +7 -0
- package/dist/types/src/schema.d.ts +22 -0
- package/dist/types/src/splits/splitHelpers.d.ts +2 -1
- package/dist/types/src/types.d.ts +18 -2
- package/dist/types/test/eoa/eoa.spec.d.ts +1 -0
- package/package.json +1 -1
- package/src/ajv.ts +0 -1
- package/src/constants.ts +9 -0
- package/src/eoa/eoa.ts +94 -0
- package/src/eoa/eoaHelpers.ts +43 -0
- package/src/index.ts +9 -0
- package/src/schema.ts +24 -1
- package/src/splits/splitHelpers.ts +8 -4
- package/src/splits/splits.ts +1 -0
- package/src/types.ts +22 -2
package/dist/cjs/package.json
CHANGED
package/dist/cjs/src/ajv.js
CHANGED
|
@@ -68,7 +68,6 @@ const validateOVMTotalSplitRecipients = (_, data) => {
|
|
|
68
68
|
return validateTotalPercentage(splitPercentage);
|
|
69
69
|
};
|
|
70
70
|
const validateOVMRequestWithdrawalPayload = (_, data) => {
|
|
71
|
-
console.log(data, 'hanaaan dataaaa');
|
|
72
71
|
if (!data.pubKeys || !data.amounts) {
|
|
73
72
|
return false;
|
|
74
73
|
}
|
|
@@ -171,6 +171,9 @@ exports.CHAIN_CONFIGURATION = {
|
|
|
171
171
|
address: '0x5cbA88D55Cec83caD5A105Ad40C8c9aF20bE21d1',
|
|
172
172
|
bytecode: bytecodes_1.MAINNET_SPLIT_V2_FACTORY_BYTECODE,
|
|
173
173
|
},
|
|
174
|
+
EOA_WITHDRAWAL_CONTRACT: {
|
|
175
|
+
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
176
|
+
},
|
|
174
177
|
},
|
|
175
178
|
[types_1.FORK_MAPPING['0x01017000']]: {
|
|
176
179
|
SPLITMAIN_CONTRACT: {
|
|
@@ -189,6 +192,9 @@ exports.CHAIN_CONFIGURATION = {
|
|
|
189
192
|
address: '0x43F641fA70e09f0326ac66b4Ef0C416EaEcBC6f5',
|
|
190
193
|
bytecode: '',
|
|
191
194
|
},
|
|
195
|
+
EOA_WITHDRAWAL_CONTRACT: {
|
|
196
|
+
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
197
|
+
},
|
|
192
198
|
},
|
|
193
199
|
[types_1.FORK_MAPPING['0x10000910']]: {
|
|
194
200
|
SPLITMAIN_CONTRACT: {
|
|
@@ -220,6 +226,9 @@ exports.CHAIN_CONFIGURATION = {
|
|
|
220
226
|
address: '0x5cbA88D55Cec83caD5A105Ad40C8c9aF20bE21d1',
|
|
221
227
|
bytecode: bytecodes_1.HOODI_SPLIT_V2_FACTORY_BYTECODE,
|
|
222
228
|
},
|
|
229
|
+
EOA_WITHDRAWAL_CONTRACT: {
|
|
230
|
+
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
231
|
+
},
|
|
223
232
|
},
|
|
224
233
|
};
|
|
225
234
|
exports.DEFAULT_RETROACTIVE_FUNDING_REWARDS_ONLY_SPLIT = 1;
|
|
@@ -0,0 +1,83 @@
|
|
|
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.EOA = void 0;
|
|
13
|
+
const eoaHelpers_1 = require("./eoaHelpers");
|
|
14
|
+
const ajv_1 = require("../ajv");
|
|
15
|
+
const schema_1 = require("../schema");
|
|
16
|
+
const constants_1 = require("../constants");
|
|
17
|
+
/**
|
|
18
|
+
* EOA can be used for managing EOA (Externally Owned Account) operations like withdrawals.
|
|
19
|
+
* @class
|
|
20
|
+
* @internal Access it through Client.eoa.
|
|
21
|
+
* @example
|
|
22
|
+
* const obolClient = new Client(config);
|
|
23
|
+
* await obolClient.eoa.requestWithdrawal(EOAWithdrawalPayload);
|
|
24
|
+
*/
|
|
25
|
+
class EOA {
|
|
26
|
+
constructor(signer, chainId, provider) {
|
|
27
|
+
this.signer = signer;
|
|
28
|
+
this.chainId = chainId;
|
|
29
|
+
this.provider = provider;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Requests withdrawal from an EOA contract.
|
|
33
|
+
*
|
|
34
|
+
* This method allows requesting withdrawal of validator funds.
|
|
35
|
+
* The withdrawal request includes validator public key and corresponding withdrawal amount.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
39
|
+
* and not pushed to version control.
|
|
40
|
+
*
|
|
41
|
+
* @param {EOAWithdrawalPayload} payload - Data needed to request withdrawal
|
|
42
|
+
* @returns {Promise<{txHash: string}>} Transaction hash of the withdrawal request
|
|
43
|
+
* @throws Will throw an error if the signer is not provided or the request fails
|
|
44
|
+
*
|
|
45
|
+
* An example of how to use requestWithdrawal:
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const result = await client.eoa.requestWithdrawal({
|
|
48
|
+
* pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
49
|
+
* allocation: 32, // 32 ETH
|
|
50
|
+
* requiredFee: '1' // in wei
|
|
51
|
+
* });
|
|
52
|
+
* console.log('Withdrawal requested:', result.txHash);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
requestWithdrawal(payload) {
|
|
56
|
+
var _a;
|
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
if (!this.signer) {
|
|
59
|
+
throw new Error('Signer is required in requestWithdrawal');
|
|
60
|
+
}
|
|
61
|
+
if (!this.provider) {
|
|
62
|
+
throw new Error('Provider is required in requestWithdrawal');
|
|
63
|
+
}
|
|
64
|
+
const chainConfig = constants_1.CHAIN_CONFIGURATION[this.chainId];
|
|
65
|
+
if (!((_a = chainConfig === null || chainConfig === void 0 ? void 0 : chainConfig.EOA_WITHDRAWAL_CONTRACT) === null || _a === void 0 ? void 0 : _a.address)) {
|
|
66
|
+
throw new Error(`EOA withdrawal contract is not configured for chain ${this.chainId}`);
|
|
67
|
+
}
|
|
68
|
+
const validatedPayload = (0, ajv_1.validatePayload)(payload, schema_1.eoaWithdrawalPayloadSchema);
|
|
69
|
+
const withdrawalAddress = yield this.signer.getAddress();
|
|
70
|
+
return yield (0, eoaHelpers_1.submitEOAWithdrawalRequest)({
|
|
71
|
+
pubkey: validatedPayload.pubkey,
|
|
72
|
+
allocation: validatedPayload.allocation,
|
|
73
|
+
withdrawalAddress,
|
|
74
|
+
withdrawalContractAddress: chainConfig.EOA_WITHDRAWAL_CONTRACT.address,
|
|
75
|
+
requiredFee: validatedPayload.requiredFee,
|
|
76
|
+
chainId: this.chainId,
|
|
77
|
+
signer: this.signer,
|
|
78
|
+
provider: this.provider,
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.EOA = EOA;
|
|
@@ -0,0 +1,37 @@
|
|
|
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.submitEOAWithdrawalRequest = void 0;
|
|
13
|
+
const constants_1 = require("../constants");
|
|
14
|
+
/**
|
|
15
|
+
* Helper function to submit withdrawal request for EOA
|
|
16
|
+
*/
|
|
17
|
+
function submitEOAWithdrawalRequest({ pubkey, allocation, withdrawalAddress, withdrawalContractAddress, requiredFee, chainId, signer, provider, }) {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
if (!withdrawalAddress)
|
|
20
|
+
throw new Error('No withdrawal address provided');
|
|
21
|
+
if (!allocation)
|
|
22
|
+
throw new Error('No allocation provided');
|
|
23
|
+
const amountInGwei = BigInt(Math.floor(Number(allocation) * constants_1.ETHER_TO_GWEI));
|
|
24
|
+
const data = `0x${pubkey.slice(2)}${amountInGwei.toString(16).padStart(16, '0')}`;
|
|
25
|
+
const { hash } = yield signer.sendTransaction({
|
|
26
|
+
to: withdrawalContractAddress,
|
|
27
|
+
chainId,
|
|
28
|
+
value: BigInt(requiredFee),
|
|
29
|
+
data: data,
|
|
30
|
+
});
|
|
31
|
+
const txResult = yield provider.getTransactionReceipt(hash);
|
|
32
|
+
if (!txResult)
|
|
33
|
+
return { txHash: null };
|
|
34
|
+
return { txHash: txResult === null || txResult === void 0 ? void 0 : txResult.hash };
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
exports.submitEOAWithdrawalRequest = submitEOAWithdrawalRequest;
|
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 = exports.ObolSplits = exports.Exit = exports.Incentives = void 0;
|
|
26
|
+
exports.Client = exports.EOA = exports.ObolSplits = exports.Exit = exports.Incentives = void 0;
|
|
27
27
|
const uuid_1 = require("uuid");
|
|
28
28
|
const base_js_1 = require("./base.js");
|
|
29
29
|
const constants_js_1 = require("./constants.js");
|
|
@@ -36,6 +36,7 @@ const utils_js_1 = require("./utils.js");
|
|
|
36
36
|
const incentives_js_1 = require("./incentives/incentives.js");
|
|
37
37
|
const exit_js_1 = require("./exits/exit.js");
|
|
38
38
|
const splits_js_1 = require("./splits/splits.js");
|
|
39
|
+
const eoa_js_1 = require("./eoa/eoa.js");
|
|
39
40
|
__exportStar(require("./types.js"), exports);
|
|
40
41
|
__exportStar(require("./services.js"), exports);
|
|
41
42
|
__exportStar(require("./verification/signature-validator.js"), exports);
|
|
@@ -47,6 +48,8 @@ var exit_js_2 = require("./exits/exit.js");
|
|
|
47
48
|
Object.defineProperty(exports, "Exit", { enumerable: true, get: function () { return exit_js_2.Exit; } });
|
|
48
49
|
var splits_js_2 = require("./splits/splits.js");
|
|
49
50
|
Object.defineProperty(exports, "ObolSplits", { enumerable: true, get: function () { return splits_js_2.ObolSplits; } });
|
|
51
|
+
var eoa_js_2 = require("./eoa/eoa.js");
|
|
52
|
+
Object.defineProperty(exports, "EOA", { enumerable: true, get: function () { return eoa_js_2.EOA; } });
|
|
50
53
|
/**
|
|
51
54
|
* Obol sdk Client can be used for creating, managing and activating distributed validators.
|
|
52
55
|
*/
|
|
@@ -70,6 +73,7 @@ class Client extends base_js_1.Base {
|
|
|
70
73
|
this.incentives = new incentives_js_1.Incentives(this.signer, this.chainId, this.request.bind(this), this.provider);
|
|
71
74
|
this.exit = new exit_js_1.Exit(this.chainId, this.provider);
|
|
72
75
|
this.splits = new splits_js_1.ObolSplits(this.signer, this.chainId, this.provider);
|
|
76
|
+
this.eoa = new eoa_js_1.EOA(this.signer, this.chainId, this.provider);
|
|
73
77
|
}
|
|
74
78
|
/**
|
|
75
79
|
* Accepts Obol terms and conditions to be able to create or update data.
|
package/dist/cjs/src/schema.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ovmRequestWithdrawalPayloadSchema = exports.ovmTotalSplitPayloadSchema = exports.ovmRewardsSplitPayloadSchema = exports.ovmBaseSplitPayload = exports.rewardsSplitterPayloadSchema = exports.totalSplitterPayloadSchema = exports.definitionSchema = exports.operatorPayloadSchema = void 0;
|
|
3
|
+
exports.eoaWithdrawalPayloadSchema = exports.ovmRequestWithdrawalPayloadSchema = exports.ovmTotalSplitPayloadSchema = exports.ovmRewardsSplitPayloadSchema = exports.ovmBaseSplitPayload = exports.rewardsSplitterPayloadSchema = exports.totalSplitterPayloadSchema = exports.definitionSchema = exports.operatorPayloadSchema = void 0;
|
|
4
4
|
const ethers_1 = require("ethers");
|
|
5
5
|
const constants_1 = require("./constants");
|
|
6
6
|
const ajv_1 = require("./ajv");
|
|
@@ -212,6 +212,10 @@ exports.ovmTotalSplitPayloadSchema = {
|
|
|
212
212
|
exports.ovmRequestWithdrawalPayloadSchema = {
|
|
213
213
|
type: 'object',
|
|
214
214
|
properties: {
|
|
215
|
+
withdrawalFees: {
|
|
216
|
+
type: 'string',
|
|
217
|
+
pattern: '^[0-9]+$',
|
|
218
|
+
},
|
|
215
219
|
ovmAddress: {
|
|
216
220
|
type: 'string',
|
|
217
221
|
pattern: '^0x[a-fA-F0-9]{40}$',
|
|
@@ -234,5 +238,23 @@ exports.ovmRequestWithdrawalPayloadSchema = {
|
|
|
234
238
|
},
|
|
235
239
|
},
|
|
236
240
|
validateOVMRequestWithdrawalPayload: true,
|
|
237
|
-
required: ['ovmAddress', 'pubKeys', 'amounts'],
|
|
241
|
+
required: ['ovmAddress', 'pubKeys', 'amounts', 'withdrawalFees'],
|
|
242
|
+
};
|
|
243
|
+
exports.eoaWithdrawalPayloadSchema = {
|
|
244
|
+
type: 'object',
|
|
245
|
+
properties: {
|
|
246
|
+
pubkey: {
|
|
247
|
+
type: 'string',
|
|
248
|
+
pattern: '^0x[a-fA-F0-9]{96}$', // 48 bytes = 96 hex chars + 0x prefix
|
|
249
|
+
},
|
|
250
|
+
allocation: {
|
|
251
|
+
type: 'number',
|
|
252
|
+
minimum: 0,
|
|
253
|
+
},
|
|
254
|
+
requiredFee: {
|
|
255
|
+
type: 'string',
|
|
256
|
+
pattern: '^[0-9]+$',
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
required: ['pubkey', 'allocation', 'requiredFee'],
|
|
238
260
|
};
|
|
@@ -410,7 +410,7 @@ const deployOVMContract = ({ OVMOwnerAddress, principalRecipient, rewardRecipien
|
|
|
410
410
|
throw new Error(`OVM Factory not configured for chain ${chainId}`);
|
|
411
411
|
}
|
|
412
412
|
const ovmFactoryContract = new ethers_1.Contract(chainConfig.OVM_FACTORY_CONTRACT.address, OVMFactory_1.OVMFactoryContract.abi, signer);
|
|
413
|
-
const tx = yield ovmFactoryContract.createObolValidatorManager(OVMOwnerAddress, principalRecipient, rewardRecipient, principalThreshold);
|
|
413
|
+
const tx = yield ovmFactoryContract.createObolValidatorManager(OVMOwnerAddress, principalRecipient, rewardRecipient, principalThreshold * constants_1.ETHER_TO_GWEI);
|
|
414
414
|
const receipt = yield tx.wait();
|
|
415
415
|
// Extract OVM address from logs
|
|
416
416
|
const ovmAddressLog = (_3 = receipt === null || receipt === void 0 ? void 0 : receipt.logs[1]) === null || _3 === void 0 ? void 0 : _3.topics[1];
|
|
@@ -455,7 +455,7 @@ const deployOVMAndSplitV2 = ({ ovmArgs, rewardRecipients, isRewardsSplitterDeplo
|
|
|
455
455
|
});
|
|
456
456
|
}
|
|
457
457
|
// Create OVM call data
|
|
458
|
-
const ovmTxData = encodeCreateOVMTxData(ovmArgs.OVMOwnerAddress, ovmArgs.principalRecipient, ovmArgs.rewardRecipient, ovmArgs.principalThreshold);
|
|
458
|
+
const ovmTxData = encodeCreateOVMTxData(ovmArgs.OVMOwnerAddress, ovmArgs.principalRecipient, ovmArgs.rewardRecipient, ovmArgs.principalThreshold * constants_1.ETHER_TO_GWEI);
|
|
459
459
|
executeCalls.push({
|
|
460
460
|
target: chainConfig.OVM_FACTORY_CONTRACT.address,
|
|
461
461
|
callData: ovmTxData,
|
|
@@ -507,13 +507,15 @@ const getChainConfig = (chainId) => {
|
|
|
507
507
|
* @param signer - The signer to use for the transaction
|
|
508
508
|
* @returns Promise that resolves to the transaction hash
|
|
509
509
|
*/
|
|
510
|
-
const requestWithdrawalFromOVM = ({ ovmAddress, pubKeys, amounts, signer, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
510
|
+
const requestWithdrawalFromOVM = ({ ovmAddress, pubKeys, amounts, withdrawalFees, signer, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
511
511
|
var _15;
|
|
512
512
|
try {
|
|
513
513
|
// Convert string amounts to bigint
|
|
514
514
|
const bigintAmounts = amounts.map(amount => BigInt(amount));
|
|
515
515
|
const ovmContract = new ethers_1.Contract(ovmAddress, OVMFactory_1.OVMContract.abi, signer);
|
|
516
|
-
const tx = yield ovmContract.requestWithdrawal(pubKeys, bigintAmounts
|
|
516
|
+
const tx = yield ovmContract.requestWithdrawal(pubKeys, bigintAmounts, {
|
|
517
|
+
value: BigInt(withdrawalFees),
|
|
518
|
+
});
|
|
517
519
|
const receipt = yield tx.wait();
|
|
518
520
|
return { txHash: receipt.hash };
|
|
519
521
|
}
|
|
@@ -274,6 +274,7 @@ describe('ovmRequestWithdrawalPayloadSchema', () => {
|
|
|
274
274
|
'0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
275
275
|
],
|
|
276
276
|
amounts: ['32000000000'],
|
|
277
|
+
withdrawalFees: '1',
|
|
277
278
|
};
|
|
278
279
|
it('should throw error when OVM address is missing', () => {
|
|
279
280
|
const payload = {
|
|
@@ -288,14 +289,32 @@ describe('ovmRequestWithdrawalPayloadSchema', () => {
|
|
|
288
289
|
pubKeys: validPayload.pubKeys,
|
|
289
290
|
amounts: validPayload.amounts,
|
|
290
291
|
};
|
|
291
|
-
expect(() => (0, ajv_1.validatePayload)(payload, schema_1.ovmRequestWithdrawalPayloadSchema)).toThrow('Validation failed: /ovmAddress must match pattern');
|
|
292
|
+
expect(() => (0, ajv_1.validatePayload)(payload, schema_1.ovmRequestWithdrawalPayloadSchema)).toThrow('Validation failed: must have required property \'withdrawalFees\', /ovmAddress must match pattern "^0x[a-fA-F0-9]{40}$"');
|
|
292
293
|
});
|
|
293
294
|
it('should throw error when number of public keys does not match number of amounts', () => {
|
|
294
295
|
const payload = {
|
|
295
296
|
ovmAddress: validPayload.ovmAddress,
|
|
296
297
|
pubKeys: validPayload.pubKeys,
|
|
297
298
|
amounts: ['32000000000', '16000000000'], // 2 amounts, 1 pubKey
|
|
299
|
+
withdrawalFees: validPayload.withdrawalFees,
|
|
298
300
|
};
|
|
299
301
|
expect(() => (0, ajv_1.validatePayload)(payload, schema_1.ovmRequestWithdrawalPayloadSchema)).toThrow('Validation failed: must pass "validateOVMRequestWithdrawalPayload" keyword validation');
|
|
300
302
|
});
|
|
303
|
+
it('should throw error when withdrawalFees is missing', () => {
|
|
304
|
+
const payload = {
|
|
305
|
+
ovmAddress: validPayload.ovmAddress,
|
|
306
|
+
pubKeys: validPayload.pubKeys,
|
|
307
|
+
amounts: validPayload.amounts,
|
|
308
|
+
};
|
|
309
|
+
expect(() => (0, ajv_1.validatePayload)(payload, schema_1.ovmRequestWithdrawalPayloadSchema)).toThrow("Validation failed: must have required property 'withdrawalFees'");
|
|
310
|
+
});
|
|
311
|
+
it('should throw error when withdrawalFees is invalid', () => {
|
|
312
|
+
const payload = {
|
|
313
|
+
ovmAddress: validPayload.ovmAddress,
|
|
314
|
+
pubKeys: validPayload.pubKeys,
|
|
315
|
+
amounts: validPayload.amounts,
|
|
316
|
+
withdrawalFees: 'invalid',
|
|
317
|
+
};
|
|
318
|
+
expect(() => (0, ajv_1.validatePayload)(payload, schema_1.ovmRequestWithdrawalPayloadSchema)).toThrow('Validation failed: /withdrawalFees must match pattern "^[0-9]+$"');
|
|
319
|
+
});
|
|
301
320
|
});
|
|
@@ -0,0 +1,87 @@
|
|
|
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
|
+
const eoa_1 = require("../../src/eoa/eoa");
|
|
13
|
+
const eoaHelpers_1 = require("../../src/eoa/eoaHelpers");
|
|
14
|
+
// Mock the helper function
|
|
15
|
+
jest.mock('../../src/eoa/eoaHelpers', () => ({
|
|
16
|
+
submitEOAWithdrawalRequest: jest.fn(),
|
|
17
|
+
}));
|
|
18
|
+
describe('EOA', () => {
|
|
19
|
+
let eoa;
|
|
20
|
+
let mockSigner;
|
|
21
|
+
let mockProvider;
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
// Clear all mocks before each test
|
|
24
|
+
jest.clearAllMocks();
|
|
25
|
+
mockSigner = {
|
|
26
|
+
getAddress: jest
|
|
27
|
+
.fn()
|
|
28
|
+
.mockResolvedValue('0x1234567890123456789012345678901234567890'),
|
|
29
|
+
};
|
|
30
|
+
mockProvider = {
|
|
31
|
+
getNetwork: jest.fn().mockResolvedValue({ chainId: 1 }),
|
|
32
|
+
};
|
|
33
|
+
eoa = new eoa_1.EOA(mockSigner, 1, mockProvider);
|
|
34
|
+
});
|
|
35
|
+
describe('requestWithdrawal', () => {
|
|
36
|
+
it('should successfully request withdrawal', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
const mockPayload = {
|
|
38
|
+
pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
39
|
+
allocation: 32,
|
|
40
|
+
requiredFee: '1',
|
|
41
|
+
};
|
|
42
|
+
const mockResult = {
|
|
43
|
+
txHash: '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
|
|
44
|
+
};
|
|
45
|
+
eoaHelpers_1.submitEOAWithdrawalRequest.mockResolvedValue(mockResult);
|
|
46
|
+
const result = yield eoa.requestWithdrawal(mockPayload);
|
|
47
|
+
expect(eoaHelpers_1.submitEOAWithdrawalRequest).toHaveBeenCalledWith({
|
|
48
|
+
pubkey: mockPayload.pubkey,
|
|
49
|
+
allocation: mockPayload.allocation,
|
|
50
|
+
withdrawalAddress: '0x1234567890123456789012345678901234567890',
|
|
51
|
+
withdrawalContractAddress: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
52
|
+
requiredFee: mockPayload.requiredFee,
|
|
53
|
+
chainId: 1,
|
|
54
|
+
signer: mockSigner,
|
|
55
|
+
provider: mockProvider,
|
|
56
|
+
});
|
|
57
|
+
expect(result).toEqual(mockResult);
|
|
58
|
+
}));
|
|
59
|
+
it('should throw error when signer is not provided', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
|
+
const eoaWithoutSigner = new eoa_1.EOA(undefined, 1, mockProvider);
|
|
61
|
+
const mockPayload = {
|
|
62
|
+
pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
63
|
+
allocation: 32,
|
|
64
|
+
requiredFee: '1',
|
|
65
|
+
};
|
|
66
|
+
yield expect(eoaWithoutSigner.requestWithdrawal(mockPayload)).rejects.toThrow('Signer is required in requestWithdrawal');
|
|
67
|
+
}));
|
|
68
|
+
it('should throw error when provider is not provided', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
69
|
+
const eoaWithoutProvider = new eoa_1.EOA(mockSigner, 1, null);
|
|
70
|
+
const mockPayload = {
|
|
71
|
+
pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
72
|
+
allocation: 32,
|
|
73
|
+
requiredFee: '1',
|
|
74
|
+
};
|
|
75
|
+
yield expect(eoaWithoutProvider.requestWithdrawal(mockPayload)).rejects.toThrow('Provider is required in requestWithdrawal');
|
|
76
|
+
}));
|
|
77
|
+
it('should throw error when EOA withdrawal contract is not configured for chain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
78
|
+
const eoaUnsupportedChain = new eoa_1.EOA(mockSigner, 999, mockProvider);
|
|
79
|
+
const mockPayload = {
|
|
80
|
+
pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
81
|
+
allocation: 32,
|
|
82
|
+
requiredFee: '1',
|
|
83
|
+
};
|
|
84
|
+
yield expect(eoaUnsupportedChain.requestWithdrawal(mockPayload)).rejects.toThrow('EOA withdrawal contract is not configured for chain 999');
|
|
85
|
+
}));
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -246,6 +246,7 @@ describe('ObolSplits', () => {
|
|
|
246
246
|
ovmAddress: mockOVMAddress,
|
|
247
247
|
pubKeys: mockPubKeys,
|
|
248
248
|
amounts: mockAmounts,
|
|
249
|
+
withdrawalFees: '1',
|
|
249
250
|
});
|
|
250
251
|
expect(result).toEqual({
|
|
251
252
|
txHash: '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
|
|
@@ -254,6 +255,7 @@ describe('ObolSplits', () => {
|
|
|
254
255
|
ovmAddress: mockOVMAddress,
|
|
255
256
|
pubKeys: mockPubKeys,
|
|
256
257
|
amounts: mockAmounts,
|
|
258
|
+
withdrawalFees: '1',
|
|
257
259
|
signer: mockSigner,
|
|
258
260
|
});
|
|
259
261
|
}));
|
|
@@ -263,6 +265,7 @@ describe('ObolSplits', () => {
|
|
|
263
265
|
ovmAddress: mockOVMAddress,
|
|
264
266
|
pubKeys: mockPubKeys,
|
|
265
267
|
amounts: mockAmounts,
|
|
268
|
+
withdrawalFees: '1',
|
|
266
269
|
})).rejects.toThrow('Signer is required in requestWithdrawal');
|
|
267
270
|
}));
|
|
268
271
|
// it('should throw error when amount is below minimum (1,000,000 gwei)', async () => {
|
|
@@ -290,6 +293,7 @@ describe('ObolSplits', () => {
|
|
|
290
293
|
ovmAddress: mockOVMAddress,
|
|
291
294
|
pubKeys: multiplePubKeys,
|
|
292
295
|
amounts: multipleAmounts,
|
|
296
|
+
withdrawalFees: '1',
|
|
293
297
|
});
|
|
294
298
|
expect(result).toEqual({
|
|
295
299
|
txHash: '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
|
|
@@ -298,6 +302,7 @@ describe('ObolSplits', () => {
|
|
|
298
302
|
ovmAddress: mockOVMAddress,
|
|
299
303
|
pubKeys: multiplePubKeys,
|
|
300
304
|
amounts: multipleAmounts,
|
|
305
|
+
withdrawalFees: '1',
|
|
301
306
|
signer: mockSigner,
|
|
302
307
|
});
|
|
303
308
|
}));
|
package/dist/esm/package.json
CHANGED
package/dist/esm/src/ajv.js
CHANGED
|
@@ -62,7 +62,6 @@ const validateOVMTotalSplitRecipients = (_, data) => {
|
|
|
62
62
|
return validateTotalPercentage(splitPercentage);
|
|
63
63
|
};
|
|
64
64
|
const validateOVMRequestWithdrawalPayload = (_, data) => {
|
|
65
|
-
console.log(data, 'hanaaan dataaaa');
|
|
66
65
|
if (!data.pubKeys || !data.amounts) {
|
|
67
66
|
return false;
|
|
68
67
|
}
|
|
@@ -137,6 +137,9 @@ export const CHAIN_CONFIGURATION = {
|
|
|
137
137
|
address: '0x5cbA88D55Cec83caD5A105Ad40C8c9aF20bE21d1',
|
|
138
138
|
bytecode: MAINNET_SPLIT_V2_FACTORY_BYTECODE,
|
|
139
139
|
},
|
|
140
|
+
EOA_WITHDRAWAL_CONTRACT: {
|
|
141
|
+
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
142
|
+
},
|
|
140
143
|
},
|
|
141
144
|
[FORK_MAPPING['0x01017000']]: {
|
|
142
145
|
SPLITMAIN_CONTRACT: {
|
|
@@ -155,6 +158,9 @@ export const CHAIN_CONFIGURATION = {
|
|
|
155
158
|
address: '0x43F641fA70e09f0326ac66b4Ef0C416EaEcBC6f5',
|
|
156
159
|
bytecode: '',
|
|
157
160
|
},
|
|
161
|
+
EOA_WITHDRAWAL_CONTRACT: {
|
|
162
|
+
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
163
|
+
},
|
|
158
164
|
},
|
|
159
165
|
[FORK_MAPPING['0x10000910']]: {
|
|
160
166
|
SPLITMAIN_CONTRACT: {
|
|
@@ -186,6 +192,9 @@ export const CHAIN_CONFIGURATION = {
|
|
|
186
192
|
address: '0x5cbA88D55Cec83caD5A105Ad40C8c9aF20bE21d1',
|
|
187
193
|
bytecode: HOODI_SPLIT_V2_FACTORY_BYTECODE,
|
|
188
194
|
},
|
|
195
|
+
EOA_WITHDRAWAL_CONTRACT: {
|
|
196
|
+
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
197
|
+
},
|
|
189
198
|
},
|
|
190
199
|
};
|
|
191
200
|
export const DEFAULT_RETROACTIVE_FUNDING_REWARDS_ONLY_SPLIT = 1;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { submitEOAWithdrawalRequest } from './eoaHelpers';
|
|
11
|
+
import { validatePayload } from '../ajv';
|
|
12
|
+
import { eoaWithdrawalPayloadSchema } from '../schema';
|
|
13
|
+
import { CHAIN_CONFIGURATION } from '../constants';
|
|
14
|
+
/**
|
|
15
|
+
* EOA can be used for managing EOA (Externally Owned Account) operations like withdrawals.
|
|
16
|
+
* @class
|
|
17
|
+
* @internal Access it through Client.eoa.
|
|
18
|
+
* @example
|
|
19
|
+
* const obolClient = new Client(config);
|
|
20
|
+
* await obolClient.eoa.requestWithdrawal(EOAWithdrawalPayload);
|
|
21
|
+
*/
|
|
22
|
+
export class EOA {
|
|
23
|
+
constructor(signer, chainId, provider) {
|
|
24
|
+
this.signer = signer;
|
|
25
|
+
this.chainId = chainId;
|
|
26
|
+
this.provider = provider;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Requests withdrawal from an EOA contract.
|
|
30
|
+
*
|
|
31
|
+
* This method allows requesting withdrawal of validator funds.
|
|
32
|
+
* The withdrawal request includes validator public key and corresponding withdrawal amount.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
36
|
+
* and not pushed to version control.
|
|
37
|
+
*
|
|
38
|
+
* @param {EOAWithdrawalPayload} payload - Data needed to request withdrawal
|
|
39
|
+
* @returns {Promise<{txHash: string}>} Transaction hash of the withdrawal request
|
|
40
|
+
* @throws Will throw an error if the signer is not provided or the request fails
|
|
41
|
+
*
|
|
42
|
+
* An example of how to use requestWithdrawal:
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const result = await client.eoa.requestWithdrawal({
|
|
45
|
+
* pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
46
|
+
* allocation: 32, // 32 ETH
|
|
47
|
+
* requiredFee: '1' // in wei
|
|
48
|
+
* });
|
|
49
|
+
* console.log('Withdrawal requested:', result.txHash);
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
requestWithdrawal(payload) {
|
|
53
|
+
var _a;
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
if (!this.signer) {
|
|
56
|
+
throw new Error('Signer is required in requestWithdrawal');
|
|
57
|
+
}
|
|
58
|
+
if (!this.provider) {
|
|
59
|
+
throw new Error('Provider is required in requestWithdrawal');
|
|
60
|
+
}
|
|
61
|
+
const chainConfig = CHAIN_CONFIGURATION[this.chainId];
|
|
62
|
+
if (!((_a = chainConfig === null || chainConfig === void 0 ? void 0 : chainConfig.EOA_WITHDRAWAL_CONTRACT) === null || _a === void 0 ? void 0 : _a.address)) {
|
|
63
|
+
throw new Error(`EOA withdrawal contract is not configured for chain ${this.chainId}`);
|
|
64
|
+
}
|
|
65
|
+
const validatedPayload = validatePayload(payload, eoaWithdrawalPayloadSchema);
|
|
66
|
+
const withdrawalAddress = yield this.signer.getAddress();
|
|
67
|
+
return yield submitEOAWithdrawalRequest({
|
|
68
|
+
pubkey: validatedPayload.pubkey,
|
|
69
|
+
allocation: validatedPayload.allocation,
|
|
70
|
+
withdrawalAddress,
|
|
71
|
+
withdrawalContractAddress: chainConfig.EOA_WITHDRAWAL_CONTRACT.address,
|
|
72
|
+
requiredFee: validatedPayload.requiredFee,
|
|
73
|
+
chainId: this.chainId,
|
|
74
|
+
signer: this.signer,
|
|
75
|
+
provider: this.provider,
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { ETHER_TO_GWEI } from '../constants';
|
|
11
|
+
/**
|
|
12
|
+
* Helper function to submit withdrawal request for EOA
|
|
13
|
+
*/
|
|
14
|
+
export function submitEOAWithdrawalRequest({ pubkey, allocation, withdrawalAddress, withdrawalContractAddress, requiredFee, chainId, signer, provider, }) {
|
|
15
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
if (!withdrawalAddress)
|
|
17
|
+
throw new Error('No withdrawal address provided');
|
|
18
|
+
if (!allocation)
|
|
19
|
+
throw new Error('No allocation provided');
|
|
20
|
+
const amountInGwei = BigInt(Math.floor(Number(allocation) * ETHER_TO_GWEI));
|
|
21
|
+
const data = `0x${pubkey.slice(2)}${amountInGwei.toString(16).padStart(16, '0')}`;
|
|
22
|
+
const { hash } = yield signer.sendTransaction({
|
|
23
|
+
to: withdrawalContractAddress,
|
|
24
|
+
chainId,
|
|
25
|
+
value: BigInt(requiredFee),
|
|
26
|
+
data: data,
|
|
27
|
+
});
|
|
28
|
+
const txResult = yield provider.getTransactionReceipt(hash);
|
|
29
|
+
if (!txResult)
|
|
30
|
+
return { txHash: null };
|
|
31
|
+
return { txHash: txResult === null || txResult === void 0 ? void 0 : txResult.hash };
|
|
32
|
+
});
|
|
33
|
+
}
|
package/dist/esm/src/index.js
CHANGED
|
@@ -19,6 +19,7 @@ import { isContractAvailable } from './utils.js';
|
|
|
19
19
|
import { Incentives } from './incentives/incentives.js';
|
|
20
20
|
import { Exit } from './exits/exit.js';
|
|
21
21
|
import { ObolSplits } from './splits/splits.js';
|
|
22
|
+
import { EOA } from './eoa/eoa.js';
|
|
22
23
|
export * from './types.js';
|
|
23
24
|
export * from './services.js';
|
|
24
25
|
export * from './verification/signature-validator.js';
|
|
@@ -27,6 +28,7 @@ export * from './constants.js';
|
|
|
27
28
|
export { Incentives } from './incentives/incentives.js';
|
|
28
29
|
export { Exit } from './exits/exit.js';
|
|
29
30
|
export { ObolSplits } from './splits/splits.js';
|
|
31
|
+
export { EOA } from './eoa/eoa.js';
|
|
30
32
|
/**
|
|
31
33
|
* Obol sdk Client can be used for creating, managing and activating distributed validators.
|
|
32
34
|
*/
|
|
@@ -50,6 +52,7 @@ export class Client extends Base {
|
|
|
50
52
|
this.incentives = new Incentives(this.signer, this.chainId, this.request.bind(this), this.provider);
|
|
51
53
|
this.exit = new Exit(this.chainId, this.provider);
|
|
52
54
|
this.splits = new ObolSplits(this.signer, this.chainId, this.provider);
|
|
55
|
+
this.eoa = new EOA(this.signer, this.chainId, this.provider);
|
|
53
56
|
}
|
|
54
57
|
/**
|
|
55
58
|
* Accepts Obol terms and conditions to be able to create or update data.
|