@obolnetwork/obol-sdk 2.0.1 → 2.1.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.
Files changed (49) hide show
  1. package/README.md +6 -0
  2. package/dist/cjs/package.json +1 -1
  3. package/dist/cjs/src/abi/Multicall.js +148 -0
  4. package/dist/cjs/src/abi/OWR.js +133 -0
  5. package/dist/cjs/src/abi/SplitMain.js +929 -0
  6. package/dist/cjs/src/ajv.js +17 -2
  7. package/dist/cjs/src/bytecodes.js +9 -0
  8. package/dist/cjs/src/constants.js +48 -1
  9. package/dist/cjs/src/index.js +146 -0
  10. package/dist/cjs/src/schema.js +52 -5
  11. package/dist/cjs/src/splitHelpers.js +177 -0
  12. package/dist/cjs/src/utils.js +22 -1
  13. package/dist/cjs/test/fixtures.js +1 -1
  14. package/dist/cjs/test/methods.test.js +215 -11
  15. package/dist/esm/package.json +1 -1
  16. package/dist/esm/src/abi/Multicall.js +145 -0
  17. package/dist/esm/src/abi/OWR.js +130 -0
  18. package/dist/esm/src/abi/SplitMain.js +926 -0
  19. package/dist/esm/src/ajv.js +17 -2
  20. package/dist/esm/src/bytecodes.js +6 -0
  21. package/dist/esm/src/constants.js +47 -0
  22. package/dist/esm/src/index.js +148 -2
  23. package/dist/esm/src/schema.js +51 -4
  24. package/dist/esm/src/splitHelpers.js +168 -0
  25. package/dist/esm/src/utils.js +19 -0
  26. package/dist/esm/test/fixtures.js +1 -1
  27. package/dist/esm/test/methods.test.js +193 -12
  28. package/dist/types/src/abi/Multicall.d.ts +35 -0
  29. package/dist/types/src/abi/OWR.d.ts +52 -0
  30. package/dist/types/src/abi/SplitMain.d.ts +1159 -0
  31. package/dist/types/src/bytecodes.d.ts +6 -0
  32. package/dist/types/src/constants.d.ts +25 -0
  33. package/dist/types/src/index.d.ts +29 -1
  34. package/dist/types/src/schema.d.ts +85 -4
  35. package/dist/types/src/splitHelpers.d.ts +62 -0
  36. package/dist/types/src/types.d.ts +39 -2
  37. package/dist/types/src/utils.d.ts +3 -0
  38. package/package.json +1 -1
  39. package/src/abi/Multicall.ts +145 -0
  40. package/src/abi/OWR.ts +130 -0
  41. package/src/abi/SplitMain.ts +927 -0
  42. package/src/ajv.ts +33 -2
  43. package/src/bytecodes.ts +12 -0
  44. package/src/constants.ts +59 -0
  45. package/src/index.ts +244 -2
  46. package/src/schema.ts +67 -4
  47. package/src/splitHelpers.ts +341 -0
  48. package/src/types.ts +49 -2
  49. package/src/utils.ts +21 -0
