Skip to content

Commit

Permalink
ID-913 ZkEvm provider events
Browse files Browse the repository at this point in the history
  • Loading branch information
haydenfowler committed Jul 21, 2023
1 parent 47bbe3a commit 9c387de
Show file tree
Hide file tree
Showing 20 changed files with 206 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum EthereumParamType {
interface EthereumParam {
name: string;
type?: EthereumParamType;
default?: string;
}

interface EthereumMethod {
Expand All @@ -37,15 +38,15 @@ const EthereumMethods: EthereumMethod[] = [
name: 'eth_getBalance',
params: [
{ name: 'address' },
{ name: 'blockNumber/tag' },
{ name: 'blockNumber/tag', default: 'latest' },
],
},
{
name: 'eth_getStorageAt',
params: [
{ name: 'address' },
{ name: 'position' },
{ name: 'blockNumber' },
{ name: 'blockNumber', default: 'latest' },
],
},
{
Expand All @@ -58,7 +59,7 @@ const EthereumMethods: EthereumMethod[] = [
name: 'eth_call',
params: [
{ name: 'transaction' },
{ name: 'blockNumber/tag' },
{ name: 'blockNumber/tag', default: 'latest' },
],
},
{ name: 'eth_blockNumber' },
Expand Down Expand Up @@ -93,7 +94,6 @@ const EthereumMethods: EthereumMethod[] = [
name: 'eth_getTransactionCount',
params: [
{ name: 'address' },
{ name: 'blockNumber' },
],
},
];
Expand Down Expand Up @@ -147,10 +147,8 @@ function Request({ showRequest, setShowRequest }: RequestProps) {
addMessage(selectedEthMethod?.name, result);
handleClose();
} catch (err) {
if (err instanceof Error) {
addMessage('Request', err);
handleClose();
}
addMessage('Request', err);
handleClose();
}
} else {
setInvalid(true);
Expand All @@ -164,7 +162,7 @@ function Request({ showRequest, setShowRequest }: RequestProps) {
console.error('Invalid eth method');
} else {
setSelectedEthMethod(ethMethod);
setParams(Array(ethMethod.params?.length || 0).fill(''));
setParams(ethMethod.params ? ethMethod.params.map((param) => param.default || '') : []);
}
};

Expand Down Expand Up @@ -199,6 +197,7 @@ function Request({ showRequest, setShowRequest }: RequestProps) {
<Form.Control
key={param.name}
type="text"
value={param.default}
onChange={(e) => {
const newParams = [...params];
newParams[index] = e.target.value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const getPassportConfig = (environment: EnvironmentNames): PassportModuleConfigu
},
}),
zkEvmRpcUrl: 'https://zkevm-rpc.dev.x.immutable.com',
zkEvmChainId: 'eip155:13403',
zkEvmChainId: 'eip155:13413',
relayerUrl: 'https://evm-relayer.dev.imtbl.com',
indexerMrBasePath: 'https://indexer-mr.dev.imtbl.com',
orderBookMrBasePath: 'https://order-book-mr.dev.imtbl.com',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export function PassportProvider({
} finally {
setIsLoading(false);
}
}, [passportClient, setIsLoading]);
}, [addMessage, passportClient, setIsLoading]);

