From e6c4e1b48630605b929eef8e5ae17339e92ffa5b Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Tue, 9 Jul 2024 16:59:52 +0200
Subject: [PATCH] feat!(auth): remove eip712
---
packages/taco-auth/src/auth-provider.ts | 12 +-
packages/taco-auth/src/auth-sig.ts | 12 +-
packages/taco-auth/src/helper.ts | 19 ---
packages/taco-auth/src/index.ts | 1 -
packages/taco-auth/src/providers/eip712.ts | 155 ------------------
packages/taco-auth/src/providers/index.ts | 1 -
packages/taco-auth/test/auth-provider.test.ts | 32 +---
packages/taco-auth/test/auth-sig.test.ts | 74 +--------
packages/taco/src/conditions/const.ts | 12 +-
packages/taco/src/conditions/shared.ts | 8 +-
.../test/conditions/base/contract.test.ts | 4 +-
packages/taco/test/conditions/context.test.ts | 58 +------
packages/test-utils/src/utils.ts | 28 ++--
13 files changed, 33 insertions(+), 383 deletions(-)
delete mode 100644 packages/taco-auth/src/helper.ts
delete mode 100644 packages/taco-auth/src/providers/eip712.ts
diff --git a/packages/taco-auth/src/auth-provider.ts b/packages/taco-auth/src/auth-provider.ts
index 18e83d5e6..fbb8d4c64 100644
--- a/packages/taco-auth/src/auth-provider.ts
+++ b/packages/taco-auth/src/auth-provider.ts
@@ -1,30 +1,20 @@
import { AuthSignature } from './auth-sig';
-import { EIP4361AuthProvider, EIP712AuthProvider } from './providers';
+import { EIP4361AuthProvider } from './providers';
-/**
- * @deprecated Use EIP4361_AUTH_METHOD instead.
- */
-export const EIP712_AUTH_METHOD = 'EIP712';
export const EIP4361_AUTH_METHOD = 'EIP4361';
-
export interface AuthProvider {
getOrCreateAuthSignature(): Promise;
}
export type AuthProviders = {
- [EIP712_AUTH_METHOD]?: EIP712AuthProvider;
[EIP4361_AUTH_METHOD]?: EIP4361AuthProvider;
// Fallback to satisfy type checking
[key: string]: AuthProvider | undefined;
};
export const USER_ADDRESS_PARAM_DEFAULT = ':userAddress';
-export const USER_ADDRESS_PARAM_EIP712 = `:userAddress${EIP712_AUTH_METHOD}`;
-export const USER_ADDRESS_PARAM_EIP4361 = `:userAddress${EIP4361_AUTH_METHOD}`;
export const AUTH_METHOD_FOR_PARAM: Record = {
[USER_ADDRESS_PARAM_DEFAULT]: EIP4361_AUTH_METHOD,
- [USER_ADDRESS_PARAM_EIP712]: EIP712_AUTH_METHOD,
- [USER_ADDRESS_PARAM_EIP4361]: EIP4361_AUTH_METHOD,
};
diff --git a/packages/taco-auth/src/auth-sig.ts b/packages/taco-auth/src/auth-sig.ts
index 4e21677b0..5d51d7491 100644
--- a/packages/taco-auth/src/auth-sig.ts
+++ b/packages/taco-auth/src/auth-sig.ts
@@ -1,19 +1,15 @@
import { EthAddressSchema } from '@nucypher/shared';
import { z } from 'zod';
-import { EIP4361_AUTH_METHOD, EIP712_AUTH_METHOD } from './auth-provider';
-import { EIP4361TypedDataSchema, EIP712TypedDataSchema } from './providers';
+import { EIP4361_AUTH_METHOD } from './auth-provider';
+import { EIP4361TypedDataSchema } from './providers';
export const authSignatureSchema = z.object({
signature: z.string(),
address: EthAddressSchema,
- scheme: z.enum([EIP712_AUTH_METHOD, EIP4361_AUTH_METHOD]),
- typedData: z.union([
- EIP4361TypedDataSchema,
- // TODO(#536): Remove post EIP712 deprecation
- EIP712TypedDataSchema,
- ]),
+ scheme: z.enum([EIP4361_AUTH_METHOD]),
+ typedData: EIP4361TypedDataSchema,
});
export type AuthSignature = z.infer;
diff --git a/packages/taco-auth/src/helper.ts b/packages/taco-auth/src/helper.ts
deleted file mode 100644
index 894353afb..000000000
--- a/packages/taco-auth/src/helper.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { ethers } from 'ethers';
-
-import { AuthProviders, EIP4361_AUTH_METHOD, EIP712_AUTH_METHOD } from './auth-provider';
-import {
- EIP4361AuthProvider,
- EIP4361AuthProviderParams,
- EIP712AuthProvider,
-} from './providers';
-
-export const makeAuthProviders = (
- provider: ethers.providers.Provider,
- signer?: ethers.Signer,
- siweDefaultParams?: EIP4361AuthProviderParams,
-): AuthProviders => {
- return {
- [EIP712_AUTH_METHOD]: signer ? new EIP712AuthProvider(provider, signer) : undefined,
- [EIP4361_AUTH_METHOD]: signer ? new EIP4361AuthProvider(provider, signer, siweDefaultParams) : undefined,
- } as AuthProviders;
-};
diff --git a/packages/taco-auth/src/index.ts b/packages/taco-auth/src/index.ts
index a7cb7846a..48718042f 100644
--- a/packages/taco-auth/src/index.ts
+++ b/packages/taco-auth/src/index.ts
@@ -1,4 +1,3 @@
export * from './providers';
-export * from './helper';
export * from './auth-sig';
export * from './auth-provider';
diff --git a/packages/taco-auth/src/providers/eip712.ts b/packages/taco-auth/src/providers/eip712.ts
deleted file mode 100644
index fb554f16a..000000000
--- a/packages/taco-auth/src/providers/eip712.ts
+++ /dev/null
@@ -1,155 +0,0 @@
-import type { TypedDataSigner } from '@ethersproject/abstract-signer';
-import { ethers } from 'ethers';
-import { utils as ethersUtils } from 'ethers/lib/ethers';
-import { z } from 'zod';
-
-import { AuthProvider } from '../auth-provider';
-import { AuthSignature } from '../auth-sig';
-import { LocalStorage } from '../storage';
-
-
-const typeFieldSchema = z.object({
- name: z.string(),
- type: z.string(),
-});
-
-const domain = z.object({
- salt: z.string(),
- chainId: z.number(),
- name: z.string(),
- version: z.string(),
-});
-
-const messageSchema = z.object({
- blockHash: z.string(),
- address: z.string(),
- blockNumber: z.number(),
- signatureText: z.string(),
-});
-
-export const EIP712TypedDataSchema = z.object({
- primaryType: z.literal('Wallet'),
- types: z.object({
- EIP712Domain: z.array(typeFieldSchema),
- Wallet: z.array(typeFieldSchema),
- }),
- domain: domain,
- message: messageSchema,
-});
-
-
-export type EIP712TypedData = z.infer;
-
-interface ChainData {
- blockHash: string;
- chainId: number;
- blockNumber: number;
-}
-
-const EIP712Domain = [
- {
- name: 'name',
- type: 'string',
- },
- {
- name: 'version',
- type: 'string',
- },
- {
- name: 'chainId',
- type: 'uint256',
- },
- {
- name: 'salt',
- type: 'bytes32',
- },
-];
-
-/**
- * @deprecated Use EIP4361AuthProvider instead.
- */
-export class EIP712AuthProvider implements AuthProvider {
- private readonly storage: LocalStorage;
-
- constructor(
- // TODO: We only need the provider to fetch the chainId, consider removing it
- private readonly provider: ethers.providers.Provider,
- private readonly signer: ethers.Signer,
- ) {
- console.warn(
- 'DeprecationWarning: The EIP712AuthProvider authentication provider is deprecated. ' +
- 'Please use EIP4361AuthProvider instead. Refer to the documentation for more details.'
- );
- this.storage = new LocalStorage();
- }
-
- public async getOrCreateAuthSignature(): Promise {
- const address = await this.signer.getAddress();
- const storageKey = `eip712-signature-${address}`;
-
- // If we have a signature in localStorage, return it
- const maybeSignature = this.storage.getAuthSignature(storageKey);
- if (maybeSignature) {
- return maybeSignature;
- }
-
- // If at this point we didn't return, we need to create a new signature
- const authSignature = await this.createAuthMessage();
- this.storage.setAuthSignature(storageKey, authSignature);
- return authSignature;
- }
-
- private async createAuthMessage(): Promise {
- // Ensure freshness of the signature
- const { blockNumber, blockHash, chainId } = await this.getChainData();
- const address = await this.signer.getAddress();
- const signatureText = `I'm the owner of address ${address} as of block number ${blockNumber}`;
- const salt = ethersUtils.hexlify(ethersUtils.randomBytes(32));
-
- const typedData = {
- types: {
- Wallet: [
- { name: 'address', type: 'address' },
- { name: 'signatureText', type: 'string' },
- { name: 'blockNumber', type: 'uint256' },
- { name: 'blockHash', type: 'bytes32' },
- ],
- },
- domain: {
- name: 'TACo',
- version: '1',
- chainId,
- salt,
- },
- message: {
- address,
- signatureText,
- blockNumber,
- blockHash,
- },
- };
- // https://github.com/ethers-io/ethers.js/issues/1431#issuecomment-813950552
- const signature = await (
- this.signer as unknown as TypedDataSigner
- )._signTypedData(typedData.domain, typedData.types, typedData.message);
-
- const formattedTypedData: EIP712TypedData = {
- ...typedData,
- primaryType: 'Wallet',
- types: {
- ...typedData.types,
- EIP712Domain,
- },
- };
- const scheme = 'EIP712';
- return { signature, address, scheme, typedData: formattedTypedData };
- }
-
- private async getChainData(): Promise {
- const blockNumber = await this.provider.getBlockNumber();
- const block = await this.provider.getBlock(blockNumber);
- const blockHash = block.hash;
- const chainId = (await this.provider.getNetwork()).chainId;
- return { blockNumber, blockHash, chainId };
- }
-}
diff --git a/packages/taco-auth/src/providers/index.ts b/packages/taco-auth/src/providers/index.ts
index 6b5476af1..5bc7a7faf 100644
--- a/packages/taco-auth/src/providers/index.ts
+++ b/packages/taco-auth/src/providers/index.ts
@@ -1,2 +1 @@
-export * from './eip712';
export * from './eip4361';
diff --git a/packages/taco-auth/test/auth-provider.test.ts b/packages/taco-auth/test/auth-provider.test.ts
index 1ced7495a..69b5636a1 100644
--- a/packages/taco-auth/test/auth-provider.test.ts
+++ b/packages/taco-auth/test/auth-provider.test.ts
@@ -7,39 +7,9 @@ import {
import { SiweMessage } from 'siwe';
import { describe, expect, it } from 'vitest';
-import {
- EIP4361AuthProvider,
- EIP712AuthProvider,
- EIP712TypedData,
-} from '../src';
+import { EIP4361AuthProvider } from '../src';
describe('auth provider', () => {
- it('creates a new EIP-712 message', async () => {
- const provider = fakeProvider(bobSecretKeyBytes);
- const signer = fakeSigner(bobSecretKeyBytes);
-
- const eip712Provider = new EIP712AuthProvider(provider, signer);
- const eip712Message = await eip712Provider.getOrCreateAuthSignature();
- expect(eip712Message.signature).toBeDefined();
- expect(eip712Message.address).toEqual(await signer.getAddress());
- expect(eip712Message.scheme).toEqual('EIP712');
-
- const typedData = eip712Message.typedData as EIP712TypedData;
- expect(typedData).toBeDefined();
- expect(typedData.types.Wallet).toBeDefined();
- expect(typedData.domain.name).toEqual('TACo');
- expect(typedData.domain.version).toEqual('1');
- expect(typedData.domain.chainId).toEqual(
- (await provider.getNetwork()).chainId,
- );
- expect(typedData.domain.salt).toBeDefined();
- expect(typedData.message.address).toEqual(await signer.getAddress());
- expect(typedData.message.blockNumber).toEqual(
- await provider.getBlockNumber(),
- );
- expect(typedData.message['blockHash']).toBeDefined();
- });
-
it('creates a new SIWE message', async () => {
const provider = fakeProvider(bobSecretKeyBytes);
const signer = fakeSigner(bobSecretKeyBytes);
diff --git a/packages/taco-auth/test/auth-sig.test.ts b/packages/taco-auth/test/auth-sig.test.ts
index 1eabf42fb..cc8eca343 100644
--- a/packages/taco-auth/test/auth-sig.test.ts
+++ b/packages/taco-auth/test/auth-sig.test.ts
@@ -1,67 +1,8 @@
import { describe, expect, it } from 'vitest';
-import {
- authSignatureSchema,
-} from '../src';
+import { authSignatureSchema } from '../src';
+
-const eip712AuthSignature = {
- 'signature': 'fake-typed-signature',
- 'address': '0x0000000000000000000000000000000000000000',
- 'scheme': 'EIP712',
- 'typedData': {
- 'types': {
- 'Wallet': [
- {
- 'name': 'address',
- 'type': 'address',
- },
- {
- 'name': 'signatureText',
- 'type': 'string',
- },
- {
- 'name': 'blockNumber',
- 'type': 'uint256',
- },
- {
- 'name': 'blockHash',
- 'type': 'bytes32',
- },
- ],
- 'EIP712Domain': [
- {
- 'name': 'name',
- 'type': 'string',
- },
- {
- 'name': 'version',
- 'type': 'string',
- },
- {
- 'name': 'chainId',
- 'type': 'uint256',
- },
- {
- 'name': 'salt',
- 'type': 'bytes32',
- },
- ],
- },
- 'domain': {
- 'name': 'TACo',
- 'version': '1',
- 'chainId': 1234,
- 'salt': '0x55d90a3b041db6dda74671bc83a25d1508979b19a105be17f57f86fe08627dbd',
- },
- 'message': {
- 'address': '0x0000000000000000000000000000000000000000',
- 'signatureText': 'I\'m the owner of address 0x0000000000000000000000000000000000000000 as of block number 1000',
- 'blockNumber': 1000,
- 'blockHash': '0x0000000000000000000000000000000000000000',
- },
- 'primaryType': 'Wallet',
- },
-};
const eip4361AuthSignature = {
'signature': 'fake-signature',
'address': '0x0000000000000000000000000000000000000000',
@@ -70,17 +11,6 @@ const eip4361AuthSignature = {
};
describe('auth signature', () => {
- it('accepts a well-formed EIP172 auth signature', async () => {
- authSignatureSchema.parse(eip712AuthSignature);
- });
-
- it('rejects an EIP712 auth signature with missing fields', async () => {
- expect(() => authSignatureSchema.parse({
- ...eip712AuthSignature,
- 'signature': undefined,
- })).toThrow();
- });
-
it('accepts a well-formed EIP4361 auth signature', async () => {
authSignatureSchema.parse(eip4361AuthSignature);
});
diff --git a/packages/taco/src/conditions/const.ts b/packages/taco/src/conditions/const.ts
index 45f25c44c..3cfff3d09 100644
--- a/packages/taco/src/conditions/const.ts
+++ b/packages/taco/src/conditions/const.ts
@@ -1,9 +1,5 @@
-import {ChainId} from '@nucypher/shared';
-import {
- USER_ADDRESS_PARAM_DEFAULT,
- USER_ADDRESS_PARAM_EIP4361,
- USER_ADDRESS_PARAM_EIP712
-} from "@nucypher/taco-auth";
+import { ChainId } from '@nucypher/shared';
+import { USER_ADDRESS_PARAM_DEFAULT } from "@nucypher/taco-auth";
export const USER_ADDRESS_PARAM_EXTERNAL_EIP4361 =
':userAddressExternalEIP4361';
@@ -21,8 +17,6 @@ export const SUPPORTED_CHAIN_IDS = [
];
export const USER_ADDRESS_PARAMS = [
- USER_ADDRESS_PARAM_EIP712,
- USER_ADDRESS_PARAM_EIP4361,
USER_ADDRESS_PARAM_EXTERNAL_EIP4361,
// Ordering matters, this should always be last
USER_ADDRESS_PARAM_DEFAULT,
@@ -30,7 +24,5 @@ export const USER_ADDRESS_PARAMS = [
export const RESERVED_CONTEXT_PARAMS = [
USER_ADDRESS_PARAM_DEFAULT,
- USER_ADDRESS_PARAM_EIP712,
- USER_ADDRESS_PARAM_EIP4361,
// USER_ADDRESS_PARAM_EXTERNAL_EIP4361 is not reserved and can be used as a custom context parameter
];
diff --git a/packages/taco/src/conditions/shared.ts b/packages/taco/src/conditions/shared.ts
index 7f4a63e77..025bbdf6b 100644
--- a/packages/taco/src/conditions/shared.ts
+++ b/packages/taco/src/conditions/shared.ts
@@ -1,9 +1,5 @@
import { EthAddressSchema } from '@nucypher/shared';
-import {
- USER_ADDRESS_PARAM_DEFAULT,
- USER_ADDRESS_PARAM_EIP4361,
- USER_ADDRESS_PARAM_EIP712
-} from "@nucypher/taco-auth";
+import { USER_ADDRESS_PARAM_DEFAULT } from "@nucypher/taco-auth";
import { z } from 'zod';
import {
@@ -40,8 +36,6 @@ export const returnValueTestSchema = z.object({
export type ReturnValueTestProps = z.infer;
const UserAddressSchema = z.enum([
- USER_ADDRESS_PARAM_EIP712,
- USER_ADDRESS_PARAM_EIP4361,
USER_ADDRESS_PARAM_DEFAULT,
]);
export const EthAddressOrUserAddressSchema = z.union([
diff --git a/packages/taco/test/conditions/base/contract.test.ts b/packages/taco/test/conditions/base/contract.test.ts
index aec30a6dd..8ab390791 100644
--- a/packages/taco/test/conditions/base/contract.test.ts
+++ b/packages/taco/test/conditions/base/contract.test.ts
@@ -1,6 +1,6 @@
import { initialize } from '@nucypher/nucypher-core';
-import {USER_ADDRESS_PARAM_DEFAULT} from "@nucypher/taco-auth";
-import { fakeAuthProviders} from '@nucypher/test-utils';
+import { USER_ADDRESS_PARAM_DEFAULT } from '@nucypher/taco-auth';
+import { fakeAuthProviders } from '@nucypher/test-utils';
import { beforeAll, describe, expect, it } from 'vitest';
import {
diff --git a/packages/taco/test/conditions/context.test.ts b/packages/taco/test/conditions/context.test.ts
index 5120a8685..673ed3db3 100644
--- a/packages/taco/test/conditions/context.test.ts
+++ b/packages/taco/test/conditions/context.test.ts
@@ -4,16 +4,9 @@ import {
AuthSignature,
EIP4361_AUTH_METHOD,
EIP4361AuthProvider,
- EIP712AuthProvider,
- EIP712TypedData,
- makeAuthProviders,
} from '@nucypher/taco-auth';
-import {
- USER_ADDRESS_PARAM_DEFAULT,
- USER_ADDRESS_PARAM_EIP4361,
- USER_ADDRESS_PARAM_EIP712
-} from "@nucypher/taco-auth";
-import { fakeAuthProviders, fakeProvider, fakeSigner, TEST_SIWE_PARAMS } from '@nucypher/test-utils';
+import { USER_ADDRESS_PARAM_DEFAULT } from "@nucypher/taco-auth";
+import { fakeAuthProviders, fakeProvider, fakeSigner } from '@nucypher/test-utils';
import { ethers } from 'ethers';
import { beforeAll, describe, expect, it, vi } from 'vitest';
@@ -316,7 +309,7 @@ describe('No authentication provider', () => {
await initialize();
provider = fakeProvider();
signer = fakeSigner();
- authProviders = makeAuthProviders(provider, signer, TEST_SIWE_PARAMS);
+ authProviders = fakeAuthProviders();
});
it('throws an error if there is no auth provider', () => {
@@ -351,22 +344,6 @@ describe('No authentication provider', () => {
).not.toThrow();
});
- it('supports multiple providers when needed', () => {
- const conditionObj = {
- ...testContractConditionObj,
- returnValueTest: {
- ...testReturnValueTest,
- // TODO: Is it supposed to work? Multiple providers at the same time?
- value: [USER_ADDRESS_PARAM_EIP712, USER_ADDRESS_PARAM_EIP4361],
- },
- };
- const condition = new ContractCondition(conditionObj);
- const conditionExpr = new ConditionExpression(condition);
- expect(() =>
- conditionExpr.buildContext( {}, authProviders),
- ).not.toThrow();
- });
-
async function makeAuthSignature(authMethod: string) {
const conditionObj = {
...testContractConditionObj,
@@ -386,25 +363,6 @@ describe('No authentication provider', () => {
return authSignature;
}
- async function testEIP712AuthMethod(authMethod: string) {
- const eip712Spy = vi.spyOn(
- EIP712AuthProvider.prototype,
- 'getOrCreateAuthSignature',
- );
-
- const authSignature = await makeAuthSignature(authMethod);
- expect(authSignature).toBeDefined();
- expect(authSignature.signature).toBeDefined();
- expect(authSignature.scheme).toEqual('EIP712');
- expect(authSignature.address).toEqual(await signer.getAddress());
-
- const typedData = authSignature.typedData as EIP712TypedData;
- expect(typedData).toBeDefined();
- expect(typedData.domain.name).toEqual('TACo');
- expect(typedData.message.address).toEqual(await signer.getAddress());
- expect(eip712Spy).toHaveBeenCalledOnce();
- }
-
async function testEIP4361AuthMethod(authMethod: string) {
const eip4361Spy = vi.spyOn(
EIP4361AuthProvider.prototype,
@@ -419,17 +377,9 @@ describe('No authentication provider', () => {
await testEIP4361AuthMethod(USER_ADDRESS_PARAM_DEFAULT);
});
- it('supports eip712', async () => {
- await testEIP712AuthMethod(USER_ADDRESS_PARAM_EIP712);
- });
-
- it('supports eip4361', async () => {
- await testEIP4361AuthMethod(USER_ADDRESS_PARAM_EIP4361);
- });
-
it('supports reusing external eip4361', async () => {
// Because we are reusing an existing SIWE auth message, we have to pass it as a custom parameter
- const authMessage = await makeAuthSignature(USER_ADDRESS_PARAM_EIP4361);
+ const authMessage = await makeAuthSignature(USER_ADDRESS_PARAM_DEFAULT);
const customParams: Record = {
[USER_ADDRESS_PARAM_EXTERNAL_EIP4361]: authMessage as CustomContextParam,
};
diff --git a/packages/test-utils/src/utils.ts b/packages/test-utils/src/utils.ts
index c72822466..b5d830a07 100644
--- a/packages/test-utils/src/utils.ts
+++ b/packages/test-utils/src/utils.ts
@@ -39,7 +39,7 @@ import {
Ursula,
zip,
} from '@nucypher/shared';
-import {makeAuthProviders} from "@nucypher/taco-auth";
+import { EIP4361_AUTH_METHOD, EIP4361AuthProvider } from '@nucypher/taco-auth';
import axios from 'axios';
import { ethers, providers, Wallet } from 'ethers';
import { expect, SpyInstance, vi } from 'vitest';
@@ -58,7 +58,7 @@ export const fakePorterUri = 'https://_this_should_crash.com/';
const makeFakeProvider = (
timestamp: number,
blockNumber: number,
- blockHash: string
+ blockHash: string,
) => {
const block = { timestamp, hash: blockHash };
return {
@@ -86,7 +86,11 @@ export const fakeSigner = (
} as unknown as ethers.providers.JsonRpcSigner;
};
-export const fakeAuthProviders = () => makeAuthProviders(fakeProvider(), fakeSigner(), TEST_SIWE_PARAMS);
+export const fakeAuthProviders = () => {
+ return {
+ [EIP4361_AUTH_METHOD]: new EIP4361AuthProvider(fakeProvider(), fakeSigner(), TEST_SIWE_PARAMS),
+ };
+};
export const fakeProvider = (
secretKeyBytes = SecretKey.random().toBEBytes(),
@@ -254,15 +258,15 @@ interface FakeDkgRitualFlow {
}
export const fakeTDecFlow = ({
- validators,
- validatorKeypairs,
- ritualId,
- sharesNum,
- threshold,
- receivedMessages,
- message,
- thresholdMessageKit,
-}: FakeDkgRitualFlow) => {
+ validators,
+ validatorKeypairs,
+ ritualId,
+ sharesNum,
+ threshold,
+ receivedMessages,
+ message,
+ thresholdMessageKit,
+ }: FakeDkgRitualFlow) => {
// Having aggregated the transcripts, the validators can now create decryption shares
const decryptionShares: DecryptionShareSimple[] = [];
zip(validators, validatorKeypairs).forEach(([validator, keypair]) => {