@@ -0,0 +1,177 @@
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.multicall = exports.deploySplitterAndOWRContracts = exports.deploySplitterContract = exports.handleDeployOWRAndSplitter = exports.predictSplitterAddress = exports.formatSplitRecipients = void 0;
13
+ const ethers_1 = require("ethers");
14
+ const OWR_1 = require("./abi/OWR");
15
+ const SplitMain_1 = require("./abi/SplitMain");
16
+ const Multicall_1 = require("./abi/Multicall");
17
+ const constants_1 = require("./constants");
18
+ const splitMainContractInterface = new ethers_1.Interface(SplitMain_1.splitMainEthereumAbi);
19
+ const owrFactoryContractInterface = new ethers_1.Interface(OWR_1.OWRFactoryContract.abi);
20
+ const formatSplitRecipients = (recipients) => {
21
+ // Has to be sorted when passed
22
+ recipients.sort((a, b) => a.account.localeCompare(b.account));
23
+ const accounts = recipients.map(item => item.account);
24
+ const percentAllocations = recipients.map(recipient => {
25
+ const splitTostring = (recipient.percentAllocation * 1e4).toFixed(0);
26
+ return parseInt(splitTostring);
27
+ });
28
+ return { accounts, percentAllocations };
29
+ };
30
+ exports.formatSplitRecipients = formatSplitRecipients;
31
+ const predictSplitterAddress = ({ signer, accounts, percentAllocations, chainId, distributorFee, controllerAddress, }) => __awaiter(void 0, void 0, void 0, function* () {
32
+ try {
33
+ let predictedSplitterAddress;
34
+ const splitMainContractInstance = new ethers_1.Contract(constants_1.CHAIN_CONFIGURATION[chainId].SPLITMAIN_ADDRESS.address, SplitMain_1.splitMainEthereumAbi, signer);
35
+ if (controllerAddress === ethers_1.ZeroAddress) {
36
+ predictedSplitterAddress =
37
+ yield splitMainContractInstance.predictImmutableSplitAddress(accounts, percentAllocations, distributorFee);
38
+ }
39
+ else {
40
+ // It throws on deployed Immutable splitter
41
+ predictedSplitterAddress =
42
+ yield splitMainContractInstance.createSplit.staticCall(accounts, percentAllocations, distributorFee, controllerAddress);
43
+ }
44
+ return predictedSplitterAddress;
45
+ }
46
+ catch (e) {
47
+ throw e;
48
+ }
49
+ });
50
+ exports.predictSplitterAddress = predictSplitterAddress;
51
+ const handleDeployOWRAndSplitter = ({ signer, isSplitterDeployed, predictedSplitterAddress, accounts, percentAllocations, etherAmount, principalRecipient, chainId, distributorFee, controllerAddress, recoveryAddress, }) => __awaiter(void 0, void 0, void 0, function* () {
52
+ try {
53
+ if (isSplitterDeployed) {
54
+ const owrAddress = yield createOWRContract({
55
+ owrArgs: {
56
+ principalRecipient,
57
+ amountOfPrincipalStake: etherAmount,
58
+ predictedSplitterAddress,
59
+ recoveryAddress,
60
+ },
61
+ signer,
62
+ chainId,
63
+ });
64
+ return {
65
+ withdrawal_address: owrAddress,
66
+ fee_recipient_address: predictedSplitterAddress,
67
+ };
68
+ }
69
+ else {
70
+ const { owrAddress, splitterAddress } = yield (0, exports.deploySplitterAndOWRContracts)({
71
+ owrArgs: {
72
+ principalRecipient,
73
+ amountOfPrincipalStake: etherAmount,
74
+ predictedSplitterAddress,
75
+ recoveryAddress,
76
+ },
77
+ splitterArgs: {
78
+ accounts,
79
+ percentAllocations,
80
+ distributorFee,
81
+ controllerAddress,
82
+ },
83
+ signer,
84
+ chainId,
85
+ });
86
+ return {
87
+ withdrawal_address: owrAddress,
88
+ fee_recipient_address: splitterAddress,
89
+ };
90
+ }
91
+ }
92
+ catch (e) {
93
+ throw e;
94
+ }
95
+ });
96
+ exports.handleDeployOWRAndSplitter = handleDeployOWRAndSplitter;
97
+ const createOWRContract = ({ owrArgs, signer, chainId, }) => __awaiter(void 0, void 0, void 0, function* () {
98
+ var _a;
99
+ try {
100
+ const OWRFactoryInstance = new ethers_1.Contract(constants_1.CHAIN_CONFIGURATION[chainId].OWR_FACTORY_ADDRESS.address, OWR_1.OWRFactoryContract.abi, signer);
101
+ const tx = yield OWRFactoryInstance.createOWRecipient(owrArgs.recoveryAddress, owrArgs.principalRecipient, owrArgs.predictedSplitterAddress, (0, ethers_1.parseEther)(owrArgs.amountOfPrincipalStake.toString()));
102
+ const receipt = yield tx.wait();
103
+ const OWRAddressData = (_a = receipt === null || receipt === void 0 ? void 0 : receipt.logs[0]) === null || _a === void 0 ? void 0 : _a.topics[1];
104
+ const formattedOWRAddress = '0x' + (OWRAddressData === null || OWRAddressData === void 0 ? void 0 : OWRAddressData.slice(26, 66));
105
+ return formattedOWRAddress;
106
+ }
107
+ catch (e) {
108
+ throw e;
109
+ }
110
+ });
111
+ const deploySplitterContract = ({ signer, accounts, percentAllocations, chainId, distributorFee, controllerAddress, }) => __awaiter(void 0, void 0, void 0, function* () {
112
+ var _b;
113
+ try {
114
+ const splitMainContractInstance = new ethers_1.Contract(constants_1.CHAIN_CONFIGURATION[chainId].SPLITMAIN_ADDRESS.address, SplitMain_1.splitMainEthereumAbi, signer);
115
+ const tx = yield splitMainContractInstance.createSplit(accounts, percentAllocations, distributorFee, controllerAddress);
116
+ const receipt = yield tx.wait();
117
+ const splitterAddressData = (_b = receipt === null || receipt === void 0 ? void 0 : receipt.logs[0]) === null || _b === void 0 ? void 0 : _b.topics[1];
118
+ const formattedSplitterAddress = '0x' + (splitterAddressData === null || splitterAddressData === void 0 ? void 0 : splitterAddressData.slice(26, 66));
119
+ return formattedSplitterAddress;
120
+ }
121
+ catch (e) {
122
+ throw e;
123
+ }
124
+ });
125
+ exports.deploySplitterContract = deploySplitterContract;
126
+ const deploySplitterAndOWRContracts = ({ owrArgs, splitterArgs, signer, chainId, }) => __awaiter(void 0, void 0, void 0, function* () {
127
+ var _c, _d;
128
+ const executeCalls = [];
129
+ try {
130
+ const splitTxData = encodeCreateSplitTxData(splitterArgs.accounts, splitterArgs.percentAllocations, splitterArgs.distributorFee, splitterArgs.controllerAddress);
131
+ const owrTxData = encodeCreateOWRecipientTxData(owrArgs.recoveryAddress, owrArgs.principalRecipient, owrArgs.predictedSplitterAddress, owrArgs.amountOfPrincipalStake);
132
+ executeCalls.push({
133
+ target: constants_1.CHAIN_CONFIGURATION[chainId].SPLITMAIN_ADDRESS.address,
134
+ callData: splitTxData,
135
+ }, {
136
+ target: constants_1.CHAIN_CONFIGURATION[chainId].OWR_FACTORY_ADDRESS.address,
137
+ callData: owrTxData,
138
+ });
139
+ const multicallAddess = constants_1.CHAIN_CONFIGURATION[chainId].MULTICALL_ADDRESS.address;
140
+ const executeMultiCalls = yield (0, exports.multicall)(executeCalls, signer, multicallAddess);
141
+ const splitAddressData = (_c = executeMultiCalls === null || executeMultiCalls === void 0 ? void 0 : executeMultiCalls.logs[0]) === null || _c === void 0 ? void 0 : _c.topics[1];
142
+ const formattedSplitterAddress = '0x' + (splitAddressData === null || splitAddressData === void 0 ? void 0 : splitAddressData.slice(26, 66));
143
+ const owrAddressData = (_d = executeMultiCalls === null || executeMultiCalls === void 0 ? void 0 : executeMultiCalls.logs[1]) === null || _d === void 0 ? void 0 : _d.topics[1];
144
+ const formattedOwrAddress = '0x' + (owrAddressData === null || owrAddressData === void 0 ? void 0 : owrAddressData.slice(26, 66));
145
+ return {
146
+ owrAddress: formattedOwrAddress,
147
+ splitterAddress: formattedSplitterAddress,
148
+ };
149
+ }
150
+ catch (e) {
151
+ throw e;
152
+ }
153
+ });
154
+ exports.deploySplitterAndOWRContracts = deploySplitterAndOWRContracts;
155
+ const multicall = (calls, signer, multicallAddress) => __awaiter(void 0, void 0, void 0, function* () {
156
+ const multiCallContractInstance = new ethers_1.Contract(multicallAddress, Multicall_1.MultiCallContract.abi, signer);
157
+ const tx = yield multiCallContractInstance.aggregate(calls);
158
+ const receipt = yield tx.wait();
159
+ return receipt;
160
+ });
161
+ exports.multicall = multicall;
162
+ const encodeCreateSplitTxData = (accounts, percentAllocations, distributorFee, controller) => {
163
+ return splitMainContractInterface.encodeFunctionData('createSplit', [
164
+ accounts,
165
+ percentAllocations,
166
+ distributorFee,
167
+ controller,
168
+ ]);
169
+ };
170
+ const encodeCreateOWRecipientTxData = (recoveryAddress, principalRecipient, rewardRecipient, amountOfPrincipalStake) => {
171
+ return owrFactoryContractInterface.encodeFunctionData('createOWRecipient', [
172
+ recoveryAddress,
173
+ principalRecipient,
174
+ rewardRecipient,
175
+ (0, ethers_1.parseEther)(amountOfPrincipalStake.toString()),
176
+ ]);
177
+ };
@@ -1,6 +1,15 @@
1
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
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.definitionFlow = exports.strToUint8Array = exports.hexWithout0x = void 0;
12
+ exports.isContractAvailable = exports.findDeployedBytecode = exports.definitionFlow = exports.strToUint8Array = exports.hexWithout0x = void 0;
4
13
  const constants_1 = require("./constants");
