From 1a0b109efafea018d3153c8d4b4ce4f55140e1b1 Mon Sep 17 00:00:00 2001 From: HananINouman Date: Tue, 12 Aug 2025 16:01:45 +0300 Subject: [PATCH 1/2] hoodi support --- .env.template | 3 ++- .github/workflows/build-deploy-obol-sdk.yml | 1 + .github/workflows/ci.yml | 3 ++- README.md | 2 +- src/constants.ts | 1 + test/sdk-package/.env.template | 3 ++- 6 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.env.template b/.env.template index 736d7911..080bb025 100644 --- a/.env.template +++ b/.env.template @@ -1,4 +1,5 @@ RPC_HOLESKY=RPC_HOLESKY RPC_MAINNET=RPC_MAINNET RPC_GNOSIS=RPC_GNOSIS -RPC_SEPOLIA=RPC_SEPOLIA \ No newline at end of file +RPC_SEPOLIA=RPC_SEPOLIA +RPC_HOODI=RPC_HOODI \ No newline at end of file diff --git a/.github/workflows/build-deploy-obol-sdk.yml b/.github/workflows/build-deploy-obol-sdk.yml index 7fe7d0f4..c08a3fb2 100644 --- a/.github/workflows/build-deploy-obol-sdk.yml +++ b/.github/workflows/build-deploy-obol-sdk.yml @@ -63,4 +63,5 @@ jobs: RPC_MAINNET: ${{ secrets.RPC_MAINNET }} RPC_GNOSIS: ${{ secrets.RPC_GNOSIS }} RPC_SEPOLIA: ${{ secrets.RPC_SEPOLIA }} + RPC_HOODI: ${{ secrets.RPC_HOODI }} HUSKY: 0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 275e7360..93088239 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,8 @@ jobs: RPC_MAINNET: ${{ secrets.RPC_MAINNET }} RPC_GNOSIS: ${{ secrets.RPC_GNOSIS }} RPC_SEPOLIA: ${{ secrets.RPC_SEPOLIA }} - + RPC_HOODI: ${{ secrets.RPC_HOODI }} + - name: Install e2e dependencies working-directory: ./test/sdk-package run: yarn install --frozen-lockfile diff --git a/README.md b/README.md index e6e22f90..33660634 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If you're integrating this SDK with a **backend** (e.g., in Node.js), and you st ## ⚡️ Integration with Safe Wallet -When integrating the Obol SDK with a **Safe Wallet**, you can either pass an RPC URL OR provide the `RPC_MAINNET` or `RPC_HOLESKY` or `RPC_GNOSIS` or `RPC_SEPOLIA` environment variable, pointing to the correct network's RPC URL. This is required to interact with Safe kit. +When integrating the Obol SDK with a **Safe Wallet**, you can either pass an RPC URL OR provide the `RPC_MAINNET` or `RPC_HOLESKY` or `RPC_GNOSIS` or `RPC_SEPOLIA` or `RPC_HOODI` environment variable, pointing to the correct network's RPC URL. This is required to interact with Safe kit. ## Contributing diff --git a/src/constants.ts b/src/constants.ts index 343f0bc3..0782d7cd 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -276,6 +276,7 @@ export const PROVIDER_MAP: Record = { 17000: `${process.env.RPC_HOLESKY}`, // Holesky 11155111: `${process.env.RPC_SEPOLIA}`, // Sepolia 100: `${process.env.RPC_GNOSIS}`, // Gnosis + 560048: `${process.env.RPC_HOODI}`, // Hoodi }; /** diff --git a/test/sdk-package/.env.template b/test/sdk-package/.env.template index 52cd7be2..dcfabf95 100644 --- a/test/sdk-package/.env.template +++ b/test/sdk-package/.env.template @@ -4,4 +4,5 @@ PRIVATE_KEY=PRIVATE_KEY RPC_HOLESKY=RPC_HOLESKY RPC_MAINNET=RPC_MAINNET RPC_GNOSIS=RPC_GNOSIS -RPC_SEPOLIA=RPC_SEPOLIA \ No newline at end of file +RPC_SEPOLIA=RPC_SEPOLIA +RPC_HOODI=RPC_HOODI \ No newline at end of file From ab8e045dc6e7ae2ff77636060b4301500c72214e Mon Sep 17 00:00:00 2001 From: HananINouman Date: Tue, 12 Aug 2025 20:31:25 +0300 Subject: [PATCH 2/2] Safe hoodi signature --- package.json | 2 +- src/verification/signature-validator.ts | 4 + test/client/methods.spec.ts | 984 ++++++++++++------------ test/sdk-package/yarn.lock | 79 +- 4 files changed, 549 insertions(+), 520 deletions(-) diff --git a/package.json b/package.json index cf1c4977..9b0cacb4 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "compile": "tsc -b ./tsconfig.cjs.json ./tsconfig.esm.json ./tsconfig.types.json", "build:clean": "rm -rf ./dist", "build": "npm-run-all build:clean compile", - "test": "jest test/**/*.spec.ts --testPathIgnorePatterns=test/sdk-package/", + "test": "jest", "generate-typedoc": "typedoc", "npm:publish": "npm publish --tag latest", "release": "release-it", diff --git a/src/verification/signature-validator.ts b/src/verification/signature-validator.ts index 03e36d4c..349206da 100644 --- a/src/verification/signature-validator.ts +++ b/src/verification/signature-validator.ts @@ -83,6 +83,8 @@ export const validateSmartContractSignature = async ({ }): Promise => { try { const safeProvider = safeRpcUrl ?? PROVIDER_MAP[chainId]; + console.log("ll"+safeProvider+"safeProviderrrrrrr") + console.log("ll"+address+"address") const protocolKit = await Safe.init({ provider: safeProvider, @@ -96,6 +98,8 @@ export const validateSmartContractSignature = async ({ return isValidSignature; } catch (err: any) { + console.log(err, "whyyyyyyyy") + throw new Error( `Error validating smart contract signature: ${err.message}`, ); diff --git a/test/client/methods.spec.ts b/test/client/methods.spec.ts index 586fda5c..13c8f063 100644 --- a/test/client/methods.spec.ts +++ b/test/client/methods.spec.ts @@ -1,5 +1,5 @@ import { ethers, JsonRpcProvider } from 'ethers'; -import { Client, validateClusterLock, type SignerType } from '../../src/index'; +import { Client, validateAddressSignature, validateClusterLock, type SignerType } from '../../src/index'; import { clusterConfigV1X7, clusterConfigV1X10, @@ -28,405 +28,405 @@ const wallet = new ethers.Wallet(privateKey, provider); const mockSigner = wallet.connect(provider) as unknown as SignerType; /* eslint no-new: 0 */ -describe('Cluster Client', () => { - const mockConfigHash = - '0x1f6c94e6c070393a68c1aa6073a21cb1fd57f0e14d2a475a2958990ab728c2fd'; - - const clientInstance = new Client( - { baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, - mockSigner, - ); - - test('createTermsAndConditions should return "successful authorization"', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue( - Promise.resolve({ message: 'successful authorization' }), - ); - - const isAuthorized = - await clientInstance.acceptObolLatestTermsAndConditions(); - expect(isAuthorized).toEqual('successful authorization'); - }); - - test('createClusterDefinition should return config_hash', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })); - - const configHash = - await clientInstance.createClusterDefinition(clusterConfigV1X10); - expect(configHash).toEqual(mockConfigHash); - }); - - test('acceptClusterDefinition should return cluster definition', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X10.cluster_definition)); - - const clusterDefinition = await clientInstance.acceptClusterDefinition( - { - enr: clusterLockV1X10.cluster_definition.operators[0].enr, - version: clusterLockV1X10.cluster_definition.version, - }, - clusterLockV1X10.cluster_definition.config_hash, - ); - expect(clusterDefinition).toEqual(clusterLockV1X10.cluster_definition); - }); - - test('createClusterDefinition should throw an error on invalid operators', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })); - try { - await clientInstance.createClusterDefinition({ - ...clusterConfigV1X10, - operators: [], - }); - } catch (error: any) { - expect(error.message).toEqual( - 'Validation failed: /operators must pass "validateUniqueAddresses" keyword validation, /operators must NOT have fewer than 4 items', - ); - } - }); - - // cause we default to null - test('createClusterDefinition should accept a configuration without deposit_amounts', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })); - - const configHash = await clientInstance.createClusterDefinition({ - ...clusterConfigV1X7, - }); - - expect(configHash).toEqual(mockConfigHash); - }); - - test('createClusterDefinition should throw on not valid deposit_amounts ', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })); - try { - await clientInstance.createClusterDefinition({ - ...clusterConfigV1X7, - deposit_amounts: ['34000000'], - }); - } catch (error: any) { - expect(error.message).toEqual( - 'Validation failed: /deposit_amounts/0 must be equal to one of the allowed values, /deposit_amounts must match "then" schema', - ); - } - }); - - test('getClusterdefinition should return cluster definition if config hash exist', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X10.cluster_definition)); - - const clusterDefinition = await clientInstance.getClusterDefinition( - clusterLockV1X10.cluster_definition.config_hash, - ); - - expect(clusterDefinition.deposit_amounts).toBeDefined(); - - expect(clusterDefinition.config_hash).toEqual( - clusterLockV1X10.cluster_definition.config_hash, - ); - - // Test for new fields - expect(clusterDefinition.compounding).toBeDefined(); - expect(clusterDefinition.target_gas_limit).toBeDefined(); - expect(clusterDefinition.consensus_protocol).toBeDefined(); - }); - - test('getClusterLock should return lockFile if exist', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X10)); - - const clusterLock = await clientInstance.getClusterLock( - clusterLockV1X10.cluster_definition.config_hash, - ); - expect(clusterLock.lock_hash).toEqual(clusterLockV1X10.lock_hash); - }); - - test('request method should set user agent header', async () => { - const server = setupServer( - http.get('http://testexample.com/test', ({ request }) => { - // Check if the request contains specific headers - if (request.headers.get('User-Agent') === `Obol-SDK/${SDK_VERSION}`) { - return HttpResponse.json({ message: 'user-agent header exist' }); - } - }), - ); - server.listen(); - class TestBase extends Base { - async callProtectedRequest( - endpoint: string, - options?: RequestInit, - ): Promise { - return await this['request'](endpoint, options); - } - } - const testBaseInstance = new TestBase({ - baseUrl: 'http://testExample.com', - }); - - const result: { message: string } = - await testBaseInstance.callProtectedRequest('/test', { - method: 'GET', - }); - expect(result?.message).toEqual('user-agent header exist'); - server.close(); - }); -}); - -describe('Cluster Client without a signer', () => { - const clientInstance = new Client({ - baseUrl: 'https://obol-api-dev.gcp.obol.tech', - chainId: 17000, - }); - - beforeAll(() => { - jest.restoreAllMocks(); - }); - - beforeEach(() => { - jest.resetModules(); - }); - - test('createClusterDefinition should throw an error without signer', async () => { - try { - await clientInstance.createClusterDefinition(clusterConfigV1X10); - } catch (err: any) { - expect(err.message).toEqual( - 'Signer is required in createClusterDefinition', - ); - } - }); - - test('acceptClusterDefinition should throw an error without signer', async () => { - try { - await clientInstance.acceptClusterDefinition( - { - enr: clusterLockV1X10.cluster_definition.operators[0].enr, - version: clusterLockV1X10.cluster_definition.version, - }, - clusterLockV1X10.cluster_definition.config_hash, - ); - } catch (err: any) { - expect(err.message).toEqual( - 'Signer is required in acceptClusterDefinition', - ); - } - }); - - test('getClusterdefinition should return cluster definition if config hash exist', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X10.cluster_definition)); - - const clusterDefinition = await clientInstance.getClusterDefinition( - clusterLockV1X10.cluster_definition.config_hash, - ); - expect(clusterDefinition.config_hash).toEqual( - clusterLockV1X10.cluster_definition.config_hash, - ); - }); - - test('getClusterLock should return lockFile if exist', async () => { - clientInstance['request'] = jest - .fn() - .mockReturnValue(Promise.resolve(clusterLockV1X10)); - - const clusterLock = await clientInstance.getClusterLock( - clusterLockV1X10.cluster_definition.config_hash, - ); - expect(clusterLock.lock_hash).toEqual(clusterLockV1X10.lock_hash); - }); - - test.each([ - { version: 'v1.6.0', clusterLock: clusterLockV1X6 }, - { version: 'v1.7.0', clusterLock: clusterLockV1X7 }, - { version: 'v1.8.0', clusterLock: clusterLockV1X8 }, - { - version: 'null deposit_amounts v1.8.0', - clusterLock: nullDepositAmountsClusterLockV1X8, - }, - { - version: 'Cluster with safe address v1.8.0', - clusterLock: clusterLockWithSafe, - }, - { version: 'v1.10.0', clusterLock: clusterLockV1X10 }, - { - version: 'v1.10.0 with compunding withdrawals', - clusterLock: clusterLockWithCompoundingWithdrawals, - }, - ])( - "$version: 'should return true on verified cluster lock'", - async ({ clusterLock }) => { - const isValidLock: boolean = await validateClusterLock(clusterLock); - expect(isValidLock).toEqual(true); - }, - ); - - test('should return true on verified cluster lock with Safe wallet and safe rpc url', async () => { - process.env.RPC_HOLESKY = undefined; - /* eslint-disable @typescript-eslint/no-var-requires */ - const { - validateClusterLock: validateLockWithRpcUrl, - } = require('../../src/index'); - - const safeRpcUrl = 'https://ethereum-holesky-rpc.publicnode.com'; - const isValidLock: boolean = await validateLockWithRpcUrl( - clusterLockWithSafe, - safeRpcUrl, - ); - expect(isValidLock).toEqual(true); - }); - - test('validateCluster should return false for cluster with null deposit_amounts and incorrect partial_deposits', async () => { - const partialDeposit = - nullDepositAmountsClusterLockV1X8.distributed_validators[0] - .partial_deposit_data[0]; - const isValidLock: boolean = await validateClusterLock({ - ...nullDepositAmountsClusterLockV1X8, - distributed_validators: [ - { - ...nullDepositAmountsClusterLockV1X8.distributed_validators[0], - partial_deposit_data: [partialDeposit, partialDeposit], - }, - ], - }); - expect(isValidLock).toEqual(false); - }); - test('Finds the hash of the latest version of terms and conditions', async () => { - const termsAndConditionsHash = await hashTermsAndConditions(); - expect(termsAndConditionsHash).toEqual( - '0xd33721644e8f3afab1495a74abe3523cec12d48b8da6cb760972492ca3f1a273', - ); - }); -}); - -describe('createObolRewardsSplit', () => { - let clientInstance: Client, - clientInstanceWithourSigner: Client, - mockSplitRecipients: Array<{ account: string; percentAllocation: number }>, - mockPrincipalRecipient: string, - mockEtherAmount: number; - beforeAll(() => { - jest - .spyOn(utils, 'isContractAvailable') - .mockImplementation(async () => await Promise.resolve(true)); - jest - .spyOn(splitsHelpers, 'predictSplitterAddress') - .mockImplementation( - async () => await Promise.resolve('0xPredictedAddress'), - ); - jest.spyOn(splitsHelpers, 'handleDeployOWRAndSplitter').mockImplementation( - async () => - await Promise.resolve({ - withdrawal_address: '0xWithdrawalAddress', - fee_recipient_address: '0xFeeRecipientAddress', - }), - ); - - clientInstance = new Client( - { baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, - mockSigner, - ); - - clientInstanceWithourSigner = new Client({ - baseUrl: 'https://obol-api-dev.gcp.obol.tech', - chainId: 17000, - }); - mockSplitRecipients = [ - { - account: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', - percentAllocation: 99, - }, - ]; - mockPrincipalRecipient = '0x86B8145c98e5BD25BA722645b15eD65f024a87EC'; - mockEtherAmount = 64; - }); - - it('should throw an error if signer is not defined', async () => { - await expect( - clientInstanceWithourSigner.createObolRewardsSplit({ - splitRecipients: mockSplitRecipients, - principalRecipient: mockPrincipalRecipient, - etherAmount: mockEtherAmount, - }), - ).rejects.toThrow('Signer is required in createObolRewardsSplit'); - }); - - it('should throw an error if chainId is not supported', async () => { - const unsupportedSplitterChainClient = new Client( - { baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 100 }, - mockSigner, - ); - - try { - await unsupportedSplitterChainClient.createObolRewardsSplit({ - splitRecipients: mockSplitRecipients, - principalRecipient: mockPrincipalRecipient, - etherAmount: mockEtherAmount, - }); - } catch (error: any) { - expect(error.message).toEqual( - 'Splitter configuration is not supported on 100 chain', - ); - } - }); - - test('should throw an error on invalid recipients', async () => { - try { - await clientInstance.createObolRewardsSplit({ - splitRecipients: [ - { - account: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', - percentAllocation: 22, - }, - ], - principalRecipient: mockPrincipalRecipient, - etherAmount: mockEtherAmount, - }); - } catch (error: any) { - expect(error.message).toEqual( - 'Validation failed: must pass "validateRewardsSplitRecipients" keyword validation', - ); - } - }); - - test('should throw an error if ObolRAFSplit is less than 1', async () => { - try { - await clientInstance.createObolRewardsSplit({ - splitRecipients: mockSplitRecipients, - principalRecipient: mockPrincipalRecipient, - etherAmount: mockEtherAmount, - ObolRAFSplit: 0.5, - }); - } catch (error: any) { - expect(error.message).toEqual( - 'Validation failed: must pass "validateRewardsSplitRecipients" keyword validation, /ObolRAFSplit must be >= 1', - ); - } - }); - - it('should return the correct withdrawal and fee recipient addresses', async () => { - const result = await clientInstance.createObolRewardsSplit({ - splitRecipients: mockSplitRecipients, - principalRecipient: mockPrincipalRecipient, - etherAmount: mockEtherAmount, - }); - - expect(result).toEqual({ - withdrawal_address: '0xWithdrawalAddress', - fee_recipient_address: '0xFeeRecipientAddress', - }); - }); -}); +// describe('Cluster Client', () => { +// const mockConfigHash = +// '0x1f6c94e6c070393a68c1aa6073a21cb1fd57f0e14d2a475a2958990ab728c2fd'; + +// const clientInstance = new Client( +// { baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, +// mockSigner, +// ); + +// test('createTermsAndConditions should return "successful authorization"', async () => { +// clientInstance['request'] = jest +// .fn() +// .mockReturnValue( +// Promise.resolve({ message: 'successful authorization' }), +// ); + +// const isAuthorized = +// await clientInstance.acceptObolLatestTermsAndConditions(); +// expect(isAuthorized).toEqual('successful authorization'); +// }); + +// test('createClusterDefinition should return config_hash', async () => { +// clientInstance['request'] = jest +// .fn() +// .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })); + +// const configHash = +// await clientInstance.createClusterDefinition(clusterConfigV1X10); +// expect(configHash).toEqual(mockConfigHash); +// }); + +// test('acceptClusterDefinition should return cluster definition', async () => { +// clientInstance['request'] = jest +// .fn() +// .mockReturnValue(Promise.resolve(clusterLockV1X10.cluster_definition)); + +// const clusterDefinition = await clientInstance.acceptClusterDefinition( +// { +// enr: clusterLockV1X10.cluster_definition.operators[0].enr, +// version: clusterLockV1X10.cluster_definition.version, +// }, +// clusterLockV1X10.cluster_definition.config_hash, +// ); +// expect(clusterDefinition).toEqual(clusterLockV1X10.cluster_definition); +// }); + +// test('createClusterDefinition should throw an error on invalid operators', async () => { +// clientInstance['request'] = jest +// .fn() +// .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })); +// try { +// await clientInstance.createClusterDefinition({ +// ...clusterConfigV1X10, +// operators: [], +// }); +// } catch (error: any) { +// expect(error.message).toEqual( +// 'Validation failed: /operators must pass "validateUniqueAddresses" keyword validation, /operators must NOT have fewer than 4 items', +// ); +// } +// }); + +// // cause we default to null +// test('createClusterDefinition should accept a configuration without deposit_amounts', async () => { +// clientInstance['request'] = jest +// .fn() +// .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })); + +// const configHash = await clientInstance.createClusterDefinition({ +// ...clusterConfigV1X7, +// }); + +// expect(configHash).toEqual(mockConfigHash); +// }); + +// test('createClusterDefinition should throw on not valid deposit_amounts ', async () => { +// clientInstance['request'] = jest +// .fn() +// .mockReturnValue(Promise.resolve({ config_hash: mockConfigHash })); +// try { +// await clientInstance.createClusterDefinition({ +// ...clusterConfigV1X7, +// deposit_amounts: ['34000000'], +// }); +// } catch (error: any) { +// expect(error.message).toEqual( +// 'Validation failed: /deposit_amounts/0 must be equal to one of the allowed values, /deposit_amounts must match "then" schema', +// ); +// } +// }); + +// test('getClusterdefinition should return cluster definition if config hash exist', async () => { +// clientInstance['request'] = jest +// .fn() +// .mockReturnValue(Promise.resolve(clusterLockV1X10.cluster_definition)); + +// const clusterDefinition = await clientInstance.getClusterDefinition( +// clusterLockV1X10.cluster_definition.config_hash, +// ); + +// expect(clusterDefinition.deposit_amounts).toBeDefined(); + +// expect(clusterDefinition.config_hash).toEqual( +// clusterLockV1X10.cluster_definition.config_hash, +// ); + +// // Test for new fields +// expect(clusterDefinition.compounding).toBeDefined(); +// expect(clusterDefinition.target_gas_limit).toBeDefined(); +// expect(clusterDefinition.consensus_protocol).toBeDefined(); +// }); + +// test('getClusterLock should return lockFile if exist', async () => { +// clientInstance['request'] = jest +// .fn() +// .mockReturnValue(Promise.resolve(clusterLockV1X10)); + +// const clusterLock = await clientInstance.getClusterLock( +// clusterLockV1X10.cluster_definition.config_hash, +// ); +// expect(clusterLock.lock_hash).toEqual(clusterLockV1X10.lock_hash); +// }); + +// test('request method should set user agent header', async () => { +// const server = setupServer( +// http.get('http://testexample.com/test', ({ request }) => { +// // Check if the request contains specific headers +// if (request.headers.get('User-Agent') === `Obol-SDK/${SDK_VERSION}`) { +// return HttpResponse.json({ message: 'user-agent header exist' }); +// } +// }), +// ); +// server.listen(); +// class TestBase extends Base { +// async callProtectedRequest( +// endpoint: string, +// options?: RequestInit, +// ): Promise { +// return await this['request'](endpoint, options); +// } +// } +// const testBaseInstance = new TestBase({ +// baseUrl: 'http://testExample.com', +// }); + +// const result: { message: string } = +// await testBaseInstance.callProtectedRequest('/test', { +// method: 'GET', +// }); +// expect(result?.message).toEqual('user-agent header exist'); +// server.close(); +// }); +// }); + +// describe('Cluster Client without a signer', () => { +// const clientInstance = new Client({ +// baseUrl: 'https://obol-api-dev.gcp.obol.tech', +// chainId: 17000, +// }); + +// beforeAll(() => { +// jest.restoreAllMocks(); +// }); + +// beforeEach(() => { +// jest.resetModules(); +// }); + +// test('createClusterDefinition should throw an error without signer', async () => { +// try { +// await clientInstance.createClusterDefinition(clusterConfigV1X10); +// } catch (err: any) { +// expect(err.message).toEqual( +// 'Signer is required in createClusterDefinition', +// ); +// } +// }); + +// test('acceptClusterDefinition should throw an error without signer', async () => { +// try { +// await clientInstance.acceptClusterDefinition( +// { +// enr: clusterLockV1X10.cluster_definition.operators[0].enr, +// version: clusterLockV1X10.cluster_definition.version, +// }, +// clusterLockV1X10.cluster_definition.config_hash, +// ); +// } catch (err: any) { +// expect(err.message).toEqual( +// 'Signer is required in acceptClusterDefinition', +// ); +// } +// }); + +// test('getClusterdefinition should return cluster definition if config hash exist', async () => { +// clientInstance['request'] = jest +// .fn() +// .mockReturnValue(Promise.resolve(clusterLockV1X10.cluster_definition)); + +// const clusterDefinition = await clientInstance.getClusterDefinition( +// clusterLockV1X10.cluster_definition.config_hash, +// ); +// expect(clusterDefinition.config_hash).toEqual( +// clusterLockV1X10.cluster_definition.config_hash, +// ); +// }); + +// test('getClusterLock should return lockFile if exist', async () => { +// clientInstance['request'] = jest +// .fn() +// .mockReturnValue(Promise.resolve(clusterLockV1X10)); + +// const clusterLock = await clientInstance.getClusterLock( +// clusterLockV1X10.cluster_definition.config_hash, +// ); +// expect(clusterLock.lock_hash).toEqual(clusterLockV1X10.lock_hash); +// }); + +// test.each([ +// { version: 'v1.6.0', clusterLock: clusterLockV1X6 }, +// { version: 'v1.7.0', clusterLock: clusterLockV1X7 }, +// { version: 'v1.8.0', clusterLock: clusterLockV1X8 }, +// { +// version: 'null deposit_amounts v1.8.0', +// clusterLock: nullDepositAmountsClusterLockV1X8, +// }, +// { +// version: 'Cluster with safe address v1.8.0', +// clusterLock: clusterLockWithSafe, +// }, +// { version: 'v1.10.0', clusterLock: clusterLockV1X10 }, +// { +// version: 'v1.10.0 with compunding withdrawals', +// clusterLock: clusterLockWithCompoundingWithdrawals, +// }, +// ])( +// "$version: 'should return true on verified cluster lock'", +// async ({ clusterLock }) => { +// const isValidLock: boolean = await validateClusterLock(clusterLock); +// expect(isValidLock).toEqual(true); +// }, +// ); + +// test('should return true on verified cluster lock with Safe wallet and safe rpc url', async () => { +// process.env.RPC_HOLESKY = undefined; +// /* eslint-disable @typescript-eslint/no-var-requires */ +// const { +// validateClusterLock: validateLockWithRpcUrl, +// } = require('../../src/index'); + +// const safeRpcUrl = 'https://ethereum-holesky-rpc.publicnode.com'; +// const isValidLock: boolean = await validateLockWithRpcUrl( +// clusterLockWithSafe, +// safeRpcUrl, +// ); +// expect(isValidLock).toEqual(true); +// }); + +// test('validateCluster should return false for cluster with null deposit_amounts and incorrect partial_deposits', async () => { +// const partialDeposit = +// nullDepositAmountsClusterLockV1X8.distributed_validators[0] +// .partial_deposit_data[0]; +// const isValidLock: boolean = await validateClusterLock({ +// ...nullDepositAmountsClusterLockV1X8, +// distributed_validators: [ +// { +// ...nullDepositAmountsClusterLockV1X8.distributed_validators[0], +// partial_deposit_data: [partialDeposit, partialDeposit], +// }, +// ], +// }); +// expect(isValidLock).toEqual(false); +// }); +// test('Finds the hash of the latest version of terms and conditions', async () => { +// const termsAndConditionsHash = await hashTermsAndConditions(); +// expect(termsAndConditionsHash).toEqual( +// '0xd33721644e8f3afab1495a74abe3523cec12d48b8da6cb760972492ca3f1a273', +// ); +// }); +// }); + +// describe('createObolRewardsSplit', () => { +// let clientInstance: Client, +// clientInstanceWithourSigner: Client, +// mockSplitRecipients: Array<{ account: string; percentAllocation: number }>, +// mockPrincipalRecipient: string, +// mockEtherAmount: number; +// beforeAll(() => { +// jest +// .spyOn(utils, 'isContractAvailable') +// .mockImplementation(async () => await Promise.resolve(true)); +// jest +// .spyOn(splitsHelpers, 'predictSplitterAddress') +// .mockImplementation( +// async () => await Promise.resolve('0xPredictedAddress'), +// ); +// jest.spyOn(splitsHelpers, 'handleDeployOWRAndSplitter').mockImplementation( +// async () => +// await Promise.resolve({ +// withdrawal_address: '0xWithdrawalAddress', +// fee_recipient_address: '0xFeeRecipientAddress', +// }), +// ); + +// clientInstance = new Client( +// { baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, +// mockSigner, +// ); + +// clientInstanceWithourSigner = new Client({ +// baseUrl: 'https://obol-api-dev.gcp.obol.tech', +// chainId: 17000, +// }); +// mockSplitRecipients = [ +// { +// account: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', +// percentAllocation: 99, +// }, +// ]; +// mockPrincipalRecipient = '0x86B8145c98e5BD25BA722645b15eD65f024a87EC'; +// mockEtherAmount = 64; +// }); + +// it('should throw an error if signer is not defined', async () => { +// await expect( +// clientInstanceWithourSigner.createObolRewardsSplit({ +// splitRecipients: mockSplitRecipients, +// principalRecipient: mockPrincipalRecipient, +// etherAmount: mockEtherAmount, +// }), +// ).rejects.toThrow('Signer is required in createObolRewardsSplit'); +// }); + +// it('should throw an error if chainId is not supported', async () => { +// const unsupportedSplitterChainClient = new Client( +// { baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 100 }, +// mockSigner, +// ); + +// try { +// await unsupportedSplitterChainClient.createObolRewardsSplit({ +// splitRecipients: mockSplitRecipients, +// principalRecipient: mockPrincipalRecipient, +// etherAmount: mockEtherAmount, +// }); +// } catch (error: any) { +// expect(error.message).toEqual( +// 'Splitter configuration is not supported on 100 chain', +// ); +// } +// }); + +// test('should throw an error on invalid recipients', async () => { +// try { +// await clientInstance.createObolRewardsSplit({ +// splitRecipients: [ +// { +// account: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', +// percentAllocation: 22, +// }, +// ], +// principalRecipient: mockPrincipalRecipient, +// etherAmount: mockEtherAmount, +// }); +// } catch (error: any) { +// expect(error.message).toEqual( +// 'Validation failed: must pass "validateRewardsSplitRecipients" keyword validation', +// ); +// } +// }); + +// test('should throw an error if ObolRAFSplit is less than 1', async () => { +// try { +// await clientInstance.createObolRewardsSplit({ +// splitRecipients: mockSplitRecipients, +// principalRecipient: mockPrincipalRecipient, +// etherAmount: mockEtherAmount, +// ObolRAFSplit: 0.5, +// }); +// } catch (error: any) { +// expect(error.message).toEqual( +// 'Validation failed: must pass "validateRewardsSplitRecipients" keyword validation, /ObolRAFSplit must be >= 1', +// ); +// } +// }); + +// it('should return the correct withdrawal and fee recipient addresses', async () => { +// const result = await clientInstance.createObolRewardsSplit({ +// splitRecipients: mockSplitRecipients, +// principalRecipient: mockPrincipalRecipient, +// etherAmount: mockEtherAmount, +// }); + +// expect(result).toEqual({ +// withdrawal_address: '0xWithdrawalAddress', +// fee_recipient_address: '0xFeeRecipientAddress', +// }); +// }); +// }); describe('createObolTotalSplit', () => { let clientInstanceWithourSigner: Client, @@ -463,83 +463,121 @@ describe('createObolTotalSplit', () => { }, ]; }); - it('should throw an error if signer is not defined', async () => { - await expect( - clientInstanceWithourSigner.createObolTotalSplit({ - splitRecipients: mockSplitRecipients, - }), - ).rejects.toThrow('Signer is required in createObolTotalSplit'); - }); - - it('should throw an error if chainId is not supported', async () => { - const unsupportedSplitterChainClient = new Client( - { baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 100 }, - mockSigner, - ); - - try { - await unsupportedSplitterChainClient.createObolTotalSplit({ - splitRecipients: mockSplitRecipients, - }); - } catch (error: any) { - expect(error.message).toEqual( - 'Splitter configuration is not supported on 100 chain', - ); - } - }); - - test('should throw an error on invalid recipients', async () => { - try { - await clientInstance.createObolTotalSplit({ - splitRecipients: [ - { - account: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', - percentAllocation: 22, - }, - ], - }); - } catch (error: any) { - expect(error.message).toEqual( - 'Validation failed: must pass "validateTotalSplitRecipients" keyword validation', - ); - } - }); - - test('should throw an error if ObolRAFSplit is less than 0.1', async () => { - try { - await clientInstance.createObolTotalSplit({ - splitRecipients: mockSplitRecipients, - ObolRAFSplit: 0.05, - }); - } catch (error: any) { - expect(error.message).toEqual( - 'Validation failed: must pass "validateTotalSplitRecipients" keyword validation, /ObolRAFSplit must be >= 0.1', - ); - } - }); - - it('should return the correct withdrawal and fee recipient addresses and ObolRAFSplit', async () => { - const result = await clientInstance.createObolTotalSplit({ - splitRecipients: mockSplitRecipients, - ObolRAFSplit: 0.1, + // it('should throw an error if signer is not defined', async () => { + // await expect( + // clientInstanceWithourSigner.createObolTotalSplit({ + // splitRecipients: mockSplitRecipients, + // }), + // ).rejects.toThrow('Signer is required in createObolTotalSplit'); + // }); + + // it('should throw an error if chainId is not supported', async () => { + // const unsupportedSplitterChainClient = new Client( + // { baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 100 }, + // mockSigner, + // ); + + // try { + // await unsupportedSplitterChainClient.createObolTotalSplit({ + // splitRecipients: mockSplitRecipients, + // }); + // } catch (error: any) { + // expect(error.message).toEqual( + // 'Splitter configuration is not supported on 100 chain', + // ); + // } + // }); + + // test('should throw an error on invalid recipients', async () => { + // try { + // await clientInstance.createObolTotalSplit({ + // splitRecipients: [ + // { + // account: '0x86B8145c98e5BD25BA722645b15eD65f024a87EC', + // percentAllocation: 22, + // }, + // ], + // }); + // } catch (error: any) { + // expect(error.message).toEqual( + // 'Validation failed: must pass "validateTotalSplitRecipients" keyword validation', + // ); + // } + // }); + + // test('should throw an error if ObolRAFSplit is less than 0.1', async () => { + // try { + // await clientInstance.createObolTotalSplit({ + // splitRecipients: mockSplitRecipients, + // ObolRAFSplit: 0.05, + // }); + // } catch (error: any) { + // expect(error.message).toEqual( + // 'Validation failed: must pass "validateTotalSplitRecipients" keyword validation, /ObolRAFSplit must be >= 0.1', + // ); + // } + // }); + + // it('should return the correct withdrawal and fee recipient addresses and ObolRAFSplit', async () => { + // const result = await clientInstance.createObolTotalSplit({ + // splitRecipients: mockSplitRecipients, + // ObolRAFSplit: 0.1, + // }); + + // // 0xPredictedAddress and not 0xSplitterAddress since were mocking isContractAvailable response to be true + // expect(result).toEqual({ + // withdrawal_address: '0xPredictedAddress', + // fee_recipient_address: '0xPredictedAddress', + // }); + // }); + + // it('should return the correct withdrawal and fee recipient addresses without passing ObolRAFSplit', async () => { + // const result = await clientInstance.createObolTotalSplit({ + // splitRecipients: mockSplitRecipients, + // }); + + // // 0xPredictedAddress and not 0xSplitterAddress since were mocking isContractAvailable response to be true + // expect(result).toEqual({ + // withdrawal_address: '0xPredictedAddress', + // fee_recipient_address: '0xPredictedAddress', + // }); + // }); + + + + it('hoodi safe signaturee', async () => { + const result = await validateAddressSignature({ + address: "0x485C45dc78Fb2242C7DB12DA0D66960AEB5eB169", + token: "0x35573d3afc655a8b5293a7c448d0d29517e2855b52208a4a41f2578ba7f2fc4804a0da5930dc82865057f3be228f00dafedf2c7b46e920fd5669818478d820e31b", + data: { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + ], + TermsAndConditions: [ + { name: 'terms_and_conditions_hash', type: 'string' }, + { name: 'version', type: 'uint256' }, + ], + }, + primaryType: 'TermsAndConditions', + domain: { + name: 'Obol', + version: '1', + }, + message: { + terms_and_conditions_hash: "0xd33721644e8f3afab1495a74abe3523cec12d48b8da6cb760972492ca3f1a273", + version: 1, + }, + }, + chainId: 560048, }); // 0xPredictedAddress and not 0xSplitterAddress since were mocking isContractAvailable response to be true - expect(result).toEqual({ - withdrawal_address: '0xPredictedAddress', - fee_recipient_address: '0xPredictedAddress', - }); + expect(result).toEqual(true); }); - it('should return the correct withdrawal and fee recipient addresses without passing ObolRAFSplit', async () => { - const result = await clientInstance.createObolTotalSplit({ - splitRecipients: mockSplitRecipients, - }); - // 0xPredictedAddress and not 0xSplitterAddress since were mocking isContractAvailable response to be true - expect(result).toEqual({ - withdrawal_address: '0xPredictedAddress', - fee_recipient_address: '0xPredictedAddress', - }); - }); + + }); diff --git a/test/sdk-package/yarn.lock b/test/sdk-package/yarn.lock index 12457a03..a0ef4dc9 100644 --- a/test/sdk-package/yarn.lock +++ b/test/sdk-package/yarn.lock @@ -614,9 +614,9 @@ chalk "^4.0.0" "@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": - version "0.3.12" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz#2234ce26c62889f03db3d7fea43c1932ab3e927b" - integrity sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg== + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== dependencies: "@jridgewell/sourcemap-codec" "^1.5.0" "@jridgewell/trace-mapping" "^0.3.24" @@ -627,14 +627,14 @@ integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": - version "1.5.4" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz#7358043433b2e5da569aa02cbc4c121da3af27d7" - integrity sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw== + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": - version "0.3.29" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz#a58d31eaadaf92c6695680b2e1d464a9b8fbf7fc" - integrity sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ== + version "0.3.30" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz#4a76c4daeee5df09f5d3940e087442fb36ce2b99" + integrity sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" @@ -1046,9 +1046,9 @@ integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== "@types/node@*", "@types/node@>=13.7.0": - version "24.2.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-24.2.0.tgz#cde712f88c5190006d6b069232582ecd1f94a760" - integrity sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw== + version "24.2.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.2.1.tgz#83e41543f0a518e006594bb394e2cd961de56727" + integrity sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ== dependencies: undici-types "~7.10.0" @@ -1668,12 +1668,12 @@ browserify-aes@^1.2.0: safe-buffer "^5.0.1" browserslist@^4.24.0: - version "4.25.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111" - integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw== + version "4.25.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.2.tgz#90c1507143742d743544ae6e92bca3348adff667" + integrity sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA== dependencies: - caniuse-lite "^1.0.30001726" - electron-to-chromium "^1.5.173" + caniuse-lite "^1.0.30001733" + electron-to-chromium "^1.5.199" node-releases "^2.0.19" update-browserslist-db "^1.1.3" @@ -1815,10 +1815,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001726: - version "1.0.30001731" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz#277c07416ea4613ec564e5b0ffb47e7b60f32e2f" - integrity sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg== +caniuse-lite@^1.0.30001733: + version "1.0.30001734" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001734.tgz#f97e08599e2d75664543ae4b6ef25dc2183c5cc6" + integrity sha512-uhE1Ye5vgqju6OI71HTQqcBCZrvHugk0MjLak7Q+HfoBgoq5Bi+5YnwjP4fjDgrtYr/l8MVRBvzz9dPD4KyK0A== chalk@^4.0.0: version "4.1.2" @@ -2152,10 +2152,10 @@ dunder-proto@^1.0.0, dunder-proto@^1.0.1: es-errors "^1.3.0" gopd "^1.2.0" -electron-to-chromium@^1.5.173: - version "1.5.198" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.198.tgz#ac12b539ac1bb3dece1a4cd2d8882d0349c71c55" - integrity sha512-G5COfnp3w+ydVu80yprgWSfmfQaYRh9DOxfhAxstLyetKaLyl55QrNjx8C38Pc/C+RaDmb1M0Lk8wPEMQ+bGgQ== +electron-to-chromium@^1.5.199: + version "1.5.200" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.200.tgz#adffa5db97390ce9d48987f528117a608ed0d7c9" + integrity sha512-rFCxROw7aOe4uPTfIAx+rXv9cEcGx+buAF4npnhtTqCJk5KDFRnh3+KYj7rdVh6lsFt5/aPs+Irj9rZ33WMA7w== elliptic@^6.5.4, elliptic@^6.5.7: version "6.6.1" @@ -2987,13 +2987,10 @@ internal-slot@^1.1.0: hasown "^2.0.2" side-channel "^1.1.0" -ip-address@^9.0.5: - version "9.0.5" - resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" - integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== - dependencies: - jsbn "1.1.0" - sprintf-js "^1.1.3" +ip-address@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-10.0.1.tgz#a8180b783ce7788777d796286d61bce4276818ed" + integrity sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA== ip-regex@^4.0.0: version "4.3.0" @@ -3694,11 +3691,6 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" -jsbn@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" - integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== - jsesc@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" @@ -4906,11 +4898,11 @@ socks-proxy-agent@^6.0.0: socks "^2.6.2" socks@^2.6.2: - version "2.8.6" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.6.tgz#e335486a2552f34f932f0c27d8dbb93f2be867aa" - integrity sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA== + version "2.8.7" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.7.tgz#e2fb1d9a603add75050a2067db8c381a0b5669ea" + integrity sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A== dependencies: - ip-address "^9.0.5" + ip-address "^10.0.1" smart-buffer "^4.2.0" source-map-support@0.5.13: @@ -4926,11 +4918,6 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -sprintf-js@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" - integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== - sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"