@obolnetwork/obol-sdk 2.8.0 → 2.9.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 +2 -4
- package/dist/cjs/src/abi/splitV2FactoryAbi.js +420 -0
- package/dist/cjs/src/ajv.js +24 -0
- package/dist/cjs/src/bytecodes.js +3 -1
- package/dist/cjs/src/constants.js +24 -16
- package/dist/cjs/src/index.js +10 -10
- package/dist/cjs/src/schema.js +29 -3
- package/dist/cjs/src/splits/splitHelpers.js +100 -109
- package/dist/cjs/src/splits/splits.js +77 -16
- package/dist/cjs/test/client/ajv.spec.js +32 -0
- package/dist/cjs/test/splits/splits.spec.js +76 -2
- package/dist/esm/package.json +2 -4
- package/dist/esm/src/abi/splitV2FactoryAbi.js +417 -0
- package/dist/esm/src/ajv.js +24 -0
- package/dist/esm/src/bytecodes.js +2 -0
- package/dist/esm/src/constants.js +25 -17
- package/dist/esm/src/index.js +10 -10
- package/dist/esm/src/schema.js +28 -2
- package/dist/esm/src/splits/splitHelpers.js +101 -110
- package/dist/esm/src/splits/splits.js +79 -18
- package/dist/esm/test/client/ajv.spec.js +33 -1
- package/dist/esm/test/splits/splits.spec.js +77 -3
- package/dist/types/src/abi/splitV2FactoryAbi.d.ts +60 -0
- package/dist/types/src/bytecodes.d.ts +2 -0
- package/dist/types/src/exits/verificationHelpers.d.ts +1 -0
- package/dist/types/src/schema.d.ts +30 -3
- package/dist/types/src/splits/splitHelpers.d.ts +17 -3
- package/dist/types/src/splits/splits.d.ts +28 -1
- package/dist/types/src/types.d.ts +21 -6
- package/dist/types/src/verification/common.d.ts +1 -0
- package/package.json +2 -4
- package/src/abi/splitV2FactoryAbi.ts +417 -0
- package/src/ajv.ts +33 -0
- package/src/bytecodes.ts +4 -0
- package/src/constants.ts +26 -16
- package/src/index.ts +14 -14
- package/src/schema.ts +29 -2
- package/src/splits/splitHelpers.ts +169 -124
- package/src/splits/splits.ts +115 -17
- package/src/types.ts +24 -6
package/src/constants.ts
CHANGED
|
@@ -9,11 +9,13 @@ import {
|
|
|
9
9
|
HOODI_MULTICALL_BYTECODE,
|
|
10
10
|
HOODI_OVM_FACTORY_BYTECODE,
|
|
11
11
|
HOODI_OWR_FACTORY_BYTECODE,
|
|
12
|
+
HOODI_SPLIT_V2_FACTORY_BYTECODE,
|
|
12
13
|
HOODI_SPLITMAIN_BYTECODE,
|
|
13
14
|
HOODI_WAREHOUSE_BYTECODE,
|
|
14
15
|
MAINNET_MULTICALL_BYTECODE,
|
|
15
16
|
MAINNET_OVM_FACTORY_BYTECODE,
|
|
16
17
|
MAINNET_OWR_FACTORY_BYTECODE,
|
|
18
|
+
MAINNET_SPLIT_V2_FACTORY_BYTECODE,
|
|
17
19
|
MAINNET_SPLITMAIN_BYTECODE,
|
|
18
20
|
MAINNET_WAREHOUSE_BYTECODE,
|
|
19
21
|
} from './bytecodes';
|
|
@@ -168,76 +170,84 @@ export const isChainSupportedForSplitters = (chainId: number): boolean => {
|
|
|
168
170
|
|
|
169
171
|
export const CHAIN_CONFIGURATION: Record<number, ChainConfig> = {
|
|
170
172
|
[FORK_MAPPING['0x00000000']]: {
|
|
171
|
-
|
|
173
|
+
SPLITMAIN_CONTRACT: {
|
|
172
174
|
address: '0x2ed6c4B5dA6378c7897AC67Ba9e43102Feb694EE',
|
|
173
175
|
bytecode: MAINNET_SPLITMAIN_BYTECODE,
|
|
174
176
|
},
|
|
175
|
-
|
|
177
|
+
MULTICALL_CONTRACT: {
|
|
176
178
|
address: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
|
|
177
179
|
bytecode: MAINNET_MULTICALL_BYTECODE,
|
|
178
180
|
},
|
|
179
|
-
|
|
181
|
+
OWR_FACTORY_CONTRACT: {
|
|
180
182
|
address: '0x119acd7844cbdd5fc09b1c6a4408f490c8f7f522',
|
|
181
183
|
bytecode: MAINNET_OWR_FACTORY_BYTECODE,
|
|
182
184
|
},
|
|
183
|
-
|
|
185
|
+
RETROACTIVE_FUNDING_CONTRACT: {
|
|
184
186
|
address: '0xDe5aE4De36c966747Ea7DF13BD9589642e2B1D0d',
|
|
185
187
|
bytecode: '',
|
|
186
188
|
},
|
|
187
189
|
// OVM and SplitV2 Contract Addresses
|
|
188
|
-
|
|
190
|
+
OVM_FACTORY_CONTRACT: {
|
|
189
191
|
address: '0xdfe2d8b26806583cf03b3cb623b0752f8670e93e',
|
|
190
192
|
bytecode: MAINNET_OVM_FACTORY_BYTECODE,
|
|
191
193
|
},
|
|
192
|
-
|
|
194
|
+
WAREHOUSE_CONTRACT: {
|
|
193
195
|
address: '0x8fb66F38cF86A3d5e8768f8F1754A24A6c661Fb8',
|
|
194
196
|
bytecode: MAINNET_WAREHOUSE_BYTECODE,
|
|
195
197
|
},
|
|
198
|
+
SPLIT_V2_FACTORY_CONTRACT: {
|
|
199
|
+
address: '0x5cbA88D55Cec83caD5A105Ad40C8c9aF20bE21d1',
|
|
200
|
+
bytecode: MAINNET_SPLIT_V2_FACTORY_BYTECODE,
|
|
201
|
+
},
|
|
196
202
|
},
|
|
197
203
|
[FORK_MAPPING['0x01017000']]: {
|
|
198
|
-
|
|
204
|
+
SPLITMAIN_CONTRACT: {
|
|
199
205
|
address: '0xfC8a305728051367797DADE6Aa0344E0987f5286',
|
|
200
206
|
bytecode: HOLESKY_SPLITMAIN_BYTECODE,
|
|
201
207
|
},
|
|
202
|
-
|
|
208
|
+
MULTICALL_CONTRACT: {
|
|
203
209
|
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
204
210
|
bytecode: HOLESKY_MULTICALL_BYTECODE,
|
|
205
211
|
},
|
|
206
|
-
|
|
212
|
+
OWR_FACTORY_CONTRACT: {
|
|
207
213
|
address: '0xc0961353fcc43a99e3041db07ac646720e116256',
|
|
208
214
|
bytecode: HOLESKY_OWR_FACTORY_BYTECODE,
|
|
209
215
|
},
|
|
210
|
-
|
|
216
|
+
RETROACTIVE_FUNDING_CONTRACT: {
|
|
211
217
|
address: '0x43F641fA70e09f0326ac66b4Ef0C416EaEcBC6f5',
|
|
212
218
|
bytecode: '',
|
|
213
219
|
},
|
|
214
220
|
},
|
|
215
221
|
[FORK_MAPPING['0x10000910']]: {
|
|
216
|
-
|
|
222
|
+
SPLITMAIN_CONTRACT: {
|
|
217
223
|
address: '0xc05ae267291705ac16F75283572294ed2a91CBc7',
|
|
218
224
|
bytecode: HOODI_SPLITMAIN_BYTECODE,
|
|
219
225
|
},
|
|
220
|
-
|
|
226
|
+
MULTICALL_CONTRACT: {
|
|
221
227
|
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
222
228
|
bytecode: HOODI_MULTICALL_BYTECODE,
|
|
223
229
|
},
|
|
224
|
-
|
|
230
|
+
OWR_FACTORY_CONTRACT: {
|
|
225
231
|
address: '0x9ff0c649d0bf5fe7efa4d72e94bed7302ed5c8d7',
|
|
226
232
|
bytecode: HOODI_OWR_FACTORY_BYTECODE,
|
|
227
233
|
},
|
|
228
|
-
|
|
234
|
+
RETROACTIVE_FUNDING_CONTRACT: {
|
|
229
235
|
address: '0x43F641fA70e09f0326ac66b4Ef0C416EaEcBC6f5',
|
|
230
236
|
bytecode: '',
|
|
231
237
|
},
|
|
232
238
|
// OVM and SplitV2 Contract Addresses
|
|
233
|
-
|
|
239
|
+
OVM_FACTORY_CONTRACT: {
|
|
234
240
|
address: '0x6F13d929C783a420AE4DC71C1dcc27A02038Ed09',
|
|
235
241
|
bytecode: HOODI_OVM_FACTORY_BYTECODE,
|
|
236
242
|
},
|
|
237
|
-
|
|
243
|
+
WAREHOUSE_CONTRACT: {
|
|
238
244
|
address: '0x8fb66F38cF86A3d5e8768f8F1754A24A6c661Fb8',
|
|
239
245
|
bytecode: HOODI_WAREHOUSE_BYTECODE,
|
|
240
246
|
},
|
|
247
|
+
SPLIT_V2_FACTORY_CONTRACT: {
|
|
248
|
+
address: '0x5cbA88D55Cec83caD5A105Ad40C8c9aF20bE21d1',
|
|
249
|
+
bytecode: HOODI_SPLIT_V2_FACTORY_BYTECODE,
|
|
250
|
+
},
|
|
241
251
|
},
|
|
242
252
|
};
|
|
243
253
|
|
package/src/index.ts
CHANGED
|
@@ -221,28 +221,28 @@ export class Client extends Base {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
const chainConfig = CHAIN_CONFIGURATION[this.chainId];
|
|
224
|
-
if (!chainConfig?.
|
|
224
|
+
if (!chainConfig?.SPLITMAIN_CONTRACT) {
|
|
225
225
|
throw new Error(
|
|
226
|
-
`
|
|
226
|
+
`SPLITMAIN_CONTRACT is not configured for chain ${this.chainId}`,
|
|
227
227
|
);
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
const checkSplitMainAddress = await isContractAvailable(
|
|
231
|
-
chainConfig.
|
|
231
|
+
chainConfig.SPLITMAIN_CONTRACT.address,
|
|
232
232
|
this.signer.provider as ProviderType,
|
|
233
|
-
chainConfig.
|
|
233
|
+
chainConfig.SPLITMAIN_CONTRACT.bytecode,
|
|
234
234
|
);
|
|
235
235
|
|
|
236
236
|
const checkMulticallAddress = await isContractAvailable(
|
|
237
|
-
chainConfig.
|
|
237
|
+
chainConfig.MULTICALL_CONTRACT.address,
|
|
238
238
|
this.signer.provider as ProviderType,
|
|
239
|
-
chainConfig.
|
|
239
|
+
chainConfig.MULTICALL_CONTRACT.bytecode,
|
|
240
240
|
);
|
|
241
241
|
|
|
242
242
|
const checkOWRFactoryAddress = await isContractAvailable(
|
|
243
|
-
chainConfig.
|
|
243
|
+
chainConfig.OWR_FACTORY_CONTRACT.address,
|
|
244
244
|
this.signer.provider as ProviderType,
|
|
245
|
-
chainConfig.
|
|
245
|
+
chainConfig.OWR_FACTORY_CONTRACT.bytecode,
|
|
246
246
|
);
|
|
247
247
|
|
|
248
248
|
if (
|
|
@@ -256,7 +256,7 @@ export class Client extends Base {
|
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
const retroActiveFundingRecipient = {
|
|
259
|
-
account: chainConfig.
|
|
259
|
+
account: chainConfig.RETROACTIVE_FUNDING_CONTRACT.address,
|
|
260
260
|
percentAllocation: validatedPayload.ObolRAFSplit,
|
|
261
261
|
};
|
|
262
262
|
|
|
@@ -342,16 +342,16 @@ export class Client extends Base {
|
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
const chainConfig = CHAIN_CONFIGURATION[this.chainId];
|
|
345
|
-
if (!chainConfig?.
|
|
345
|
+
if (!chainConfig?.SPLITMAIN_CONTRACT) {
|
|
346
346
|
throw new Error(
|
|
347
|
-
`
|
|
347
|
+
`SPLITMAIN_CONTRACT is not configured for chain ${this.chainId}`,
|
|
348
348
|
);
|
|
349
349
|
}
|
|
350
350
|
|
|
351
351
|
const checkSplitMainAddress = await isContractAvailable(
|
|
352
|
-
chainConfig.
|
|
352
|
+
chainConfig.SPLITMAIN_CONTRACT.address,
|
|
353
353
|
this.signer.provider as ProviderType,
|
|
354
|
-
chainConfig.
|
|
354
|
+
chainConfig.SPLITMAIN_CONTRACT.bytecode,
|
|
355
355
|
);
|
|
356
356
|
|
|
357
357
|
if (!checkSplitMainAddress) {
|
|
@@ -361,7 +361,7 @@ export class Client extends Base {
|
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
const retroActiveFundingRecipient = {
|
|
364
|
-
account: chainConfig.
|
|
364
|
+
account: chainConfig.RETROACTIVE_FUNDING_CONTRACT.address,
|
|
365
365
|
percentAllocation: validatedPayload.ObolRAFSplit,
|
|
366
366
|
};
|
|
367
367
|
|
package/src/schema.ts
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
PRINCIPAL_THRESHOLD,
|
|
6
6
|
} from './constants';
|
|
7
7
|
import { VALID_DEPOSIT_AMOUNTS, VALID_NON_COMPOUNDING_AMOUNTS } from './ajv';
|
|
8
|
-
import { zeroAddress } from 'viem';
|
|
9
8
|
|
|
10
9
|
export const operatorPayloadSchema = {
|
|
11
10
|
type: 'object',
|
|
@@ -175,7 +174,7 @@ export const ovmBaseSplitPayload = {
|
|
|
175
174
|
splitOwnerAddress: {
|
|
176
175
|
type: 'string',
|
|
177
176
|
pattern: '^0x[a-fA-F0-9]{40}$',
|
|
178
|
-
default:
|
|
177
|
+
default: ZeroAddress,
|
|
179
178
|
},
|
|
180
179
|
principalThreshold: {
|
|
181
180
|
type: 'number',
|
|
@@ -230,3 +229,31 @@ export const ovmTotalSplitPayloadSchema = {
|
|
|
230
229
|
'OVMOwnerAddress',
|
|
231
230
|
],
|
|
232
231
|
};
|
|
232
|
+
|
|
233
|
+
export const ovmRequestWithdrawalPayloadSchema = {
|
|
234
|
+
type: 'object',
|
|
235
|
+
properties: {
|
|
236
|
+
ovmAddress: {
|
|
237
|
+
type: 'string',
|
|
238
|
+
pattern: '^0x[a-fA-F0-9]{40}$',
|
|
239
|
+
},
|
|
240
|
+
pubKeys: {
|
|
241
|
+
type: 'array',
|
|
242
|
+
minItems: 1,
|
|
243
|
+
items: {
|
|
244
|
+
type: 'string',
|
|
245
|
+
pattern: '^0x[a-fA-F0-9]{96}$', // 48 bytes = 96 hex chars + 0x prefix
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
amounts: {
|
|
249
|
+
type: 'array',
|
|
250
|
+
minItems: 1,
|
|
251
|
+
items: {
|
|
252
|
+
type: 'string',
|
|
253
|
+
pattern: '^[0-9]+$',
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
validateOVMRequestWithdrawalPayload: true,
|
|
258
|
+
required: ['ovmAddress', 'pubKeys', 'amounts'],
|
|
259
|
+
};
|
|
@@ -8,27 +8,18 @@ import {
|
|
|
8
8
|
type OVMArgs,
|
|
9
9
|
type ChainConfig,
|
|
10
10
|
} from '../types';
|
|
11
|
-
import {
|
|
12
|
-
BrowserProvider,
|
|
13
|
-
Contract,
|
|
14
|
-
Interface,
|
|
15
|
-
parseEther,
|
|
16
|
-
type Wallet,
|
|
17
|
-
ZeroAddress,
|
|
18
|
-
} from 'ethers';
|
|
11
|
+
import { Contract, Interface, parseEther, ZeroAddress } from 'ethers';
|
|
19
12
|
import { OWRContract, OWRFactoryContract } from '../abi/OWR';
|
|
20
|
-
import { OVMFactoryContract } from '../abi/OVMFactory';
|
|
13
|
+
import { OVMFactoryContract, OVMContract } from '../abi/OVMFactory';
|
|
21
14
|
import { splitMainEthereumAbi } from '../abi/SplitMain';
|
|
22
15
|
import { MultiCallContract } from '../abi/Multicall';
|
|
23
|
-
import { CHAIN_CONFIGURATION
|
|
24
|
-
import {
|
|
25
|
-
import { createPublicClient, createWalletClient, custom, http } from 'viem';
|
|
26
|
-
import { hoodi, mainnet } from 'viem/chains';
|
|
27
|
-
import { privateKeyToAccount } from 'viem/accounts';
|
|
16
|
+
import { CHAIN_CONFIGURATION } from '../constants';
|
|
17
|
+
import { splitV2FactoryAbi } from '../abi/splitV2FactoryAbi';
|
|
28
18
|
|
|
29
19
|
const splitMainContractInterface = new Interface(splitMainEthereumAbi);
|
|
30
20
|
const owrFactoryContractInterface = new Interface(OWRFactoryContract.abi);
|
|
31
21
|
const ovmFactoryContractInterface = new Interface(OVMFactoryContract.abi);
|
|
22
|
+
const splitV2FactoryInterface = new Interface(splitV2FactoryAbi);
|
|
32
23
|
|
|
33
24
|
type Call = {
|
|
34
25
|
target: ETH_ADDRESS;
|
|
@@ -104,7 +95,7 @@ export const predictSplitterAddress = async ({
|
|
|
104
95
|
}): Promise<ETH_ADDRESS> => {
|
|
105
96
|
try {
|
|
106
97
|
const splitMainContractInstance = new Contract(
|
|
107
|
-
getChainConfig(chainId).
|
|
98
|
+
getChainConfig(chainId).SPLITMAIN_CONTRACT.address,
|
|
108
99
|
splitMainEthereumAbi,
|
|
109
100
|
signer,
|
|
110
101
|
);
|
|
@@ -258,7 +249,7 @@ const createOWRContract = async ({
|
|
|
258
249
|
}): Promise<ETH_ADDRESS> => {
|
|
259
250
|
try {
|
|
260
251
|
const OWRFactoryInstance = new Contract(
|
|
261
|
-
getChainConfig(chainId).
|
|
252
|
+
getChainConfig(chainId).OWR_FACTORY_CONTRACT.address,
|
|
262
253
|
OWRFactoryContract.abi,
|
|
263
254
|
signer,
|
|
264
255
|
);
|
|
@@ -345,7 +336,7 @@ export const deploySplitterContract = async ({
|
|
|
345
336
|
}): Promise<ETH_ADDRESS> => {
|
|
346
337
|
try {
|
|
347
338
|
const splitMainContractInstance = new Contract(
|
|
348
|
-
getChainConfig(chainId).
|
|
339
|
+
getChainConfig(chainId).SPLITMAIN_CONTRACT.address,
|
|
349
340
|
splitMainEthereumAbi,
|
|
350
341
|
signer,
|
|
351
342
|
);
|
|
@@ -444,21 +435,16 @@ export const deploySplitterAndOWRContracts = async ({
|
|
|
444
435
|
|
|
445
436
|
executeCalls.push(
|
|
446
437
|
{
|
|
447
|
-
target: getChainConfig(chainId).
|
|
438
|
+
target: getChainConfig(chainId).SPLITMAIN_CONTRACT.address,
|
|
448
439
|
callData: splitTxData,
|
|
449
440
|
},
|
|
450
441
|
{
|
|
451
|
-
target: getChainConfig(chainId).
|
|
442
|
+
target: getChainConfig(chainId).OWR_FACTORY_CONTRACT.address,
|
|
452
443
|
callData: owrTxData,
|
|
453
444
|
},
|
|
454
445
|
);
|
|
455
|
-
const multicallAddess = getChainConfig(chainId).MULTICALL_ADDRESS.address;
|
|
456
446
|
|
|
457
|
-
const executeMultiCalls = await multicall(
|
|
458
|
-
executeCalls,
|
|
459
|
-
signer,
|
|
460
|
-
multicallAddess,
|
|
461
|
-
);
|
|
447
|
+
const executeMultiCalls = await multicall(executeCalls, signer, chainId);
|
|
462
448
|
|
|
463
449
|
const splitAddressData = executeMultiCalls?.logs[0]?.topics[1];
|
|
464
450
|
const formattedSplitterAddress = '0x' + splitAddressData?.slice(26, 66);
|
|
@@ -519,9 +505,11 @@ export const getOWRTranches = async ({
|
|
|
519
505
|
export const multicall = async (
|
|
520
506
|
calls: Call[],
|
|
521
507
|
signer: SignerType,
|
|
522
|
-
|
|
508
|
+
chainId: number,
|
|
523
509
|
): Promise<any> => {
|
|
524
510
|
try {
|
|
511
|
+
const chainConfig = getChainConfig(chainId);
|
|
512
|
+
const multicallAddress = chainConfig.MULTICALL_CONTRACT.address;
|
|
525
513
|
const multiCallContractInstance = new Contract(
|
|
526
514
|
multicallAddress,
|
|
527
515
|
MultiCallContract.abi,
|
|
@@ -613,57 +601,31 @@ export const formatRecipientsForSplitV2 = (
|
|
|
613
601
|
}));
|
|
614
602
|
};
|
|
615
603
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
)
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
chain,
|
|
635
|
-
transport: custom((window as any).ethereum),
|
|
636
|
-
});
|
|
637
|
-
return new SplitsClient({
|
|
638
|
-
publicClient: client,
|
|
639
|
-
walletClient: viemWalletClient,
|
|
640
|
-
chainId,
|
|
641
|
-
});
|
|
642
|
-
} else {
|
|
643
|
-
// For non-browser environment, extract private key from signer
|
|
644
|
-
const signerPrivateKey = (signer as Wallet)?.privateKey;
|
|
645
|
-
if (!signerPrivateKey) {
|
|
646
|
-
throw new Error('Signer private key not available');
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
const privateKey = signerPrivateKey.startsWith('0x')
|
|
650
|
-
? signerPrivateKey
|
|
651
|
-
: `0x${signerPrivateKey}`;
|
|
652
|
-
|
|
653
|
-
const scriptAccount = privateKeyToAccount(privateKey as `0x${string}`);
|
|
654
|
-
const account = scriptAccount;
|
|
604
|
+
// Helper function to create SplitV2 parameters
|
|
605
|
+
const createSplitV2Params = (
|
|
606
|
+
recipients: SplitV2Recipient[],
|
|
607
|
+
distributorFeePercent: number,
|
|
608
|
+
): {
|
|
609
|
+
recipients: string[];
|
|
610
|
+
allocations: number[];
|
|
611
|
+
totalAllocation: number;
|
|
612
|
+
distributionIncentive: number;
|
|
613
|
+
} => {
|
|
614
|
+
const addresses = recipients.map(r => r.address);
|
|
615
|
+
const allocations = recipients.map(r =>
|
|
616
|
+
Math.floor(r.percentAllocation * 1e4),
|
|
617
|
+
); // Convert to basis points
|
|
618
|
+
const totalAllocation = allocations.reduce(
|
|
619
|
+
(sum, allocation) => sum + allocation,
|
|
620
|
+
0,
|
|
621
|
+
);
|
|
655
622
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
publicClient: client,
|
|
663
|
-
walletClient: viemWalletClient,
|
|
664
|
-
chainId,
|
|
665
|
-
});
|
|
666
|
-
}
|
|
623
|
+
return {
|
|
624
|
+
recipients: addresses,
|
|
625
|
+
allocations,
|
|
626
|
+
totalAllocation,
|
|
627
|
+
distributionIncentive: distributorFeePercent,
|
|
628
|
+
};
|
|
667
629
|
};
|
|
668
630
|
|
|
669
631
|
export const predictSplitV2Address = async ({
|
|
@@ -682,19 +644,27 @@ export const predictSplitV2Address = async ({
|
|
|
682
644
|
chainId: number;
|
|
683
645
|
}): Promise<string> => {
|
|
684
646
|
try {
|
|
685
|
-
const
|
|
647
|
+
const chainConfig = getChainConfig(chainId);
|
|
648
|
+
if (!chainConfig?.SPLIT_V2_FACTORY_CONTRACT?.address) {
|
|
649
|
+
throw new Error(`SplitV2 Factory not configured for chain ${chainId}`);
|
|
650
|
+
}
|
|
686
651
|
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
652
|
+
const splitV2FactoryContract = new Contract(
|
|
653
|
+
chainConfig.SPLIT_V2_FACTORY_CONTRACT.address,
|
|
654
|
+
splitV2FactoryAbi,
|
|
655
|
+
signer,
|
|
656
|
+
);
|
|
657
|
+
|
|
658
|
+
const splitParams = createSplitV2Params(recipients, distributorFeePercent);
|
|
659
|
+
|
|
660
|
+
const predictedAddress = await splitV2FactoryContract[
|
|
661
|
+
'predictDeterministicAddress((address[],uint256[],uint256,uint16),address,bytes32)'
|
|
662
|
+
](splitParams, splitOwnerAddress, salt);
|
|
693
663
|
|
|
694
|
-
return
|
|
664
|
+
return predictedAddress;
|
|
695
665
|
} catch (error: any) {
|
|
696
666
|
throw new Error(
|
|
697
|
-
`Failed to predict SplitV2 address: ${error.message ?? 'SplitV2
|
|
667
|
+
`Failed to predict SplitV2 address: ${error.message ?? 'SplitV2 contract call failed'}`,
|
|
698
668
|
);
|
|
699
669
|
}
|
|
700
670
|
};
|
|
@@ -715,15 +685,26 @@ export const isSplitV2Deployed = async ({
|
|
|
715
685
|
chainId: number;
|
|
716
686
|
}): Promise<boolean> => {
|
|
717
687
|
try {
|
|
718
|
-
const
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
688
|
+
const chainConfig = getChainConfig(chainId);
|
|
689
|
+
if (!chainConfig?.SPLIT_V2_FACTORY_CONTRACT?.address) {
|
|
690
|
+
throw new Error(`SplitV2 Factory not configured for chain ${chainId}`);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const splitV2FactoryContract = new Contract(
|
|
694
|
+
chainConfig.SPLIT_V2_FACTORY_CONTRACT.address,
|
|
695
|
+
splitV2FactoryAbi,
|
|
696
|
+
signer,
|
|
697
|
+
);
|
|
698
|
+
|
|
699
|
+
const splitParams = createSplitV2Params(recipients, distributorFeePercent);
|
|
700
|
+
|
|
701
|
+
const [, exists] = await splitV2FactoryContract.isDeployed(
|
|
702
|
+
splitParams,
|
|
703
|
+
splitOwnerAddress,
|
|
723
704
|
salt,
|
|
724
|
-
|
|
705
|
+
);
|
|
725
706
|
|
|
726
|
-
return
|
|
707
|
+
return exists;
|
|
727
708
|
} catch (error: any) {
|
|
728
709
|
// If the check fails, assume it's not deployed
|
|
729
710
|
return false;
|
|
@@ -747,12 +728,12 @@ export const deployOVMContract = async ({
|
|
|
747
728
|
}): Promise<string> => {
|
|
748
729
|
try {
|
|
749
730
|
const chainConfig = getChainConfig(chainId);
|
|
750
|
-
if (!chainConfig?.
|
|
731
|
+
if (!chainConfig?.OVM_FACTORY_CONTRACT?.address) {
|
|
751
732
|
throw new Error(`OVM Factory not configured for chain ${chainId}`);
|
|
752
733
|
}
|
|
753
734
|
|
|
754
735
|
const ovmFactoryContract = new Contract(
|
|
755
|
-
chainConfig.
|
|
736
|
+
chainConfig.OVM_FACTORY_CONTRACT.address,
|
|
756
737
|
OVMFactoryContract.abi,
|
|
757
738
|
signer,
|
|
758
739
|
);
|
|
@@ -806,36 +787,49 @@ export const deployOVMAndSplitV2 = async ({
|
|
|
806
787
|
}): Promise<string> => {
|
|
807
788
|
try {
|
|
808
789
|
const chainConfig = getChainConfig(chainId);
|
|
809
|
-
if (!chainConfig?.
|
|
790
|
+
if (!chainConfig?.OVM_FACTORY_CONTRACT?.address) {
|
|
810
791
|
throw new Error(`OVM Factory not configured for chain ${chainId}`);
|
|
811
792
|
}
|
|
812
793
|
|
|
813
|
-
|
|
814
|
-
|
|
794
|
+
if (!chainConfig?.SPLIT_V2_FACTORY_CONTRACT?.address) {
|
|
795
|
+
throw new Error(`SplitV2 Factory not configured for chain ${chainId}`);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const executeCalls: Call[] = [];
|
|
815
799
|
|
|
816
800
|
if (rewardRecipients && !isRewardsSplitterDeployed) {
|
|
817
801
|
// Create rewards split call data
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
802
|
+
const splitParams = createSplitV2Params(
|
|
803
|
+
rewardRecipients,
|
|
804
|
+
distributorFeePercent,
|
|
805
|
+
);
|
|
806
|
+
const rewardsSplitTxData = encodeCreateSplitV2DeterministicTxData(
|
|
807
|
+
splitParams,
|
|
808
|
+
splitOwnerAddress,
|
|
809
|
+
salt,
|
|
810
|
+
);
|
|
825
811
|
|
|
826
|
-
executeCalls.push(
|
|
812
|
+
executeCalls.push({
|
|
813
|
+
target: chainConfig.SPLIT_V2_FACTORY_CONTRACT.address,
|
|
814
|
+
callData: rewardsSplitTxData,
|
|
815
|
+
});
|
|
827
816
|
}
|
|
828
817
|
|
|
829
818
|
// Create principal split call data if needed (for total split scenario)
|
|
830
819
|
if (principalSplitRecipients && !isPrincipalSplitDeployed) {
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
820
|
+
const principalSplitParams = createSplitV2Params(
|
|
821
|
+
principalSplitRecipients,
|
|
822
|
+
distributorFeePercent,
|
|
823
|
+
);
|
|
824
|
+
const principalSplitTxData = encodeCreateSplitV2DeterministicTxData(
|
|
825
|
+
principalSplitParams,
|
|
826
|
+
splitOwnerAddress,
|
|
827
|
+
salt,
|
|
828
|
+
);
|
|
829
|
+
executeCalls.push({
|
|
830
|
+
target: chainConfig.SPLIT_V2_FACTORY_CONTRACT.address,
|
|
831
|
+
callData: principalSplitTxData,
|
|
832
|
+
});
|
|
839
833
|
}
|
|
840
834
|
|
|
841
835
|
// Create OVM call data
|
|
@@ -847,25 +841,23 @@ export const deployOVMAndSplitV2 = async ({
|
|
|
847
841
|
);
|
|
848
842
|
|
|
849
843
|
executeCalls.push({
|
|
850
|
-
|
|
851
|
-
|
|
844
|
+
target: chainConfig.OVM_FACTORY_CONTRACT.address,
|
|
845
|
+
callData: ovmTxData,
|
|
852
846
|
});
|
|
853
847
|
|
|
854
848
|
// Execute multicall
|
|
855
|
-
const executeMultiCalls = await
|
|
856
|
-
calls: executeCalls,
|
|
857
|
-
});
|
|
849
|
+
const executeMultiCalls = await multicall(executeCalls, signer, chainId);
|
|
858
850
|
|
|
859
851
|
// Extract addresses from events
|
|
860
852
|
let ovmAddress: string | undefined;
|
|
861
|
-
const
|
|
853
|
+
const logsCount = executeMultiCalls?.logs?.length || 0;
|
|
862
854
|
|
|
863
|
-
if (
|
|
864
|
-
ovmAddress = executeMultiCalls?.
|
|
865
|
-
} else if (
|
|
866
|
-
ovmAddress = executeMultiCalls?.
|
|
855
|
+
if (logsCount === 2) {
|
|
856
|
+
ovmAddress = '0x' + executeMultiCalls?.logs[1]?.topics[1]?.slice(26, 66);
|
|
857
|
+
} else if (logsCount === 5) {
|
|
858
|
+
ovmAddress = '0x' + executeMultiCalls?.logs[4]?.topics[1]?.slice(26, 66);
|
|
867
859
|
} else {
|
|
868
|
-
ovmAddress = executeMultiCalls?.
|
|
860
|
+
ovmAddress = '0x' + executeMultiCalls?.logs[7]?.topics[1]?.slice(26, 66);
|
|
869
861
|
}
|
|
870
862
|
if (!ovmAddress) {
|
|
871
863
|
throw new Error(
|
|
@@ -893,6 +885,23 @@ const encodeCreateOVMTxData = (
|
|
|
893
885
|
);
|
|
894
886
|
};
|
|
895
887
|
|
|
888
|
+
const encodeCreateSplitV2DeterministicTxData = (
|
|
889
|
+
splitParams: {
|
|
890
|
+
recipients: string[];
|
|
891
|
+
allocations: number[];
|
|
892
|
+
totalAllocation: number;
|
|
893
|
+
distributionIncentive: number;
|
|
894
|
+
},
|
|
895
|
+
splitOwnerAddress: string,
|
|
896
|
+
salt: `0x${string}`,
|
|
897
|
+
): string => {
|
|
898
|
+
// creatorAddress can be kept as default https://docs.splits.org/sdk/splits-v2#createsplit
|
|
899
|
+
return splitV2FactoryInterface.encodeFunctionData(
|
|
900
|
+
'createSplitDeterministic',
|
|
901
|
+
[splitParams, splitOwnerAddress, ZeroAddress, salt],
|
|
902
|
+
);
|
|
903
|
+
};
|
|
904
|
+
|
|
896
905
|
// Helper function to safely get chain configuration
|
|
897
906
|
const getChainConfig = (chainId: number): ChainConfig => {
|
|
898
907
|
const config = CHAIN_CONFIGURATION[chainId];
|
|
@@ -901,3 +910,39 @@ const getChainConfig = (chainId: number): ChainConfig => {
|
|
|
901
910
|
}
|
|
902
911
|
return config;
|
|
903
912
|
};
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Requests withdrawal from an OVM contract
|
|
916
|
+
* @param ovmAddress - The address of the OVM contract
|
|
917
|
+
* @param pubKeys - Array of validator public keys in bytes format
|
|
918
|
+
* @param amounts - Array of withdrawal amounts in wei (uint64)
|
|
919
|
+
* @param signer - The signer to use for the transaction
|
|
920
|
+
* @returns Promise that resolves to the transaction hash
|
|
921
|
+
*/
|
|
922
|
+
export const requestWithdrawalFromOVM = async ({
|
|
923
|
+
ovmAddress,
|
|
924
|
+
pubKeys,
|
|
925
|
+
amounts,
|
|
926
|
+
signer,
|
|
927
|
+
}: {
|
|
928
|
+
ovmAddress: string;
|
|
929
|
+
pubKeys: string[];
|
|
930
|
+
amounts: string[];
|
|
931
|
+
signer: SignerType;
|
|
932
|
+
}): Promise<{ txHash: string }> => {
|
|
933
|
+
try {
|
|
934
|
+
// Convert string amounts to bigint
|
|
935
|
+
const bigintAmounts = amounts.map(amount => BigInt(amount));
|
|
936
|
+
|
|
937
|
+
const ovmContract = new Contract(ovmAddress, OVMContract.abi, signer);
|
|
938
|
+
|
|
939
|
+
const tx = await ovmContract.requestWithdrawal(pubKeys, bigintAmounts);
|
|
940
|
+
const receipt = await tx.wait();
|
|
941
|
+
|
|
942
|
+
return { txHash: receipt.hash };
|
|
943
|
+
} catch (error: any) {
|
|
944
|
+
throw new Error(
|
|
945
|
+
`Failed to request withdrawal from OVM: ${error.message ?? 'Request withdrawal failed'}`,
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
};
|