@obolnetwork/obol-sdk 2.9.1 → 2.10.1
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/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 +19 -1
- package/dist/cjs/src/splits/splitHelpers.js +2 -2
- package/dist/cjs/test/eoa/eoa.spec.js +98 -0
- package/dist/esm/package.json +1 -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 +18 -0
- package/dist/esm/src/splits/splitHelpers.js +3 -3
- package/dist/esm/test/eoa/eoa.spec.js +96 -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 +18 -0
- package/dist/types/src/types.d.ts +16 -2
- package/dist/types/test/eoa/eoa.spec.d.ts +1 -0
- package/package.json +1 -1
- package/src/constants.ts +9 -0
- package/src/eoa/eoa.ts +94 -0
- package/src/eoa/eoaHelpers.ts +42 -0
- package/src/index.ts +9 -0
- package/src/schema.ts +19 -0
- package/src/splits/splitHelpers.ts +3 -3
- package/src/types.ts +19 -2
package/dist/cjs/package.json
CHANGED
|
@@ -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 tx = yield signer.sendTransaction({
|
|
26
|
+
to: withdrawalContractAddress,
|
|
27
|
+
chainId,
|
|
28
|
+
value: BigInt(requiredFee),
|
|
29
|
+
data: data,
|
|
30
|
+
});
|
|
31
|
+
const receipt = yield tx.wait();
|
|
32
|
+
if (!receipt)
|
|
33
|
+
return { txHash: null };
|
|
34
|
+
return { txHash: receipt.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");
|
|
@@ -240,3 +240,21 @@ exports.ovmRequestWithdrawalPayloadSchema = {
|
|
|
240
240
|
validateOVMRequestWithdrawalPayload: true,
|
|
241
241
|
required: ['ovmAddress', 'pubKeys', 'amounts', 'withdrawalFees'],
|
|
242
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'],
|
|
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,
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
it('should return null txHash when transaction receipt is null', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
87
|
+
const mockPayload = {
|
|
88
|
+
pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
89
|
+
allocation: 32,
|
|
90
|
+
requiredFee: '1',
|
|
91
|
+
};
|
|
92
|
+
const mockResult = { txHash: null };
|
|
93
|
+
eoaHelpers_1.submitEOAWithdrawalRequest.mockResolvedValue(mockResult);
|
|
94
|
+
const result = yield eoa.requestWithdrawal(mockPayload);
|
|
95
|
+
expect(result).toEqual(mockResult);
|
|
96
|
+
}));
|
|
97
|
+
});
|
|
98
|
+
});
|
package/dist/esm/package.json
CHANGED
|
@@ -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 tx = yield signer.sendTransaction({
|
|
23
|
+
to: withdrawalContractAddress,
|
|
24
|
+
chainId,
|
|
25
|
+
value: BigInt(requiredFee),
|
|
26
|
+
data: data,
|
|
27
|
+
});
|
|
28
|
+
const receipt = yield tx.wait();
|
|
29
|
+
if (!receipt)
|
|
30
|
+
return { txHash: null };
|
|
31
|
+
return { txHash: receipt.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.
|
package/dist/esm/src/schema.js
CHANGED
|
@@ -237,3 +237,21 @@ export const ovmRequestWithdrawalPayloadSchema = {
|
|
|
237
237
|
validateOVMRequestWithdrawalPayload: true,
|
|
238
238
|
required: ['ovmAddress', 'pubKeys', 'amounts', 'withdrawalFees'],
|
|
239
239
|
};
|
|
240
|
+
export const eoaWithdrawalPayloadSchema = {
|
|
241
|
+
type: 'object',
|
|
242
|
+
properties: {
|
|
243
|
+
pubkey: {
|
|
244
|
+
type: 'string',
|
|
245
|
+
pattern: '^0x[a-fA-F0-9]{96}$', // 48 bytes = 96 hex chars + 0x prefix
|
|
246
|
+
},
|
|
247
|
+
allocation: {
|
|
248
|
+
type: 'number',
|
|
249
|
+
minimum: 0,
|
|
250
|
+
},
|
|
251
|
+
requiredFee: {
|
|
252
|
+
type: 'string',
|
|
253
|
+
pattern: '^[0-9]+$',
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
required: ['pubkey', 'allocation', 'requiredFee'],
|
|
257
|
+
};
|
|
@@ -12,7 +12,7 @@ import { OWRContract, OWRFactoryContract } from '../abi/OWR';
|
|
|
12
12
|
import { OVMFactoryContract, OVMContract } from '../abi/OVMFactory';
|
|
13
13
|
import { splitMainEthereumAbi } from '../abi/SplitMain';
|
|
14
14
|
import { MultiCallContract } from '../abi/Multicall';
|
|
15
|
-
import { CHAIN_CONFIGURATION } from '../constants';
|
|
15
|
+
import { CHAIN_CONFIGURATION, ETHER_TO_GWEI } from '../constants';
|
|
16
16
|
import { splitV2FactoryAbi } from '../abi/splitV2FactoryAbi';
|
|
17
17
|
const splitMainContractInterface = new Interface(splitMainEthereumAbi);
|
|
18
18
|
const owrFactoryContractInterface = new Interface(OWRFactoryContract.abi);
|
|
@@ -397,7 +397,7 @@ export const deployOVMContract = ({ OVMOwnerAddress, principalRecipient, rewardR
|
|
|
397
397
|
throw new Error(`OVM Factory not configured for chain ${chainId}`);
|
|
398
398
|
}
|
|
399
399
|
const ovmFactoryContract = new Contract(chainConfig.OVM_FACTORY_CONTRACT.address, OVMFactoryContract.abi, signer);
|
|
400
|
-
const tx = yield ovmFactoryContract.createObolValidatorManager(OVMOwnerAddress, principalRecipient, rewardRecipient, principalThreshold);
|
|
400
|
+
const tx = yield ovmFactoryContract.createObolValidatorManager(OVMOwnerAddress, principalRecipient, rewardRecipient, principalThreshold * ETHER_TO_GWEI);
|
|
401
401
|
const receipt = yield tx.wait();
|
|
402
402
|
// Extract OVM address from logs
|
|
403
403
|
const ovmAddressLog = (_3 = receipt === null || receipt === void 0 ? void 0 : receipt.logs[1]) === null || _3 === void 0 ? void 0 : _3.topics[1];
|
|
@@ -441,7 +441,7 @@ export const deployOVMAndSplitV2 = ({ ovmArgs, rewardRecipients, isRewardsSplitt
|
|
|
441
441
|
});
|
|
442
442
|
}
|
|
443
443
|
// Create OVM call data
|
|
444
|
-
const ovmTxData = encodeCreateOVMTxData(ovmArgs.OVMOwnerAddress, ovmArgs.principalRecipient, ovmArgs.rewardRecipient, ovmArgs.principalThreshold);
|
|
444
|
+
const ovmTxData = encodeCreateOVMTxData(ovmArgs.OVMOwnerAddress, ovmArgs.principalRecipient, ovmArgs.rewardRecipient, ovmArgs.principalThreshold * ETHER_TO_GWEI);
|
|
445
445
|
executeCalls.push({
|
|
446
446
|
target: chainConfig.OVM_FACTORY_CONTRACT.address,
|
|
447
447
|
callData: ovmTxData,
|
|
@@ -0,0 +1,96 @@
|
|
|
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 { EOA } from '../../src/eoa/eoa';
|
|
11
|
+
import { submitEOAWithdrawalRequest } from '../../src/eoa/eoaHelpers';
|
|
12
|
+
// Mock the helper function
|
|
13
|
+
jest.mock('../../src/eoa/eoaHelpers', () => ({
|
|
14
|
+
submitEOAWithdrawalRequest: jest.fn(),
|
|
15
|
+
}));
|
|
16
|
+
describe('EOA', () => {
|
|
17
|
+
let eoa;
|
|
18
|
+
let mockSigner;
|
|
19
|
+
let mockProvider;
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
// Clear all mocks before each test
|
|
22
|
+
jest.clearAllMocks();
|
|
23
|
+
mockSigner = {
|
|
24
|
+
getAddress: jest
|
|
25
|
+
.fn()
|
|
26
|
+
.mockResolvedValue('0x1234567890123456789012345678901234567890'),
|
|
27
|
+
};
|
|
28
|
+
mockProvider = {
|
|
29
|
+
getNetwork: jest.fn().mockResolvedValue({ chainId: 1 }),
|
|
30
|
+
};
|
|
31
|
+
eoa = new EOA(mockSigner, 1, mockProvider);
|
|
32
|
+
});
|
|
33
|
+
describe('requestWithdrawal', () => {
|
|
34
|
+
it('should successfully request withdrawal', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
+
const mockPayload = {
|
|
36
|
+
pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
37
|
+
allocation: 32,
|
|
38
|
+
requiredFee: '1',
|
|
39
|
+
};
|
|
40
|
+
const mockResult = {
|
|
41
|
+
txHash: '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
|
|
42
|
+
};
|
|
43
|
+
submitEOAWithdrawalRequest.mockResolvedValue(mockResult);
|
|
44
|
+
const result = yield eoa.requestWithdrawal(mockPayload);
|
|
45
|
+
expect(submitEOAWithdrawalRequest).toHaveBeenCalledWith({
|
|
46
|
+
pubkey: mockPayload.pubkey,
|
|
47
|
+
allocation: mockPayload.allocation,
|
|
48
|
+
withdrawalAddress: '0x1234567890123456789012345678901234567890',
|
|
49
|
+
withdrawalContractAddress: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
50
|
+
requiredFee: mockPayload.requiredFee,
|
|
51
|
+
chainId: 1,
|
|
52
|
+
signer: mockSigner,
|
|
53
|
+
provider: mockProvider,
|
|
54
|
+
});
|
|
55
|
+
expect(result).toEqual(mockResult);
|
|
56
|
+
}));
|
|
57
|
+
it('should throw error when signer is not provided', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
58
|
+
const eoaWithoutSigner = new EOA(undefined, 1, mockProvider);
|
|
59
|
+
const mockPayload = {
|
|
60
|
+
pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
61
|
+
allocation: 32,
|
|
62
|
+
requiredFee: '1',
|
|
63
|
+
};
|
|
64
|
+
yield expect(eoaWithoutSigner.requestWithdrawal(mockPayload)).rejects.toThrow('Signer is required in requestWithdrawal');
|
|
65
|
+
}));
|
|
66
|
+
it('should throw error when provider is not provided', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
67
|
+
const eoaWithoutProvider = new EOA(mockSigner, 1, null);
|
|
68
|
+
const mockPayload = {
|
|
69
|
+
pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
70
|
+
allocation: 32,
|
|
71
|
+
requiredFee: '1',
|
|
72
|
+
};
|
|
73
|
+
yield expect(eoaWithoutProvider.requestWithdrawal(mockPayload)).rejects.toThrow('Provider is required in requestWithdrawal');
|
|
74
|
+
}));
|
|
75
|
+
it('should throw error when EOA withdrawal contract is not configured for chain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
76
|
+
const eoaUnsupportedChain = new EOA(mockSigner, 999, mockProvider);
|
|
77
|
+
const mockPayload = {
|
|
78
|
+
pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
79
|
+
allocation: 32,
|
|
80
|
+
requiredFee: '1',
|
|
81
|
+
};
|
|
82
|
+
yield expect(eoaUnsupportedChain.requestWithdrawal(mockPayload)).rejects.toThrow('EOA withdrawal contract is not configured for chain 999');
|
|
83
|
+
}));
|
|
84
|
+
it('should return null txHash when transaction receipt is null', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
85
|
+
const mockPayload = {
|
|
86
|
+
pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
87
|
+
allocation: 32,
|
|
88
|
+
requiredFee: '1',
|
|
89
|
+
};
|
|
90
|
+
const mockResult = { txHash: null };
|
|
91
|
+
submitEOAWithdrawalRequest.mockResolvedValue(mockResult);
|
|
92
|
+
const result = yield eoa.requestWithdrawal(mockPayload);
|
|
93
|
+
expect(result).toEqual(mockResult);
|
|
94
|
+
}));
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ProviderType, type SignerType, type EOAWithdrawalPayload } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* EOA can be used for managing EOA (Externally Owned Account) operations like withdrawals.
|
|
4
|
+
* @class
|
|
5
|
+
* @internal Access it through Client.eoa.
|
|
6
|
+
* @example
|
|
7
|
+
* const obolClient = new Client(config);
|
|
8
|
+
* await obolClient.eoa.requestWithdrawal(EOAWithdrawalPayload);
|
|
9
|
+
*/
|
|
10
|
+
export declare class EOA {
|
|
11
|
+
private readonly signer;
|
|
12
|
+
readonly chainId: number;
|
|
13
|
+
readonly provider: ProviderType | undefined | null;
|
|
14
|
+
constructor(signer: SignerType | undefined, chainId: number, provider: ProviderType | undefined | null);
|
|
15
|
+
/**
|
|
16
|
+
* Requests withdrawal from an EOA contract.
|
|
17
|
+
*
|
|
18
|
+
* This method allows requesting withdrawal of validator funds.
|
|
19
|
+
* The withdrawal request includes validator public key and corresponding withdrawal amount.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
23
|
+
* and not pushed to version control.
|
|
24
|
+
*
|
|
25
|
+
* @param {EOAWithdrawalPayload} payload - Data needed to request withdrawal
|
|
26
|
+
* @returns {Promise<{txHash: string}>} Transaction hash of the withdrawal request
|
|
27
|
+
* @throws Will throw an error if the signer is not provided or the request fails
|
|
28
|
+
*
|
|
29
|
+
* An example of how to use requestWithdrawal:
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const result = await client.eoa.requestWithdrawal({
|
|
32
|
+
* pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
33
|
+
* allocation: 32, // 32 ETH
|
|
34
|
+
* requiredFee: '1' // in wei
|
|
35
|
+
* });
|
|
36
|
+
* console.log('Withdrawal requested:', result.txHash);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
requestWithdrawal(payload: EOAWithdrawalPayload): Promise<{
|
|
40
|
+
txHash: string | null;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type SignerType, type ProviderType } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Helper function to submit withdrawal request for EOA
|
|
4
|
+
*/
|
|
5
|
+
export declare function submitEOAWithdrawalRequest({ pubkey, allocation, withdrawalAddress, withdrawalContractAddress, requiredFee, chainId, signer, provider, }: {
|
|
6
|
+
pubkey: string;
|
|
7
|
+
allocation: number;
|
|
8
|
+
withdrawalAddress: string;
|
|
9
|
+
withdrawalContractAddress: string;
|
|
10
|
+
requiredFee: string;
|
|
11
|
+
chainId: number;
|
|
12
|
+
signer: SignerType;
|
|
13
|
+
provider: ProviderType;
|
|
14
|
+
}): Promise<{
|
|
15
|
+
txHash: string | null;
|
|
16
|
+
}>;
|
|
@@ -3,6 +3,7 @@ import { type RewardsSplitPayload, type ClusterDefinition, type ClusterLock, typ
|
|
|
3
3
|
import { Incentives } from './incentives/incentives.js';
|
|
4
4
|
import { Exit } from './exits/exit.js';
|
|
5
5
|
import { ObolSplits } from './splits/splits.js';
|
|
6
|
+
import { EOA } from './eoa/eoa.js';
|
|
6
7
|
export * from './types.js';
|
|
7
8
|
export * from './services.js';
|
|
8
9
|
export * from './verification/signature-validator.js';
|
|
@@ -11,6 +12,7 @@ export * from './constants.js';
|
|
|
11
12
|
export { Incentives } from './incentives/incentives.js';
|
|
12
13
|
export { Exit } from './exits/exit.js';
|
|
13
14
|
export { ObolSplits } from './splits/splits.js';
|
|
15
|
+
export { EOA } from './eoa/eoa.js';
|
|
14
16
|
/**
|
|
15
17
|
* Obol sdk Client can be used for creating, managing and activating distributed validators.
|
|
16
18
|
*/
|
|
@@ -34,6 +36,11 @@ export declare class Client extends Base {
|
|
|
34
36
|
* @type {ObolSplits}
|
|
35
37
|
*/
|
|
36
38
|
splits: ObolSplits;
|
|
39
|
+
/**
|
|
40
|
+
* The eoa module, responsible for managing EOA operations.
|
|
41
|
+
* @type {EOA}
|
|
42
|
+
*/
|
|
43
|
+
eoa: EOA;
|
|
37
44
|
/**
|
|
38
45
|
* The blockchain provider, used to interact with the network.
|
|
39
46
|
* It can be null, undefined, or a valid provider instance and defaults to the Signer provider if Signer is passed.
|
|
@@ -352,3 +352,21 @@ export declare const ovmRequestWithdrawalPayloadSchema: {
|
|
|
352
352
|
validateOVMRequestWithdrawalPayload: boolean;
|
|
353
353
|
required: string[];
|
|
354
354
|
};
|
|
355
|
+
export declare const eoaWithdrawalPayloadSchema: {
|
|
356
|
+
type: string;
|
|
357
|
+
properties: {
|
|
358
|
+
pubkey: {
|
|
359
|
+
type: string;
|
|
360
|
+
pattern: string;
|
|
361
|
+
};
|
|
362
|
+
allocation: {
|
|
363
|
+
type: string;
|
|
364
|
+
minimum: number;
|
|
365
|
+
};
|
|
366
|
+
requiredFee: {
|
|
367
|
+
type: string;
|
|
368
|
+
pattern: string;
|
|
369
|
+
};
|
|
370
|
+
};
|
|
371
|
+
required: string[];
|
|
372
|
+
};
|
|
@@ -149,7 +149,7 @@ export type OVMBaseSplitPayload = {
|
|
|
149
149
|
OVMOwnerAddress: string;
|
|
150
150
|
/** Owner address for the splitter contracts. */
|
|
151
151
|
splitOwnerAddress?: string;
|
|
152
|
-
/** Principal threshold for OVM contract. */
|
|
152
|
+
/** Principal threshold in ETH for OVM contract. */
|
|
153
153
|
principalThreshold?: number;
|
|
154
154
|
/** Distributor fee percentage (0-10). */
|
|
155
155
|
distributorFeePercent?: number;
|
|
@@ -439,7 +439,7 @@ export type OVMArgs = {
|
|
|
439
439
|
principalRecipient: string;
|
|
440
440
|
/** Rewards recipient of the cluster. */
|
|
441
441
|
rewardRecipient: string;
|
|
442
|
-
/** Principal threshold for OVM contract. */
|
|
442
|
+
/** Principal threshold in ETH for OVM contract. */
|
|
443
443
|
principalThreshold: number;
|
|
444
444
|
};
|
|
445
445
|
export type ChainConfig = {
|
|
@@ -471,6 +471,9 @@ export type ChainConfig = {
|
|
|
471
471
|
address: string;
|
|
472
472
|
bytecode: string;
|
|
473
473
|
};
|
|
474
|
+
EOA_WITHDRAWAL_CONTRACT?: {
|
|
475
|
+
address: string;
|
|
476
|
+
};
|
|
474
477
|
};
|
|
475
478
|
/**
|
|
476
479
|
* Payload for requesting withdrawal from OVM contract
|
|
@@ -485,3 +488,14 @@ export type OVMRequestWithdrawalPayload = {
|
|
|
485
488
|
/** Array of withdrawal amounts in gwei (uint64) as strings */
|
|
486
489
|
amounts: string[];
|
|
487
490
|
};
|
|
491
|
+
/**
|
|
492
|
+
* Payload for requesting withdrawal from EOA contract
|
|
493
|
+
*/
|
|
494
|
+
export type EOAWithdrawalPayload = {
|
|
495
|
+
/** Validator public key in hex format */
|
|
496
|
+
pubkey: string;
|
|
497
|
+
/** Withdrawal amount in ETH */
|
|
498
|
+
allocation: number;
|
|
499
|
+
/** Required fee in wei */
|
|
500
|
+
requiredFee: string;
|
|
501
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -199,6 +199,9 @@ export const CHAIN_CONFIGURATION: Record<number, ChainConfig> = {
|
|
|
199
199
|
address: '0x5cbA88D55Cec83caD5A105Ad40C8c9aF20bE21d1',
|
|
200
200
|
bytecode: MAINNET_SPLIT_V2_FACTORY_BYTECODE,
|
|
201
201
|
},
|
|
202
|
+
EOA_WITHDRAWAL_CONTRACT: {
|
|
203
|
+
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
204
|
+
},
|
|
202
205
|
},
|
|
203
206
|
[FORK_MAPPING['0x01017000']]: {
|
|
204
207
|
SPLITMAIN_CONTRACT: {
|
|
@@ -217,6 +220,9 @@ export const CHAIN_CONFIGURATION: Record<number, ChainConfig> = {
|
|
|
217
220
|
address: '0x43F641fA70e09f0326ac66b4Ef0C416EaEcBC6f5',
|
|
218
221
|
bytecode: '',
|
|
219
222
|
},
|
|
223
|
+
EOA_WITHDRAWAL_CONTRACT: {
|
|
224
|
+
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
225
|
+
},
|
|
220
226
|
},
|
|
221
227
|
[FORK_MAPPING['0x10000910']]: {
|
|
222
228
|
SPLITMAIN_CONTRACT: {
|
|
@@ -248,6 +254,9 @@ export const CHAIN_CONFIGURATION: Record<number, ChainConfig> = {
|
|
|
248
254
|
address: '0x5cbA88D55Cec83caD5A105Ad40C8c9aF20bE21d1',
|
|
249
255
|
bytecode: HOODI_SPLIT_V2_FACTORY_BYTECODE,
|
|
250
256
|
},
|
|
257
|
+
EOA_WITHDRAWAL_CONTRACT: {
|
|
258
|
+
address: '0x00000961Ef480Eb55e80D19ad83579A64c007002',
|
|
259
|
+
},
|
|
251
260
|
},
|
|
252
261
|
};
|
|
253
262
|
|
package/src/eoa/eoa.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { submitEOAWithdrawalRequest } from './eoaHelpers';
|
|
2
|
+
import { validatePayload } from '../ajv';
|
|
3
|
+
import { eoaWithdrawalPayloadSchema } from '../schema';
|
|
4
|
+
import { CHAIN_CONFIGURATION } from '../constants';
|
|
5
|
+
import {
|
|
6
|
+
type ProviderType,
|
|
7
|
+
type SignerType,
|
|
8
|
+
type EOAWithdrawalPayload,
|
|
9
|
+
} from '../types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* EOA can be used for managing EOA (Externally Owned Account) operations like withdrawals.
|
|
13
|
+
* @class
|
|
14
|
+
* @internal Access it through Client.eoa.
|
|
15
|
+
* @example
|
|
16
|
+
* const obolClient = new Client(config);
|
|
17
|
+
* await obolClient.eoa.requestWithdrawal(EOAWithdrawalPayload);
|
|
18
|
+
*/
|
|
19
|
+
export class EOA {
|
|
20
|
+
private readonly signer: SignerType | undefined;
|
|
21
|
+
public readonly chainId: number;
|
|
22
|
+
public readonly provider: ProviderType | undefined | null;
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
signer: SignerType | undefined,
|
|
26
|
+
chainId: number,
|
|
27
|
+
provider: ProviderType | undefined | null,
|
|
28
|
+
) {
|
|
29
|
+
this.signer = signer;
|
|
30
|
+
this.chainId = chainId;
|
|
31
|
+
this.provider = provider;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Requests withdrawal from an EOA contract.
|
|
36
|
+
*
|
|
37
|
+
* This method allows requesting withdrawal of validator funds.
|
|
38
|
+
* The withdrawal request includes validator public key and corresponding withdrawal amount.
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
42
|
+
* and not pushed to version control.
|
|
43
|
+
*
|
|
44
|
+
* @param {EOAWithdrawalPayload} payload - Data needed to request withdrawal
|
|
45
|
+
* @returns {Promise<{txHash: string}>} Transaction hash of the withdrawal request
|
|
46
|
+
* @throws Will throw an error if the signer is not provided or the request fails
|
|
47
|
+
*
|
|
48
|
+
* An example of how to use requestWithdrawal:
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const result = await client.eoa.requestWithdrawal({
|
|
51
|
+
* pubkey: '0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456',
|
|
52
|
+
* allocation: 32, // 32 ETH
|
|
53
|
+
* requiredFee: '1' // in wei
|
|
54
|
+
* });
|
|
55
|
+
* console.log('Withdrawal requested:', result.txHash);
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
async requestWithdrawal(
|
|
59
|
+
payload: EOAWithdrawalPayload,
|
|
60
|
+
): Promise<{ txHash: string | null }> {
|
|
61
|
+
if (!this.signer) {
|
|
62
|
+
throw new Error('Signer is required in requestWithdrawal');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!this.provider) {
|
|
66
|
+
throw new Error('Provider is required in requestWithdrawal');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const chainConfig = CHAIN_CONFIGURATION[this.chainId];
|
|
70
|
+
if (!chainConfig?.EOA_WITHDRAWAL_CONTRACT?.address) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`EOA withdrawal contract is not configured for chain ${this.chainId}`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const validatedPayload = validatePayload<EOAWithdrawalPayload>(
|
|
77
|
+
payload,
|
|
78
|
+
eoaWithdrawalPayloadSchema,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const withdrawalAddress = await this.signer.getAddress();
|
|
82
|
+
|
|
83
|
+
return await submitEOAWithdrawalRequest({
|
|
84
|
+
pubkey: validatedPayload.pubkey,
|
|
85
|
+
allocation: validatedPayload.allocation,
|
|
86
|
+
withdrawalAddress,
|
|
87
|
+
withdrawalContractAddress: chainConfig.EOA_WITHDRAWAL_CONTRACT.address,
|
|
88
|
+
requiredFee: validatedPayload.requiredFee,
|
|
89
|
+
chainId: this.chainId,
|
|
90
|
+
signer: this.signer,
|
|
91
|
+
provider: this.provider,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ETHER_TO_GWEI } from '../constants';
|
|
2
|
+
import { type SignerType, type ProviderType } from '../types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Helper function to submit withdrawal request for EOA
|
|
6
|
+
*/
|
|
7
|
+
export async function submitEOAWithdrawalRequest({
|
|
8
|
+
pubkey,
|
|
9
|
+
allocation,
|
|
10
|
+
withdrawalAddress,
|
|
11
|
+
withdrawalContractAddress,
|
|
12
|
+
requiredFee,
|
|
13
|
+
chainId,
|
|
14
|
+
signer,
|
|
15
|
+
provider,
|
|
16
|
+
}: {
|
|
17
|
+
pubkey: string;
|
|
18
|
+
allocation: number;
|
|
19
|
+
withdrawalAddress: string;
|
|
20
|
+
withdrawalContractAddress: string;
|
|
21
|
+
requiredFee: string;
|
|
22
|
+
chainId: number;
|
|
23
|
+
signer: SignerType;
|
|
24
|
+
provider: ProviderType;
|
|
25
|
+
}): Promise<{ txHash: string | null }> {
|
|
26
|
+
if (!withdrawalAddress) throw new Error('No withdrawal address provided');
|
|
27
|
+
if (!allocation) throw new Error('No allocation provided');
|
|
28
|
+
|
|
29
|
+
const amountInGwei = BigInt(Math.floor(Number(allocation) * ETHER_TO_GWEI));
|
|
30
|
+
const data = `0x${pubkey.slice(2)}${amountInGwei.toString(16).padStart(16, '0')}`;
|
|
31
|
+
|
|
32
|
+
const tx = await signer.sendTransaction({
|
|
33
|
+
to: withdrawalContractAddress,
|
|
34
|
+
chainId,
|
|
35
|
+
value: BigInt(requiredFee),
|
|
36
|
+
data: data as `0x${string}`,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const receipt = await tx.wait();
|
|
40
|
+
if (!receipt) return { txHash: null };
|
|
41
|
+
return { txHash: receipt.hash };
|
|
42
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -50,6 +50,7 @@ import { isContractAvailable } from './utils.js';
|
|
|
50
50
|
import { Incentives } from './incentives/incentives.js';
|
|
51
51
|
import { Exit } from './exits/exit.js';
|
|
52
52
|
import { ObolSplits } from './splits/splits.js';
|
|
53
|
+
import { EOA } from './eoa/eoa.js';
|
|
53
54
|
export * from './types.js';
|
|
54
55
|
export * from './services.js';
|
|
55
56
|
export * from './verification/signature-validator.js';
|
|
@@ -58,6 +59,7 @@ export * from './constants.js';
|
|
|
58
59
|
export { Incentives } from './incentives/incentives.js';
|
|
59
60
|
export { Exit } from './exits/exit.js';
|
|
60
61
|
export { ObolSplits } from './splits/splits.js';
|
|
62
|
+
export { EOA } from './eoa/eoa.js';
|
|
61
63
|
|
|
62
64
|
/**
|
|
63
65
|
* Obol sdk Client can be used for creating, managing and activating distributed validators.
|
|
@@ -86,6 +88,12 @@ export class Client extends Base {
|
|
|
86
88
|
*/
|
|
87
89
|
public splits: ObolSplits;
|
|
88
90
|
|
|
91
|
+
/**
|
|
92
|
+
* The eoa module, responsible for managing EOA operations.
|
|
93
|
+
* @type {EOA}
|
|
94
|
+
*/
|
|
95
|
+
public eoa: EOA;
|
|
96
|
+
|
|
89
97
|
/**
|
|
90
98
|
* The blockchain provider, used to interact with the network.
|
|
91
99
|
* It can be null, undefined, or a valid provider instance and defaults to the Signer provider if Signer is passed.
|
|
@@ -121,6 +129,7 @@ export class Client extends Base {
|
|
|
121
129
|
);
|
|
122
130
|
this.exit = new Exit(this.chainId, this.provider);
|
|
123
131
|
this.splits = new ObolSplits(this.signer, this.chainId, this.provider);
|
|
132
|
+
this.eoa = new EOA(this.signer, this.chainId, this.provider);
|
|
124
133
|
}
|
|
125
134
|
|
|
126
135
|
/**
|
package/src/schema.ts
CHANGED
|
@@ -261,3 +261,22 @@ export const ovmRequestWithdrawalPayloadSchema = {
|
|
|
261
261
|
validateOVMRequestWithdrawalPayload: true,
|
|
262
262
|
required: ['ovmAddress', 'pubKeys', 'amounts', 'withdrawalFees'],
|
|
263
263
|
};
|
|
264
|
+
|
|
265
|
+
export const eoaWithdrawalPayloadSchema = {
|
|
266
|
+
type: 'object',
|
|
267
|
+
properties: {
|
|
268
|
+
pubkey: {
|
|
269
|
+
type: 'string',
|
|
270
|
+
pattern: '^0x[a-fA-F0-9]{96}$', // 48 bytes = 96 hex chars + 0x prefix
|
|
271
|
+
},
|
|
272
|
+
allocation: {
|
|
273
|
+
type: 'number',
|
|
274
|
+
minimum: 0,
|
|
275
|
+
},
|
|
276
|
+
requiredFee: {
|
|
277
|
+
type: 'string',
|
|
278
|
+
pattern: '^[0-9]+$',
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
required: ['pubkey', 'allocation', 'requiredFee'],
|
|
282
|
+
};
|
|
@@ -13,7 +13,7 @@ import { OWRContract, OWRFactoryContract } from '../abi/OWR';
|
|
|
13
13
|
import { OVMFactoryContract, OVMContract } from '../abi/OVMFactory';
|
|
14
14
|
import { splitMainEthereumAbi } from '../abi/SplitMain';
|
|
15
15
|
import { MultiCallContract } from '../abi/Multicall';
|
|
16
|
-
import { CHAIN_CONFIGURATION } from '../constants';
|
|
16
|
+
import { CHAIN_CONFIGURATION, ETHER_TO_GWEI } from '../constants';
|
|
17
17
|
import { splitV2FactoryAbi } from '../abi/splitV2FactoryAbi';
|
|
18
18
|
|
|
19
19
|
const splitMainContractInterface = new Interface(splitMainEthereumAbi);
|
|
@@ -742,7 +742,7 @@ export const deployOVMContract = async ({
|
|
|
742
742
|
OVMOwnerAddress,
|
|
743
743
|
principalRecipient,
|
|
744
744
|
rewardRecipient,
|
|
745
|
-
principalThreshold,
|
|
745
|
+
principalThreshold * ETHER_TO_GWEI,
|
|
746
746
|
);
|
|
747
747
|
|
|
748
748
|
const receipt = await tx.wait();
|
|
@@ -837,7 +837,7 @@ export const deployOVMAndSplitV2 = async ({
|
|
|
837
837
|
ovmArgs.OVMOwnerAddress,
|
|
838
838
|
ovmArgs.principalRecipient,
|
|
839
839
|
ovmArgs.rewardRecipient,
|
|
840
|
-
ovmArgs.principalThreshold,
|
|
840
|
+
ovmArgs.principalThreshold * ETHER_TO_GWEI,
|
|
841
841
|
);
|
|
842
842
|
|
|
843
843
|
executeCalls.push({
|
package/src/types.ts
CHANGED
|
@@ -214,7 +214,7 @@ export type OVMBaseSplitPayload = {
|
|
|
214
214
|
/** Owner address for the splitter contracts. */
|
|
215
215
|
splitOwnerAddress?: string;
|
|
216
216
|
|
|
217
|
-
/** Principal threshold for OVM contract. */
|
|
217
|
+
/** Principal threshold in ETH for OVM contract. */
|
|
218
218
|
principalThreshold?: number;
|
|
219
219
|
|
|
220
220
|
/** Distributor fee percentage (0-10). */
|
|
@@ -573,7 +573,7 @@ export type OVMArgs = {
|
|
|
573
573
|
/** Rewards recipient of the cluster. */
|
|
574
574
|
rewardRecipient: string;
|
|
575
575
|
|
|
576
|
-
/** Principal threshold for OVM contract. */
|
|
576
|
+
/** Principal threshold in ETH for OVM contract. */
|
|
577
577
|
principalThreshold: number;
|
|
578
578
|
};
|
|
579
579
|
|
|
@@ -606,6 +606,9 @@ export type ChainConfig = {
|
|
|
606
606
|
address: string;
|
|
607
607
|
bytecode: string;
|
|
608
608
|
};
|
|
609
|
+
EOA_WITHDRAWAL_CONTRACT?: {
|
|
610
|
+
address: string;
|
|
611
|
+
};
|
|
609
612
|
};
|
|
610
613
|
|
|
611
614
|
/**
|
|
@@ -624,3 +627,17 @@ export type OVMRequestWithdrawalPayload = {
|
|
|
624
627
|
/** Array of withdrawal amounts in gwei (uint64) as strings */
|
|
625
628
|
amounts: string[];
|
|
626
629
|
};
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Payload for requesting withdrawal from EOA contract
|
|
633
|
+
*/
|
|
634
|
+
export type EOAWithdrawalPayload = {
|
|
635
|
+
/** Validator public key in hex format */
|
|
636
|
+
pubkey: string;
|
|
637
|
+
|
|
638
|
+
/** Withdrawal amount in ETH */
|
|
639
|
+
allocation: number;
|
|
640
|
+
|
|
641
|
+
/** Required fee in wei */
|
|
642
|
+
requiredFee: string;
|
|
643
|
+
};
|