5
14
  const hexWithout0x = (hex) => {
6
15
  return hex.slice(2, hex.length);
@@ -44,3 +53,15 @@ const definitionFlow = (clusterDefinition) => {
44
53
  return null;
45
54
  };
46
55
  exports.definitionFlow = definitionFlow;
56
+ const findDeployedBytecode = (contractAddress, provider) => __awaiter(void 0, void 0, void 0, function* () {
57
+ return yield (provider === null || provider === void 0 ? void 0 : provider.getCode(contractAddress));
58
+ });
59
+ exports.findDeployedBytecode = findDeployedBytecode;
60
+ const isContractAvailable = (contractAddress, provider, bytecode) => __awaiter(void 0, void 0, void 0, function* () {
61
+ const code = yield (0, exports.findDeployedBytecode)(contractAddress, provider);
62
+ if (bytecode) {
63
+ return !!code && code === bytecode;
64
+ }
65
+ return !!code && code !== '0x' && code !== '0x0';
66
+ });
67
+ exports.isContractAvailable = isContractAvailable;
@@ -179,7 +179,7 @@ exports.clusterConfigV1X8 = {
179
179
  { address: '0xC35CfCd67b9C27345a54EDEcC1033F2284148c81' },
180
180
  { address: '0x33807D6F1DCe44b9C599fFE03640762A6F08C496' },
181
181
  { address: '0xc6e76F72Ea672FAe05C357157CfC37720F0aF26f' },
182
- { address: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC' },
182
+ { address: '0xf6fF1a7A14D01e86a175bA958d3B6C75f2213966' },
183
183
  ],
184
184
  validators: [
185
185
  {
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
26
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
27
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -18,22 +41,18 @@ const ajv_1 = require("../src/ajv");
18
41
  const msw_1 = require("msw");
19
42
  const node_1 = require("msw/node");
20
43
  const termsAndConditions_1 = require("../src/verification/termsAndConditions");
44
+ const utils = __importStar(require("../src/utils"));
45
+ const splitsHelpers = __importStar(require("../src/splitHelpers"));
21
46
  /* eslint no-new: 0 */
22
47
  describe('Cluster Client', () => {
23
48
  var _a, _b;
24
49
  const mockConfigHash = '0x1f6c94e6c070393a68c1aa6073a21cb1fd57f0e14d2a475a2958990ab728c2fd';
25
50
  const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
26
51
  const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
27
- const wallet = new ethers_1.ethers.Wallet(privateKey);
28
- const mockSigner = wallet.connect(null);
29
- const clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 5 }, mockSigner);
30
- // test('throws invalid ChainId when it is equal to 1', async () => {
31
- // try {
32
- // new Client({ chainId: 1 }, mockSigner)
33
- // } catch (error: any) {
34
- // expect(error.message).toBe('Obol-SDK is in Beta phase, mainnet is not yet supported')
35
- // }
36
- // })
52
+ const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
53
+ const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
54
+ const mockSigner = wallet.connect(provider);
55
+ const clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
37
56
  test('createTermsAndConditions should return "successful authorization"', () => __awaiter(void 0, void 0, void 0, function* () {
38
57
  clientInstance['request'] = jest
39
58
  .fn()
@@ -140,7 +159,7 @@ describe('Cluster Client', () => {
140
159
  describe('Cluster Client without a signer', () => {
141
160
  const clientInstance = new index_1.Client({
142
161
  baseUrl: 'https://obol-api-dev.gcp.obol.tech',
143
- chainId: 5,
162
+ chainId: 17000,
144
163
  });
145
164
  test('createClusterDefinition should throw an error without signer', () => __awaiter(void 0, void 0, void 0, function* () {
146
165
  try {
@@ -200,3 +219,188 @@ describe('Cluster Client without a signer', () => {
200
219
  expect(termsAndConditionsHash).toEqual('0xd33721644e8f3afab1495a74abe3523cec12d48b8da6cb760972492ca3f1a273');
201
220
  }));
202
221
  });
222
+ describe('createObolRewardsSplit', () => {
223
+ var _a, _b;
224
+ jest
225
+ .spyOn(utils, 'isContractAvailable')
226
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
227
+ jest
228
+ .spyOn(splitsHelpers, 'predictSplitterAddress')
229
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve('0xPredictedAddress'); }));
230
+ jest.spyOn(splitsHelpers, 'handleDeployOWRAndSplitter').mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
231
+ return yield Promise.resolve({
232
+ withdrawal_address: '0xWithdrawalAddress',
233
+ fee_recipient_address: '0xFeeRecipientAddress',
234
+ });
235
+ }));
236
+ const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
237
+ const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
238
+ const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
239
+ const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
240
+ const mockSigner = wallet.connect(provider);
241
+ const clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
242
+ const clientInstanceWithourSigner = new index_1.Client({
243
+ baseUrl: 'https://obol-api-dev.gcp.obol.tech',
244
+ chainId: 17000,
245
+ });
246
+ const mockSplitRecipients = [
247
+ {
248
+ account: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC',
249
+ percentAllocation: 99,
250
+ },
251
+ ];
252
+ const mockPrincipalRecipient = '0x86B8145c98e5BD25BA722645b15eD65f024a87EC';
253
+ const mockEtherAmount = 64;
254
+ it('should throw an error if signer is not defined', () => __awaiter(void 0, void 0, void 0, function* () {
255
+ yield expect(clientInstanceWithourSigner.createObolRewardsSplit({
256
+ splitRecipients: mockSplitRecipients,
257
+ principalRecipient: mockPrincipalRecipient,
258
+ etherAmount: mockEtherAmount,
259
+ })).rejects.toThrow('Signer is required in createObolRewardsSplit');
260
+ }));
261
+ it('should throw an error if chainId is not supported', () => __awaiter(void 0, void 0, void 0, function* () {
262
+ const unsupportedSplitterChainClient = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 100 }, mockSigner);
263
+ try {
264
+ yield unsupportedSplitterChainClient.createObolRewardsSplit({
265
+ splitRecipients: mockSplitRecipients,
266
+ principalRecipient: mockPrincipalRecipient,
267
+ etherAmount: mockEtherAmount,
268
+ });
269
+ }
270
+ catch (error) {
271
+ expect(error.message).toEqual('Splitter configuration is not supported on 100 chain');
272
+ }
273
+ }));
274
+ test('should throw an error on invalid recipients', () => __awaiter(void 0, void 0, void 0, function* () {
275
+ try {
276
+ yield clientInstance.createObolRewardsSplit({
277
+ splitRecipients: [
278
+ {
279
+ account: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC',
280
+ percentAllocation: 22,
281
+ },
282
+ ],
283
+ principalRecipient: mockPrincipalRecipient,
284
+ etherAmount: mockEtherAmount,
285
+ });
286
+ }
287
+ catch (error) {
288
+ expect(error.message).toEqual('Schema compilation errors\', must pass "validateSplitRecipients" keyword validation');
289
+ }
290
+ }));
291
+ test('should throw an error if ObolRAFSplit is less than 1', () => __awaiter(void 0, void 0, void 0, function* () {
292
+ try {
293
+ yield clientInstance.createObolRewardsSplit({
294
+ splitRecipients: mockSplitRecipients,
295
+ principalRecipient: mockPrincipalRecipient,
296
+ etherAmount: mockEtherAmount,
297
+ ObolRAFSplit: 0.5,
298
+ });
299
+ }
300
+ catch (error) {
301
+ expect(error.message).toEqual("Schema compilation errors', must be >= 1");
302
+ }
303
+ }));
304
+ it('should return the correct withdrawal and fee recipient addresses', () => __awaiter(void 0, void 0, void 0, function* () {
305
+ const result = yield clientInstance.createObolRewardsSplit({
306
+ splitRecipients: mockSplitRecipients,
307
+ principalRecipient: mockPrincipalRecipient,
308
+ etherAmount: mockEtherAmount,
309
+ });
310
+ expect(result).toEqual({
311
+ withdrawal_address: '0xWithdrawalAddress',
312
+ fee_recipient_address: '0xFeeRecipientAddress',
313
+ });
314
+ }));
315
+ });
316
+ describe('createObolTotalSplit', () => {
317
+ var _a, _b;
318
+ jest
319
+ .spyOn(utils, 'isContractAvailable')
320
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
321
+ jest
322
+ .spyOn(splitsHelpers, 'predictSplitterAddress')
323
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve('0xPredictedAddress'); }));
324
+ jest
325
+ .spyOn(splitsHelpers, 'deploySplitterContract')
326
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve('0xSplitterAddress'); }));
327
+ const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
328
+ const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
329
+ const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
330
+ const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
331
+ const mockSigner = wallet.connect(provider);
332
+ const clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
333
+ const clientInstanceWithourSigner = new index_1.Client({
334
+ baseUrl: 'https://obol-api-dev.gcp.obol.tech',
335
+ chainId: 17000,
336
+ });
337
+ const mockSplitRecipients = [
338
+ {
339
+ account: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC',
340
+ percentAllocation: 99.9,
341
+ },
342
+ ];
343
+ it('should throw an error if signer is not defined', () => __awaiter(void 0, void 0, void 0, function* () {
344
+ yield expect(clientInstanceWithourSigner.createObolTotalSplit({
345
+ splitRecipients: mockSplitRecipients,
346
+ })).rejects.toThrow('Signer is required in createObolTotalSplit');
347
+ }));
348
+ it('should throw an error if chainId is not supported', () => __awaiter(void 0, void 0, void 0, function* () {
349
+ const unsupportedSplitterChainClient = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 100 }, mockSigner);
350
+ try {
351
+ yield unsupportedSplitterChainClient.createObolTotalSplit({
352
+ splitRecipients: mockSplitRecipients,
353
+ });
354
+ }
355
+ catch (error) {
356
+ expect(error.message).toEqual('Splitter configuration is not supported on 100 chain');
357
+ }
358
+ }));
359
+ test('should throw an error on invalid recipients', () => __awaiter(void 0, void 0, void 0, function* () {
360
+ try {
361
+ yield clientInstance.createObolTotalSplit({
362
+ splitRecipients: [
363
+ {
364
+ account: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC',
365
+ percentAllocation: 22,
366
+ },
367
+ ],
368
+ });
369
+ }
370
+ catch (error) {
371
+ expect(error.message).toEqual('Schema compilation errors\', must pass "validateSplitRecipients" keyword validation');
372
+ }
373
+ }));
374
+ test('should throw an error if ObolRAFSplit is less than 0.1', () => __awaiter(void 0, void 0, void 0, function* () {
375
+ try {
376
+ yield clientInstance.createObolTotalSplit({
377
+ splitRecipients: mockSplitRecipients,
378
+ ObolRAFSplit: 0.05,
379
+ });
380
+ }
381
+ catch (error) {
382
+ expect(error.message).toEqual("Schema compilation errors', must be >= 0.1");
383
+ }
384
+ }));
385
+ it('should return the correct withdrawal and fee recipient addresses and ObolRAFSplit', () => __awaiter(void 0, void 0, void 0, function* () {
386
+ const result = yield clientInstance.createObolTotalSplit({
387
+ splitRecipients: mockSplitRecipients,
388
+ ObolRAFSplit: 0.5,
389
+ });
390
+ // 0xPredictedAddress and not 0xSplitterAddress since were mocking isContractAvailable response to be true
391
+ expect(result).toEqual({
392
+ withdrawal_address: '0xPredictedAddress',
393
+ fee_recipient_address: '0xPredictedAddress',
394
+ });
395
+ }));
396
+ it('should return the correct withdrawal and fee recipient addresses without passing ObolRAFSplit', () => __awaiter(void 0, void 0, void 0, function* () {
397
+ const result = yield clientInstance.createObolTotalSplit({
398
+ splitRecipients: mockSplitRecipients,
399
+ });
400
+ // 0xPredictedAddress and not 0xSplitterAddress since were mocking isContractAvailable response to be true
401
+ expect(result).toEqual({
402
+ withdrawal_address: '0xPredictedAddress',
403
+ fee_recipient_address: '0xPredictedAddress',
404
+ });
405
+ }));
406
+ });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obolnetwork/obol-sdk",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
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"
@@ -0,0 +1,145 @@
1
+ export const MultiCallContract = {
2
+ abi: [
3
+ {
4
+ constant: true,
5
+ inputs: [],
6
+ name: 'getCurrentBlockTimestamp',
7
+ outputs: [
8
+ {
9
+ name: 'timestamp',
10
+ type: 'uint256',
11
+ },
12
+ ],
13
+ payable: false,
14
+ stateMutability: 'view',
15
+ type: 'function',
16
+ },
17
+ {
18
+ constant: false,
19
+ inputs: [
20
+ {
21
+ components: [
22
+ {
23
+ name: 'target',
24
+ type: 'address',
25
+ },
26
+ {
27
+ name: 'callData',
28
+ type: 'bytes',
29
+ },
30
+ ],
31
+ name: 'calls',
32
+ type: 'tuple[]',
33
+ },
34
+ ],
35
+ name: 'aggregate',
36
+ outputs: [
37
+ {
38
+ name: 'blockNumber',
39
+ type: 'uint256',
40
+ },
41
+ {
42
+ name: 'returnData',
43
+ type: 'bytes[]',
44
+ },
45
+ ],
46
+ payable: false,
47
+ stateMutability: 'nonpayable',
48
+ type: 'function',
49
+ },
50
+ {
51
+ constant: true,
52
+ inputs: [],
53
+ name: 'getLastBlockHash',
54
+ outputs: [
55
+ {
56
+ name: 'blockHash',
57
+ type: 'bytes32',
58
+ },
59
+ ],
60
+ payable: false,
61
+ stateMutability: 'view',
62
+ type: 'function',
63
+ },
64
+ {
65
+ constant: true,
66
+ inputs: [
67
+ {
68
+ name: 'addr',
69
+ type: 'address',
70
+ },
71
+ ],
72
+ name: 'getEthBalance',
73
+ outputs: [
74
+ {
75
+ name: 'balance',
76
+ type: 'uint256',
77
+ },
78
+ ],
79
+ payable: false,
80
+ stateMutability: 'view',
81
+ type: 'function',
82
+ },
83
+ {
84
+ constant: true,
85
+ inputs: [],
86
+ name: 'getCurrentBlockDifficulty',
87
+ outputs: [
88
+ {
89
+ name: 'difficulty',
90
+ type: 'uint256',
91
+ },
92
+ ],
93
+ payable: false,
94
+ stateMutability: 'view',
95
+ type: 'function',
96
+ },
97
+ {
98
+ constant: true,
99
+ inputs: [],
100
+ name: 'getCurrentBlockGasLimit',
101
+ outputs: [
102
+ {
103
+ name: 'gaslimit',
104
+ type: 'uint256',
105
+ },
106
+ ],
107
+ payable: false,
108
+ stateMutability: 'view',
109
+ type: 'function',
110
+ },
111
+ {
112
+ constant: true,
113
+ inputs: [],
114
+ name: 'getCurrentBlockCoinbase',
115
+ outputs: [
116
+ {
117
+ name: 'coinbase',
118
+ type: 'address',
119
+ },
120
+ ],
121
+ payable: false,
122
+ stateMutability: 'view',
123
+ type: 'function',
124
+ },
125
+ {
126
+ constant: true,
127
+ inputs: [
128
+ {
129
+ name: 'blockNumber',
130
+ type: 'uint256',
131
+ },
132
+ ],
133
+ name: 'getBlockHash',
134
+ outputs: [
135
+ {
136
+ name: 'blockHash',
137
+ type: 'bytes32',
138
+ },
139
+ ],
140
+ payable: false,
141
+ stateMutability: 'view',
142
+ type: 'function',
143
+ },
144
+ ],
145
+ };