const providerValues = useMemo(() => ({
imxProvider,
Expand Down
7 changes: 7 additions & 0 deletions packages/passport/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ export {
JsonRpcResponsePayload,
JsonRpcRequestCallback,
Provider,
ProviderEventNames,
AccountsChangedEvent,
} from './zkEvm/types';
export {
JsonRpcError,
ProviderErrorCode,
RpcErrorCode,
} from './zkEvm/JsonRpcError';
export {
UserProfile,
Networks,
Expand Down
15 changes: 12 additions & 3 deletions packages/passport/sdk/src/zkEvm/JsonRpcError.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
/**
* ProviderErrors should take priority over RpcErrorCodes
*/
export enum ProviderErrorCode {
USER_REJECTED_REQUEST = 4001,
UNAUTHORIZED = 4100,
UNSUPPORTED_METHOD = 4200,
DISCONNECTED = 4900,
}

export enum RpcErrorCode {
RPC_SERVER_ERROR = -32000,
INVALID_REQUEST = -32600,
METHOD_NOT_FOUND = -32601,
INVALID_PARAMS = -32602,
INTERNAL_ERROR = -32603,
UNAUTHORIZED = -32604,
PARSE_ERROR = -32700,
}

export class JsonRpcError extends Error {
public readonly message: string;

public readonly code: RpcErrorCode;
public readonly code: ProviderErrorCode | RpcErrorCode;

constructor(code: RpcErrorCode, message: string) {
constructor(code: ProviderErrorCode | RpcErrorCode, message: string) {
super(message);
this.message = message;
this.code = code;
Expand Down
1 change: 0 additions & 1 deletion packages/passport/sdk/src/zkEvm/rpcMethods/index.ts

This file was deleted.

13 changes: 0 additions & 13 deletions packages/passport/sdk/src/zkEvm/rpcMethods/types.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { JsonRpcProvider, TransactionRequest } from '@ethersproject/providers';
import { getSignedMetaTransactions } from '../walletHelpers';
import { ethSendTransaction } from './eth_sendTransaction';
import { mockUserZkEvm } from '../../test/mocks';
import { RelayerClient } from '../relayerClient';
import { PassportConfiguration } from '../../config';
import { retryWithDelay } from '../../network/retry';
import { RelayerTransaction, RelayerTransactionStatus } from '../types';
import { JsonRpcError, RpcErrorCode } from '../JsonRpcError';
import { getSignedMetaTransactions } from './walletHelpers';
import { sendTransaction } from './sendTransaction';
import { mockUserZkEvm } from '../test/mocks';
import { RelayerClient } from './relayerClient';
import { PassportConfiguration } from '../config';
import { retryWithDelay } from '../network/retry';
import { RelayerTransaction, RelayerTransactionStatus } from './types';
import { JsonRpcError, RpcErrorCode } from './JsonRpcError';

jest.mock('@ethersproject/providers');
jest.mock('../walletHelpers');
jest.mock('../../network/retry');
jest.mock('./walletHelpers');
jest.mock('../network/retry');

describe('ethSendTransaction', () => {
describe('sendTransaction', () => {
const signedTransaction = 'signedTransaction123';
const signedTransactions = 'signedTransactions123';
const relayerTransactionId = 'relayerTransactionId123';
Expand Down Expand Up @@ -54,7 +54,7 @@ describe('ethSendTransaction', () => {
hash: transactionHash,
} as RelayerTransaction);

const result = await ethSendTransaction({
const result = await sendTransaction({
params: [transactionRequest],
magicProvider,
jsonRpcProvider: jsonRpcProvider as JsonRpcProvider,
Expand All @@ -72,7 +72,7 @@ describe('ethSendTransaction', () => {
status: RelayerTransactionStatus.FAILED,
} as RelayerTransaction);

await expect(ethSendTransaction({
await expect(sendTransaction({
params: [transactionRequest],
magicProvider,
jsonRpcProvider: jsonRpcProvider as JsonRpcProvider,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
import {
ExternalProvider,
JsonRpcProvider,
TransactionRequest,
Web3Provider,
} from '@ethersproject/providers';
import { getNonce, getSignedMetaTransactions, chainIdNumber } from '../walletHelpers';
import { MetaTransaction, RelayerTransactionStatus } from '../types';
import { EthMethodWithAuthParams } from './types';
import { JsonRpcError, RpcErrorCode } from '../JsonRpcError';
import { retryWithDelay } from '../../network/retry';
import { getNonce, getSignedMetaTransactions, chainIdNumber } from './walletHelpers';
import { MetaTransaction, RelayerTransactionStatus } from './types';
import { JsonRpcError, RpcErrorCode } from './JsonRpcError';
import { retryWithDelay } from '../network/retry';
import { PassportConfiguration } from '../config';
import { RelayerClient } from './relayerClient';
import { UserZkEvm } from '../types';

const MAX_TRANSACTION_HASH_RETRIEVAL_RETRIES = 30;
const TRANSACTION_HASH_RETRIEVAL_WAIT = 1000;

export const ethSendTransaction = async ({
export type EthSendTransactionParams = {
magicProvider: ExternalProvider;
jsonRpcProvider: JsonRpcProvider;
config: PassportConfiguration;
relayerClient: RelayerClient;
user: UserZkEvm;
params: Array<any>;
};

export const sendTransaction = async ({
params,
magicProvider,
jsonRpcProvider,
relayerClient,
config,
user,
}: EthMethodWithAuthParams): Promise<string> => {
}: EthSendTransactionParams): Promise<string> => {
const transactionRequest: TransactionRequest = params[0];
if (!transactionRequest.to) {
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'eth_sendTransaction requires a "to" field');
Expand Down
33 changes: 33 additions & 0 deletions packages/passport/sdk/src/zkEvm/typedEventEmitter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import TypedEventEmitter from './typedEventEmitter';

type TestEvents = {
testEvent1: [Array<number>];
testEvent2: [{ id: number }],
};

describe('TypedEventEmitter', () => {
it('should be able to emit and listen to events', () => {
const eventEmitter = new TypedEventEmitter<TestEvents>();

const testEvent1Handler = jest.fn();
const testEvent2Handler = jest.fn();

eventEmitter.on('testEvent1', testEvent1Handler);
eventEmitter.on('testEvent2', testEvent2Handler);

eventEmitter.emit('testEvent1', [1, 2, 3]);
eventEmitter.emit('testEvent2', { id: 1 });

expect(testEvent1Handler).toHaveBeenCalledWith([1, 2, 3]);
expect(testEvent2Handler).toHaveBeenCalledWith({ id: 1 });

eventEmitter.removeListener('testEvent1', testEvent1Handler);
eventEmitter.removeListener('testEvent2', testEvent2Handler);

eventEmitter.emit('testEvent1', [4, 5, 6]);
eventEmitter.emit('testEvent2', { id: 2 });

expect(testEvent1Handler).toHaveBeenCalledTimes(1);
expect(testEvent2Handler).toHaveBeenCalledTimes(1);
});
});
26 changes: 26 additions & 0 deletions packages/passport/sdk/src/zkEvm/typedEventEmitter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { EventEmitter } from 'events';

export default class TypedEventEmitter<TEvents extends Record<string, any>> {
private emitter = new EventEmitter();

emit<TEventName extends keyof TEvents & string>(
eventName: TEventName,
...eventArg: TEvents[TEventName]
) {
this.emitter.emit(eventName, ...(eventArg as []));
}

on<TEventName extends keyof TEvents & string>(
eventName: TEventName,
handler: (...eventArg: TEvents[TEventName]) => void,
) {
this.emitter.on(eventName, handler as any);
}

removeListener<TEventName extends keyof TEvents & string>(
eventName: TEventName,
handler: (...eventArg: TEvents[TEventName]) => void,
) {
this.emitter.removeListener(eventName, handler as any);
}
}
18 changes: 15 additions & 3 deletions packages/passport/sdk/src/zkEvm/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,26 @@ export interface JsonRpcResponsePayload {
}

export type Provider = {
request: (request: RequestArguments) => Promise<any>
request: (request: RequestArguments) => Promise<any>;
sendAsync: (
request: JsonRpcRequestPayload | JsonRpcRequestPayload[],
callback: JsonRpcRequestCallback,
) => void
) => void;
send: (
request: string | JsonRpcRequestPayload | JsonRpcRequestPayload[],
callbackOrParams?: JsonRpcRequestCallback | Array<any>,
callback?: JsonRpcRequestCallback,
) => void
) => void;
on: (event: string, listener: (...args: any[]) => void) => void;
removeListener: (event: string, listener: (...args: any[]) => void) => void;
};

export enum ProviderEventNames {
ACCOUNTS_CHANGED = 'accountsChanged',
}

export type AccountsChangedEvent = Array<string>;

export interface ProviderEvents extends Record<string, any> {
[ProviderEventNames.ACCOUNTS_CHANGED]: [AccountsChangedEvent],
}
2 changes: 2 additions & 0 deletions packages/passport/sdk/src/zkEvm/user/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './registerZkEvmUser';
export * from './loginZkEvmUser';
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { MultiRollupApiClients } from '@imtbl/generated-clients';
import { ExternalProvider } from '@ethersproject/providers';
import { createCounterfactualAddress } from './createCounterfactualAddress';
import { registerZkEvmUser } from './registerZkEvmUser';
import { UserZkEvm } from '../../types';
import AuthManager from '../../authManager';
import { PassportConfiguration } from '../../config';
import MagicAdapter from '../../magicAdapter';

type RegisterZkEvmUserInput = {
type LoginZkEvmUserInput = {
authManager: AuthManager;
config: PassportConfiguration;
magicAdapter: MagicAdapter;
multiRollupApiClients: MultiRollupApiClients;
};

type RegisterZkEvmUserOutput = {
type LoginZkEvmUserOutput = {
user: UserZkEvm;
magicProvider: ExternalProvider;
};

export const registerZkEvmUser = async ({
export const loginZkEvmUser = async ({
authManager,
config,
magicAdapter,
multiRollupApiClients,
}: RegisterZkEvmUserInput): Promise<RegisterZkEvmUserOutput> => {
}: LoginZkEvmUserInput): Promise<LoginZkEvmUserOutput> => {
const user = await authManager.getUser() || await authManager.login();
if (!user.idToken) {
throw new Error('User is missing idToken');
Expand All @@ -36,7 +36,7 @@ export const registerZkEvmUser = async ({

if (!user.zkEvm) {
// Generate counterfactual address and retrieve updated Auth0 user
const userZkevm = await createCounterfactualAddress({
const userZkevm = await registerZkEvmUser({
authManager,
magicProvider,
multiRollupApiClients,
Expand Down
Loading

0 comments on commit 9c387de

Please sign in to comment.