@imtbl/wallet 2.10.7-alpha.2
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/.eslintrc.cjs +18 -0
- package/LICENSE.md +176 -0
- package/dist/browser/index.mjs +21 -0
- package/dist/node/index.js +71 -0
- package/dist/node/index.mjs +22 -0
- package/dist/types/config.d.ts +13 -0
- package/dist/types/errors.d.ts +14 -0
- package/dist/types/guardian/index.d.ts +57 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/magic/index.d.ts +1 -0
- package/dist/types/magic/magicTEESigner.d.ts +24 -0
- package/dist/types/network/chains.d.ts +32 -0
- package/dist/types/network/constants.d.ts +3 -0
- package/dist/types/network/retry.d.ts +8 -0
- package/dist/types/provider/eip6963.d.ts +3 -0
- package/dist/types/types.d.ts +163 -0
- package/dist/types/utils/metrics.d.ts +3 -0
- package/dist/types/utils/string.d.ts +1 -0
- package/dist/types/utils/typedEventEmitter.d.ts +6 -0
- package/dist/types/zkEvm/JsonRpcError.d.ts +25 -0
- package/dist/types/zkEvm/index.d.ts +2 -0
- package/dist/types/zkEvm/personalSign.d.ts +15 -0
- package/dist/types/zkEvm/provider/eip6963.d.ts +3 -0
- package/dist/types/zkEvm/relayerClient.d.ts +60 -0
- package/dist/types/zkEvm/sendDeployTransactionAndPersonalSign.d.ts +6 -0
- package/dist/types/zkEvm/sendTransaction.d.ts +6 -0
- package/dist/types/zkEvm/sessionActivity/errorBoundary.d.ts +1 -0
- package/dist/types/zkEvm/sessionActivity/request.d.ts +15 -0
- package/dist/types/zkEvm/sessionActivity/sessionActivity.d.ts +2 -0
- package/dist/types/zkEvm/signEjectionTransaction.d.ts +6 -0
- package/dist/types/zkEvm/signTypedDataV4.d.ts +14 -0
- package/dist/types/zkEvm/transactionHelpers.d.ts +31 -0
- package/dist/types/zkEvm/types.d.ts +120 -0
- package/dist/types/zkEvm/user/index.d.ts +1 -0
- package/dist/types/zkEvm/user/registerZkEvmUser.d.ts +13 -0
- package/dist/types/zkEvm/walletHelpers.d.ts +33 -0
- package/dist/types/zkEvm/zkEvmProvider.d.ts +25 -0
- package/package.json +55 -0
- package/src/config.ts +51 -0
- package/src/errors.ts +33 -0
- package/src/guardian/index.ts +358 -0
- package/src/index.ts +27 -0
- package/src/magic/index.ts +1 -0
- package/src/magic/magicTEESigner.ts +214 -0
- package/src/network/chains.ts +33 -0
- package/src/network/constants.ts +28 -0
- package/src/network/retry.ts +37 -0
- package/src/provider/eip6963.ts +25 -0
- package/src/types.ts +192 -0
- package/src/utils/metrics.ts +57 -0
- package/src/utils/string.ts +12 -0
- package/src/utils/typedEventEmitter.ts +26 -0
- package/src/zkEvm/JsonRpcError.ts +33 -0
- package/src/zkEvm/index.ts +2 -0
- package/src/zkEvm/personalSign.ts +62 -0
- package/src/zkEvm/provider/eip6963.ts +25 -0
- package/src/zkEvm/relayerClient.ts +216 -0
- package/src/zkEvm/sendDeployTransactionAndPersonalSign.ts +44 -0
- package/src/zkEvm/sendTransaction.ts +34 -0
- package/src/zkEvm/sessionActivity/errorBoundary.ts +33 -0
- package/src/zkEvm/sessionActivity/request.ts +62 -0
- package/src/zkEvm/sessionActivity/sessionActivity.ts +140 -0
- package/src/zkEvm/signEjectionTransaction.ts +33 -0
- package/src/zkEvm/signTypedDataV4.ts +103 -0
- package/src/zkEvm/transactionHelpers.ts +295 -0
- package/src/zkEvm/types.ts +136 -0
- package/src/zkEvm/user/index.ts +1 -0
- package/src/zkEvm/user/registerZkEvmUser.ts +75 -0
- package/src/zkEvm/walletHelpers.ts +243 -0
- package/src/zkEvm/zkEvmProvider.ts +453 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MultiRollupApiClients } from '@imtbl/generated-clients';
|
|
2
|
+
import { Signer } from 'ethers';
|
|
3
|
+
import { Provider, RequestArguments } from './types';
|
|
4
|
+
import { AuthManager } from '@imtbl/auth';
|
|
5
|
+
import TypedEventEmitter from '../utils/typedEventEmitter';
|
|
6
|
+
import { WalletConfiguration } from '../config';
|
|
7
|
+
import { PassportEventMap, User } from '../types';
|
|
8
|
+
import GuardianClient from '../guardian';
|
|
9
|
+
export type ZkEvmProviderInput = {
|
|
10
|
+
authManager: AuthManager;
|
|
11
|
+
config: WalletConfiguration;
|
|
12
|
+
multiRollupApiClients: MultiRollupApiClients;
|
|
13
|
+
passportEventEmitter: TypedEventEmitter<PassportEventMap>;
|
|
14
|
+
guardianClient: GuardianClient;
|
|
15
|
+
ethSigner: Signer;
|
|
16
|
+
user: User | null;
|
|
17
|
+
};
|
|
18
|
+
export declare class ZkEvmProvider implements Provider {
|
|
19
|
+
#private;
|
|
20
|
+
readonly isPassport: boolean;
|
|
21
|
+
constructor({ authManager, config, multiRollupApiClients, passportEventEmitter, guardianClient, ethSigner, user, }: ZkEvmProviderInput);
|
|
22
|
+
request(request: RequestArguments): Promise<any>;
|
|
23
|
+
on(event: string, listener: (...args: any[]) => void): void;
|
|
24
|
+
removeListener(event: string, listener: (...args: any[]) => void): void;
|
|
25
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@imtbl/wallet",
|
|
3
|
+
"version": "2.10.7-alpha.2",
|
|
4
|
+
"description": "Wallet SDK for Immutable",
|
|
5
|
+
"author": "Immutable",
|
|
6
|
+
"bugs": "https://github.com/immutable/ts-immutable-sdk/issues",
|
|
7
|
+
"homepage": "https://github.com/immutable/ts-immutable-sdk#readme",
|
|
8
|
+
"license": "Apache-2.0",
|
|
9
|
+
"main": "dist/node/index.js",
|
|
10
|
+
"module": "dist/node/index.mjs",
|
|
11
|
+
"types": "dist/types/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/types/index.d.ts",
|
|
15
|
+
"import": {
|
|
16
|
+
"browser": "./dist/browser/index.mjs",
|
|
17
|
+
"default": "./dist/node/index.mjs"
|
|
18
|
+
},
|
|
19
|
+
"require": "./dist/node/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@0xsequence/abi": "^2.0.25",
|
|
24
|
+
"@0xsequence/core": "^2.0.25",
|
|
25
|
+
"@imtbl/auth": "2.10.7-alpha.2",
|
|
26
|
+
"@imtbl/config": "2.10.7-alpha.2",
|
|
27
|
+
"@imtbl/generated-clients": "2.10.7-alpha.2",
|
|
28
|
+
"@imtbl/metrics": "2.10.7-alpha.2",
|
|
29
|
+
"@magic-ext/oidc": "12.0.5",
|
|
30
|
+
"@magic-sdk/provider": "^29.0.5",
|
|
31
|
+
"@metamask/detect-provider": "^2.0.0",
|
|
32
|
+
"axios": "^1.6.5",
|
|
33
|
+
"ethers": "^6.13.4",
|
|
34
|
+
"uuid": "^9.0.1"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@imtbl/toolkit": "2.10.7-alpha.2",
|
|
38
|
+
"@types/node": "^18.14.2",
|
|
39
|
+
"@types/uuid": "^8.3.4",
|
|
40
|
+
"tsup": "^8.3.0",
|
|
41
|
+
"typescript": "^5.6.2"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"repository": "immutable/ts-immutable-sdk.git",
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "pnpm transpile && pnpm typegen",
|
|
49
|
+
"transpile": "tsup src/index.ts --config ../../tsup.config.js",
|
|
50
|
+
"typegen": "tsc --customConditions default --emitDeclarationOnly --outDir dist/types",
|
|
51
|
+
"pack:root": "pnpm pack --pack-destination $(dirname $(pnpm root -w))",
|
|
52
|
+
"lint": "eslint ./src --ext .ts,.jsx,.tsx --max-warnings=0",
|
|
53
|
+
"typecheck": "tsc --customConditions default --noEmit --jsx preserve"
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Environment } from '@imtbl/config';
|
|
2
|
+
import { WalletModuleConfiguration } from './types';
|
|
3
|
+
|
|
4
|
+
export class WalletConfiguration {
|
|
5
|
+
readonly environment: Environment;
|
|
6
|
+
|
|
7
|
+
readonly passportDomain: string;
|
|
8
|
+
|
|
9
|
+
readonly zkEvmRpcUrl: string;
|
|
10
|
+
|
|
11
|
+
readonly relayerUrl: string;
|
|
12
|
+
|
|
13
|
+
readonly indexerMrBasePath: string;
|
|
14
|
+
|
|
15
|
+
readonly jsonRpcReferrer?: string;
|
|
16
|
+
|
|
17
|
+
readonly forceScwDeployBeforeMessageSignature: boolean;
|
|
18
|
+
|
|
19
|
+
readonly crossSdkBridgeEnabled: boolean;
|
|
20
|
+
|
|
21
|
+
constructor(config: WalletModuleConfiguration) {
|
|
22
|
+
this.environment = config.baseConfig.environment;
|
|
23
|
+
this.jsonRpcReferrer = config.jsonRpcReferrer;
|
|
24
|
+
this.forceScwDeployBeforeMessageSignature = config.forceScwDeployBeforeMessageSignature || false;
|
|
25
|
+
this.crossSdkBridgeEnabled = config.crossSdkBridgeEnabled || false;
|
|
26
|
+
|
|
27
|
+
if (config.overrides) {
|
|
28
|
+
this.passportDomain = config.overrides.passportDomain;
|
|
29
|
+
this.zkEvmRpcUrl = config.overrides.zkEvmRpcUrl;
|
|
30
|
+
this.relayerUrl = config.overrides.relayerUrl;
|
|
31
|
+
this.indexerMrBasePath = config.overrides.indexerMrBasePath;
|
|
32
|
+
} else {
|
|
33
|
+
switch (config.baseConfig.environment) {
|
|
34
|
+
case Environment.PRODUCTION:
|
|
35
|
+
this.passportDomain = 'https://passport.immutable.com';
|
|
36
|
+
this.zkEvmRpcUrl = 'https://rpc.immutable.com';
|
|
37
|
+
this.relayerUrl = 'https://api.immutable.com/relayer-mr';
|
|
38
|
+
this.indexerMrBasePath = 'https://api.immutable.com';
|
|
39
|
+
break;
|
|
40
|
+
case Environment.SANDBOX:
|
|
41
|
+
this.passportDomain = 'https://passport.sandbox.immutable.com';
|
|
42
|
+
this.zkEvmRpcUrl = 'https://rpc.testnet.immutable.com';
|
|
43
|
+
this.relayerUrl = 'https://api.sandbox.immutable.com/relayer-mr';
|
|
44
|
+
this.indexerMrBasePath = 'https://api.sandbox.immutable.com';
|
|
45
|
+
break;
|
|
46
|
+
default:
|
|
47
|
+
throw new Error(`Unsupported environment: ${config.baseConfig.environment}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export enum WalletErrorType {
|
|
2
|
+
WALLET_CONNECTION_ERROR = 'WALLET_CONNECTION_ERROR',
|
|
3
|
+
TRANSACTION_REJECTED = 'TRANSACTION_REJECTED',
|
|
4
|
+
INVALID_CONFIGURATION = 'INVALID_CONFIGURATION',
|
|
5
|
+
UNAUTHORIZED = 'UNAUTHORIZED',
|
|
6
|
+
GUARDIAN_ERROR = 'GUARDIAN_ERROR',
|
|
7
|
+
SERVICE_UNAVAILABLE_ERROR = 'SERVICE_UNAVAILABLE_ERROR',
|
|
8
|
+
NOT_LOGGED_IN_ERROR = 'NOT_LOGGED_IN_ERROR',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class WalletError extends Error {
|
|
12
|
+
readonly type: WalletErrorType;
|
|
13
|
+
|
|
14
|
+
constructor(message: string, type: WalletErrorType) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'WalletError';
|
|
17
|
+
this.type = type;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function withWalletError<T>(
|
|
22
|
+
fn: () => Promise<T>,
|
|
23
|
+
defaultErrorType: WalletErrorType,
|
|
24
|
+
): Promise<T> {
|
|
25
|
+
try {
|
|
26
|
+
return await fn();
|
|
27
|
+
} catch (err: any) {
|
|
28
|
+
if (err instanceof WalletError) {
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
throw new WalletError(err?.message ?? 'Unknown error', defaultErrorType);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import * as GeneratedClients from '@imtbl/generated-clients';
|
|
2
|
+
import { BigNumberish, ZeroAddress } from 'ethers';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import { AuthManager, ConfirmationScreen } from '@imtbl/auth';
|
|
5
|
+
import { retryWithDelay } from '../network/retry';
|
|
6
|
+
import { JsonRpcError, ProviderErrorCode, RpcErrorCode } from '../zkEvm/JsonRpcError';
|
|
7
|
+
import { MetaTransaction, TypedDataPayload } from '../zkEvm/types';
|
|
8
|
+
import { WalletConfiguration } from '../config';
|
|
9
|
+
import { getEip155ChainId } from '../zkEvm/walletHelpers';
|
|
10
|
+
import { WalletError, WalletErrorType } from '../errors';
|
|
11
|
+
|
|
12
|
+
export type GuardianClientParams = {
|
|
13
|
+
confirmationScreen: ConfirmationScreen;
|
|
14
|
+
config: WalletConfiguration;
|
|
15
|
+
authManager: AuthManager;
|
|
16
|
+
guardianApi: GeneratedClients.mr.GuardianApi;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type GuardianEvaluateImxTransactionParams = {
|
|
20
|
+
payloadHash: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type GuardianEVMTxnEvaluationParams = {
|
|
24
|
+
chainId: string;
|
|
25
|
+
nonce: string;
|
|
26
|
+
metaTransactions: MetaTransaction[];
|
|
27
|
+
isBackgroundTransaction?: boolean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type GuardianEIP712MessageEvaluationParams = {
|
|
31
|
+
chainID: string;
|
|
32
|
+
payload: TypedDataPayload;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type GuardianERC191MessageEvaluationParams = {
|
|
36
|
+
chainID: bigint;
|
|
37
|
+
payload: string;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const transactionRejectedCrossSdkBridgeError = 'Transaction requires confirmation but this functionality is not'
|
|
41
|
+
+ ' supported in this environment. Please contact Immutable support if you need to enable this feature.';
|
|
42
|
+
|
|
43
|
+
export const convertBigNumberishToString = (
|
|
44
|
+
value: BigNumberish,
|
|
45
|
+
): string => BigInt(value).toString();
|
|
46
|
+
|
|
47
|
+
const transformGuardianTransactions = (
|
|
48
|
+
txs: MetaTransaction[],
|
|
49
|
+
): GeneratedClients.mr.MetaTransaction[] => {
|
|
50
|
+
try {
|
|
51
|
+
return txs.map((t) => ({
|
|
52
|
+
delegateCall: t.delegateCall === true,
|
|
53
|
+
revertOnError: t.revertOnError === true,
|
|
54
|
+
gasLimit: t.gasLimit ? convertBigNumberishToString(t.gasLimit) : '0',
|
|
55
|
+
target: t.to ?? ZeroAddress,
|
|
56
|
+
value: t.value ? convertBigNumberishToString(t.value) : '0',
|
|
57
|
+
data: t.data ? t.data.toString() : '0x',
|
|
58
|
+
}));
|
|
59
|
+
} catch (error) {
|
|
60
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
61
|
+
throw new JsonRpcError(
|
|
62
|
+
RpcErrorCode.INVALID_PARAMS,
|
|
63
|
+
`Transaction failed to parsing: ${errorMessage}`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default class GuardianClient {
|
|
69
|
+
private readonly guardianApi: GeneratedClients.mr.GuardianApi;
|
|
70
|
+
|
|
71
|
+
private readonly confirmationScreen: ConfirmationScreen;
|
|
72
|
+
|
|
73
|
+
private readonly crossSdkBridgeEnabled: boolean;
|
|
74
|
+
|
|
75
|
+
private readonly authManager: AuthManager;
|
|
76
|
+
|
|
77
|
+
constructor({
|
|
78
|
+
confirmationScreen, config, authManager, guardianApi,
|
|
79
|
+
}: GuardianClientParams) {
|
|
80
|
+
this.confirmationScreen = confirmationScreen;
|
|
81
|
+
this.crossSdkBridgeEnabled = config.crossSdkBridgeEnabled;
|
|
82
|
+
this.guardianApi = guardianApi;
|
|
83
|
+
this.authManager = authManager;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Open confirmation screen and close it automatically if the
|
|
88
|
+
* underlying task fails.
|
|
89
|
+
*/
|
|
90
|
+
public withConfirmationScreen(popupWindowSize?: {
|
|
91
|
+
width: number;
|
|
92
|
+
height: number;
|
|
93
|
+
}) {
|
|
94
|
+
return <T>(task: () => Promise<T>): Promise<T> => this.withConfirmationScreenTask(popupWindowSize)(task)();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public withConfirmationScreenTask(popupWindowSize?: {
|
|
98
|
+
width: number;
|
|
99
|
+
height: number;
|
|
100
|
+
}) {
|
|
101
|
+
return <T>(task: () => Promise<T>): (() => Promise<T>) => async () => {
|
|
102
|
+
this.confirmationScreen.loading(popupWindowSize);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
return await task();
|
|
106
|
+
} catch (err) {
|
|
107
|
+
if (err instanceof WalletError && err.type === WalletErrorType.SERVICE_UNAVAILABLE_ERROR) {
|
|
108
|
+
await this.confirmationScreen.showServiceUnavailable();
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.confirmationScreen.closeWindow();
|
|
113
|
+
throw err;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public withDefaultConfirmationScreenTask<T>(task: () => Promise<T>): (() => Promise<T>) {
|
|
119
|
+
return this.withConfirmationScreenTask()(task);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public async evaluateImxTransaction({ payloadHash }: GuardianEvaluateImxTransactionParams): Promise<void> {
|
|
123
|
+
try {
|
|
124
|
+
const finallyFn = () => {
|
|
125
|
+
this.confirmationScreen.closeWindow();
|
|
126
|
+
};
|
|
127
|
+
const user = await this.authManager.getUserImx();
|
|
128
|
+
|
|
129
|
+
const headers = { Authorization: `Bearer ${user.accessToken}` };
|
|
130
|
+
const transactionRes = await retryWithDelay(
|
|
131
|
+
async () => this.guardianApi.getTransactionByID({
|
|
132
|
+
transactionID: payloadHash,
|
|
133
|
+
chainType: 'starkex',
|
|
134
|
+
}, { headers }),
|
|
135
|
+
{ finallyFn },
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
if (!transactionRes.data.id) {
|
|
139
|
+
throw new Error("Transaction doesn't exists");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const evaluateImxRes = await this.guardianApi.evaluateTransaction({
|
|
143
|
+
id: payloadHash,
|
|
144
|
+
transactionEvaluationRequest: {
|
|
145
|
+
chainType: 'starkex',
|
|
146
|
+
},
|
|
147
|
+
}, { headers });
|
|
148
|
+
|
|
149
|
+
const { confirmationRequired } = evaluateImxRes.data;
|
|
150
|
+
if (confirmationRequired) {
|
|
151
|
+
if (this.crossSdkBridgeEnabled) {
|
|
152
|
+
throw new Error(transactionRejectedCrossSdkBridgeError);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const confirmationResult = await this.confirmationScreen.requestConfirmation(
|
|
156
|
+
payloadHash,
|
|
157
|
+
user.imx.ethAddress,
|
|
158
|
+
GeneratedClients.mr.TransactionApprovalRequestChainTypeEnum.Starkex,
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
if (!confirmationResult.confirmed) {
|
|
162
|
+
throw new Error('Transaction rejected by user');
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
this.confirmationScreen.closeWindow();
|
|
166
|
+
}
|
|
167
|
+
} catch (error) {
|
|
168
|
+
if (axios.isAxiosError(error) && error.response?.status === 403) {
|
|
169
|
+
throw new WalletError('Service unavailable', WalletErrorType.SERVICE_UNAVAILABLE_ERROR);
|
|
170
|
+
}
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private async evaluateEVMTransaction({
|
|
176
|
+
chainId,
|
|
177
|
+
nonce,
|
|
178
|
+
metaTransactions,
|
|
179
|
+
}: GuardianEVMTxnEvaluationParams): Promise<GeneratedClients.mr.TransactionEvaluationResponse> {
|
|
180
|
+
const user = await this.authManager.getUserZkEvm();
|
|
181
|
+
const headers = { Authorization: `Bearer ${user.accessToken}` };
|
|
182
|
+
const guardianTransactions = transformGuardianTransactions(metaTransactions);
|
|
183
|
+
try {
|
|
184
|
+
const response = await this.guardianApi.evaluateTransaction(
|
|
185
|
+
{
|
|
186
|
+
id: 'evm',
|
|
187
|
+
transactionEvaluationRequest: {
|
|
188
|
+
chainType: 'evm',
|
|
189
|
+
chainId,
|
|
190
|
+
transactionData: {
|
|
191
|
+
nonce,
|
|
192
|
+
userAddress: user.zkEvm.ethAddress,
|
|
193
|
+
metaTransactions: guardianTransactions,
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
{ headers },
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
return response.data;
|
|
201
|
+
} catch (error) {
|
|
202
|
+
if (axios.isAxiosError(error) && error.response?.status === 403) {
|
|
203
|
+
throw new WalletError('Service unavailable', WalletErrorType.SERVICE_UNAVAILABLE_ERROR);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
207
|
+
throw new JsonRpcError(
|
|
208
|
+
RpcErrorCode.INTERNAL_ERROR,
|
|
209
|
+
`Transaction failed to validate with error: ${errorMessage}`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public async validateEVMTransaction({
|
|
215
|
+
chainId,
|
|
216
|
+
nonce,
|
|
217
|
+
metaTransactions,
|
|
218
|
+
isBackgroundTransaction,
|
|
219
|
+
}: GuardianEVMTxnEvaluationParams): Promise<void> {
|
|
220
|
+
const transactionEvaluationResponse = await this.evaluateEVMTransaction({
|
|
221
|
+
chainId,
|
|
222
|
+
nonce,
|
|
223
|
+
metaTransactions,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const { confirmationRequired, transactionId } = transactionEvaluationResponse;
|
|
227
|
+
if (confirmationRequired && this.crossSdkBridgeEnabled) {
|
|
228
|
+
throw new JsonRpcError(
|
|
229
|
+
RpcErrorCode.TRANSACTION_REJECTED,
|
|
230
|
+
transactionRejectedCrossSdkBridgeError,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (confirmationRequired && !!transactionId) {
|
|
235
|
+
const user = await this.authManager.getUserZkEvm();
|
|
236
|
+
const confirmationResult = await this.confirmationScreen.requestConfirmation(
|
|
237
|
+
transactionId,
|
|
238
|
+
user.zkEvm.ethAddress,
|
|
239
|
+
GeneratedClients.mr.TransactionApprovalRequestChainTypeEnum.Evm,
|
|
240
|
+
chainId,
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
if (!confirmationResult.confirmed) {
|
|
244
|
+
throw new JsonRpcError(
|
|
245
|
+
RpcErrorCode.TRANSACTION_REJECTED,
|
|
246
|
+
'Transaction rejected by user',
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
// This verification is meant to ensure that it originates from zkEvmProvider#callSessionActivity
|
|
250
|
+
// and since it's a background transaction should not close the confirmation screen window.
|
|
251
|
+
} else if (!isBackgroundTransaction) {
|
|
252
|
+
this.confirmationScreen.closeWindow();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
private async handleEIP712MessageEvaluation(
|
|
257
|
+
{ chainID, payload }: GuardianEIP712MessageEvaluationParams,
|
|
258
|
+
): Promise<GeneratedClients.mr.MessageEvaluationResponse> {
|
|
259
|
+
try {
|
|
260
|
+
const user = await this.authManager.getUserZkEvm();
|
|
261
|
+
if (user === null) {
|
|
262
|
+
throw new JsonRpcError(
|
|
263
|
+
ProviderErrorCode.UNAUTHORIZED,
|
|
264
|
+
'User not logged in. Please log in first.',
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
const messageEvalResponse = await this.guardianApi.evaluateMessage(
|
|
268
|
+
{ messageEvaluationRequest: { chainID, payload } },
|
|
269
|
+
{ headers: { Authorization: `Bearer ${user.accessToken}` } },
|
|
270
|
+
);
|
|
271
|
+
return messageEvalResponse.data;
|
|
272
|
+
} catch (error) {
|
|
273
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
274
|
+
throw new JsonRpcError(
|
|
275
|
+
RpcErrorCode.INTERNAL_ERROR,
|
|
276
|
+
`Message failed to validate with error: ${errorMessage}`,
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
public async evaluateEIP712Message({ chainID, payload }: GuardianEIP712MessageEvaluationParams) {
|
|
282
|
+
const { messageId, confirmationRequired } = await this.handleEIP712MessageEvaluation({ chainID, payload });
|
|
283
|
+
if (confirmationRequired && this.crossSdkBridgeEnabled) {
|
|
284
|
+
throw new JsonRpcError(RpcErrorCode.TRANSACTION_REJECTED, transactionRejectedCrossSdkBridgeError);
|
|
285
|
+
}
|
|
286
|
+
if (confirmationRequired && !!messageId) {
|
|
287
|
+
const user = await this.authManager.getUserZkEvm();
|
|
288
|
+
const confirmationResult = await this.confirmationScreen.requestMessageConfirmation(
|
|
289
|
+
messageId,
|
|
290
|
+
user.zkEvm.ethAddress,
|
|
291
|
+
'eip712',
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
if (!confirmationResult.confirmed) {
|
|
295
|
+
throw new JsonRpcError(
|
|
296
|
+
RpcErrorCode.TRANSACTION_REJECTED,
|
|
297
|
+
'Signature rejected by user',
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
this.confirmationScreen.closeWindow();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private async handleERC191MessageEvaluation(
|
|
306
|
+
{ chainID, payload }: GuardianERC191MessageEvaluationParams,
|
|
307
|
+
): Promise<GeneratedClients.mr.MessageEvaluationResponse> {
|
|
308
|
+
try {
|
|
309
|
+
const user = await this.authManager.getUserZkEvm();
|
|
310
|
+
if (user === null) {
|
|
311
|
+
throw new JsonRpcError(
|
|
312
|
+
ProviderErrorCode.UNAUTHORIZED,
|
|
313
|
+
'User not logged in. Please log in first.',
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
const messageEvalResponse = await this.guardianApi.evaluateErc191Message(
|
|
317
|
+
{
|
|
318
|
+
eRC191MessageEvaluationRequest: {
|
|
319
|
+
chainID: getEip155ChainId(Number(chainID)),
|
|
320
|
+
payload,
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
{ headers: { Authorization: `Bearer ${user.accessToken}` } },
|
|
324
|
+
);
|
|
325
|
+
return messageEvalResponse.data;
|
|
326
|
+
} catch (error) {
|
|
327
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
328
|
+
throw new JsonRpcError(
|
|
329
|
+
RpcErrorCode.INTERNAL_ERROR,
|
|
330
|
+
`Message failed to validate with error: ${errorMessage}`,
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
public async evaluateERC191Message({ chainID, payload }: GuardianERC191MessageEvaluationParams) {
|
|
336
|
+
const { messageId, confirmationRequired } = await this.handleERC191MessageEvaluation({ chainID, payload });
|
|
337
|
+
if (confirmationRequired && this.crossSdkBridgeEnabled) {
|
|
338
|
+
throw new JsonRpcError(RpcErrorCode.TRANSACTION_REJECTED, transactionRejectedCrossSdkBridgeError);
|
|
339
|
+
}
|
|
340
|
+
if (confirmationRequired && !!messageId) {
|
|
341
|
+
const user = await this.authManager.getUserZkEvm();
|
|
342
|
+
const confirmationResult = await this.confirmationScreen.requestMessageConfirmation(
|
|
343
|
+
messageId,
|
|
344
|
+
user.zkEvm.ethAddress,
|
|
345
|
+
'erc191',
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
if (!confirmationResult.confirmed) {
|
|
349
|
+
throw new JsonRpcError(
|
|
350
|
+
RpcErrorCode.TRANSACTION_REJECTED,
|
|
351
|
+
'Signature rejected by user',
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
} else {
|
|
355
|
+
this.confirmationScreen.closeWindow();
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Export main wallet provider
|
|
2
|
+
export { ZkEvmProvider } from './zkEvm/zkEvmProvider';
|
|
3
|
+
|
|
4
|
+
// Export configuration
|
|
5
|
+
export { WalletConfiguration } from './config';
|
|
6
|
+
|
|
7
|
+
// Export types
|
|
8
|
+
export * from './types';
|
|
9
|
+
|
|
10
|
+
// Export errors
|
|
11
|
+
export { WalletError, WalletErrorType } from './errors';
|
|
12
|
+
export { JsonRpcError, ProviderErrorCode, RpcErrorCode } from './zkEvm/JsonRpcError';
|
|
13
|
+
|
|
14
|
+
// Export zkEvm utilities
|
|
15
|
+
export { RelayerClient } from './zkEvm/relayerClient';
|
|
16
|
+
export * as walletHelpers from './zkEvm/walletHelpers';
|
|
17
|
+
|
|
18
|
+
// Export guardian and magic
|
|
19
|
+
export { default as GuardianClient } from './guardian';
|
|
20
|
+
export { default as MagicTEESigner } from './magic/magicTEESigner';
|
|
21
|
+
|
|
22
|
+
// Export utilities
|
|
23
|
+
export { default as TypedEventEmitter } from './utils/typedEventEmitter';
|
|
24
|
+
export { retryWithDelay } from './network/retry';
|
|
25
|
+
|
|
26
|
+
// Export EIP-6963 provider announcement
|
|
27
|
+
export { announceProvider, passportProviderInfo } from './provider/eip6963';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as MagicTEESigner } from './magicTEESigner';
|