Skip to content

Commit

Permalink
Merge pull request #44 from etherspot/PRO-2764-SignMessage_Workaround
Browse files Browse the repository at this point in the history
  • Loading branch information
vignesha22 authored Oct 23, 2024
2 parents 6b89431 + 090d8bf commit e4506d8
Show file tree
Hide file tree
Showing 15 changed files with 440 additions and 523 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [2.0.7] - 2024-10-23
### Breaking Changes
- `signMessage` fn now adds accountAddress on personal_sign methods

## [2.0.6] - 2024-10-14
### fix
- `getNonce` function to validate for the installed module check only for the existing modular wallet
Expand Down
327 changes: 2 additions & 325 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@etherspot/modular-sdk",
"version": "2.0.6",
"version": "2.0.7",
"description": "Etherspot Modular SDK - build with ERC-7579 smart accounts modules",
"keywords": [
"ether",
Expand Down
32 changes: 26 additions & 6 deletions src/sdk/base/BaseAccountAPI.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { ethers, BigNumber, BigNumberish, TypedDataField } from 'ethers';
import { ethers, BigNumber, BigNumberish } from 'ethers';
import { BehaviorSubject } from 'rxjs';
import { Provider } from '@ethersproject/providers';
import { IEntryPoint, EntryPoint__factory } from '../contracts';
import { UserOperationStruct } from '../contracts/account-abstraction/contracts/core/BaseAccount';
import { TransactionDetailsForUserOp } from './TransactionDetailsForUserOp';
import { resolveProperties } from 'ethers/lib/utils';
import { Deferrable, resolveProperties } from 'ethers/lib/utils';
import { PaymasterAPI } from './PaymasterAPI';
import { ErrorSubject, Exception, getUserOpHash, NotPromise, packUserOp, UserOperation } from '../common';
import { calcPreVerificationGas, GasOverheads } from './calcPreVerificationGas';
import { Factory, isWalletProvider, Network, NetworkNames, NetworkService, SdkOptions, SignMessageDto, State, StateService, validateDto, WalletProviderLike, WalletService } from '..';
import { Factory, isWalletProvider, MessagePayload, Network, NetworkNames, NetworkService, SdkOptions, SignMessageDto, State, StateService, TransactionRequest, TransactionResponse, validateDto, WalletProviderLike, WalletService } from '..';
import { Context } from '../context';
import { PaymasterResponse } from './VerifyingPaymasterAPI';
import { DEFAULT_MULTIPLE_OWNER_ECDSA_VALIDATOR_ADDRESS, Networks } from '../network/constants';

export interface BaseApiParams {
provider: Provider;
Expand Down Expand Up @@ -58,6 +59,7 @@ export abstract class BaseAccountAPI {
paymasterAPI?: PaymasterAPI;
factoryUsed: Factory;
factoryAddress?: string;
validatorAddress?: string;

/**
* base constructor.
Expand Down Expand Up @@ -100,6 +102,8 @@ export abstract class BaseAccountAPI {
this.accountAddress = params.accountAddress;
this.factoryAddress = params.factoryAddress;

this.validatorAddress = Networks[params.optionsLike.chainId]?.contracts?.multipleOwnerECDSAValidator ?? DEFAULT_MULTIPLE_OWNER_ECDSA_VALIDATOR_ADDRESS;

// factory "connect" define the contract address. the contract "connect" defines the "from" address.
this.entryPointView = EntryPoint__factory.connect(params.entryPointAddress, params.provider).connect(
ethers.constants.AddressZero,
Expand Down Expand Up @@ -145,7 +149,7 @@ export abstract class BaseAccountAPI {
network: false,
});

return this.services.walletService.signMessage(message);
return this.services.walletService.signMessage(message, this.validatorAddress, this.accountAddress);
}

async setPaymasterApi(paymaster: PaymasterAPI | null) {
Expand Down Expand Up @@ -523,7 +527,23 @@ export abstract class BaseAccountAPI {
return null;
}

async signTypedData(types: TypedDataField[], message: any) {
return this.services.walletService.signTypedData(types, message, this.accountAddress);
async signTypedData(message: MessagePayload) {
return this.services.walletService.signTypedData(message, this.accountAddress);
}

async eth_requestAccounts(): Promise<string[]> {
return this.services.walletService.eth_requestAccounts(this.accountAddress)
}

async eth_accounts(): Promise<string[]> {
return this.services.walletService.eth_requestAccounts(this.accountAddress)
}

async eth_sendTransaction(transaction: Deferrable<TransactionRequest>): Promise<TransactionResponse> {
return this.services.walletService.eth_sendTransaction(transaction);
}

async eth_signTransaction(transaction: TransactionRequest): Promise<string> {
return this.services.walletService.eth_signTransaction(transaction);
}
}
3 changes: 1 addition & 2 deletions src/sdk/base/EtherspotWalletAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ export class EtherspotWalletAPI extends BaseAccountAPI {
}

async installModule(moduleTypeId: MODULE_TYPE, module: string, initData = '0x'): Promise<string> {
const accountAddress = await this.getAccountAddress();
const accountContract = EtherspotWallet7579__factory.connect(await this.getAccountAddress(), this.provider);
if (await accountContract.isModuleInstalled(moduleTypeId, module, initData)) {
throw new Error('the module is already installed')
Expand Down Expand Up @@ -333,7 +332,7 @@ export class EtherspotWalletAPI extends BaseAccountAPI {
}

async signUserOpHash(userOpHash: string): Promise<string> {
const signature = await this.services.walletService.signMessage(arrayify(userOpHash));
const signature = await this.services.walletService.signUserOp(arrayify(userOpHash));
return signature;
}

Expand Down
27 changes: 23 additions & 4 deletions src/sdk/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { BehaviorSubject } from 'rxjs';
import { BigNumber, BigNumberish, Contract, ethers, providers } from 'ethers';
import { Deferrable } from 'ethers/lib/utils';
import { State, StateService } from './state';
import {
EthereumProvider,
isWalletConnectProvider,
isWalletProvider,
MessagePayload,
TransactionRequest,
TransactionResponse,
WalletConnect2WalletProvider,
WalletProviderLike
} from './wallet';
import { Factory, PaymasterApi, SdkOptions } from './interfaces';
import { Network } from "./network";
import { BatchUserOpsRequest, Exception, getGasFee, MODULE_TYPE, onRampApiKey, openUrl, UserOperation, UserOpsRequest } from "./common";
import { BigNumber, BigNumberish, Contract, TypedDataField, ethers, providers } from 'ethers';
import { DEFAULT_QUERY_PAGE_SIZE, Networks, onRamperAllNetworks } from './network/constants';
import { EtherspotWalletAPI, HttpRpcClient, VerifyingPaymasterAPI } from './base';
import { TransactionDetailsForUserOp, TransactionGasInfoForUserOp } from './base/TransactionDetailsForUserOp';
Expand Down Expand Up @@ -218,10 +222,25 @@ export class ModularSdk {
}

async signTypedData(
DataFields: TypedDataField[],
message: any
message: MessagePayload
) {
return this.etherspotWallet.signTypedData(DataFields, message);
return this.etherspotWallet.signTypedData(message);
}

async eth_requestAccounts(): Promise<string[]>{
return this.etherspotWallet.eth_requestAccounts();
}

async eth_accounts(): Promise<string[]> {
return this.etherspotWallet.eth_accounts();
}

async eth_sendTransaction(transaction: Deferrable<TransactionRequest>): Promise<TransactionResponse> {
return this.etherspotWallet.eth_sendTransaction(transaction);
}

async eth_signTransaction(transaction: TransactionRequest): Promise<string> {
return this.etherspotWallet.eth_signTransaction(transaction);
}

async getNativeBalance() {
Expand Down
18 changes: 14 additions & 4 deletions src/sdk/wallet/providers/dynamic.wallet-provider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BytesLike, Deferrable } from 'ethers/lib/utils';
import { NetworkNames, prepareNetworkName } from '../../network';
import { prepareAddress, UniqueSubject } from '../../common';
import { WalletProvider } from './interfaces';
import { TypedDataField } from 'ethers';
import { MessagePayload, TransactionRequest, TransactionResponse, WalletProvider } from './interfaces';

export abstract class DynamicWalletProvider implements WalletProvider {
readonly address$ = new UniqueSubject<string>();
Expand All @@ -19,9 +19,11 @@ export abstract class DynamicWalletProvider implements WalletProvider {
return this.networkName$.value;
}

abstract signMessage(message: any): Promise<string>;
abstract signMessage(message: any, validatorAddress?: string): Promise<string>;

abstract signTypedData(typedData: TypedDataField[], message: any, accountAddress: string): Promise<string>;
abstract signUserOp(message: BytesLike): Promise<string>;

abstract signTypedData(msg: MessagePayload): Promise<string>

protected setAddress(address: string): void {
this.address$.next(prepareAddress(address));
Expand All @@ -30,4 +32,12 @@ export abstract class DynamicWalletProvider implements WalletProvider {
protected setNetworkName(networkNameOrChainId: string | number): void {
this.networkName$.next(prepareNetworkName(networkNameOrChainId));
}

abstract eth_requestAccounts(address?: string): Promise<string[]>;

abstract eth_accounts(address?: string): Promise<string[]>;

abstract eth_sendTransaction(transaction: Deferrable<TransactionRequest>): Promise<TransactionResponse>;

abstract eth_signTransaction(transaction: TransactionRequest): Promise<string>;
}
121 changes: 118 additions & 3 deletions src/sdk/wallet/providers/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BytesLike, TypedDataField, Wallet } from 'ethers';
import { BigNumber, BigNumberish, BytesLike, Transaction, Wallet } from 'ethers';
import { AccessListish, Deferrable } from 'ethers/lib/utils';
import type UniversalProvider from '@walletconnect/universal-provider';
import { UniqueSubject } from '../../common';
import { NetworkNames } from '../../network';
Expand All @@ -11,14 +12,127 @@ export interface WalletProvider {
readonly networkName?: NetworkNames;
readonly networkName$?: UniqueSubject<NetworkNames>;

signMessage(message: BytesLike): Promise<string>;
signTypedData(typedData: TypedDataField[], message: any, accountAddress: string): Promise<string>;
signTypedData(msg: MessagePayload, accountAddress?: string): Promise<string>;

signMessage(message: BytesLike, validatorAddress?: string, accountAddress?: string): Promise<string>;

signUserOp(message: BytesLike): Promise<string>;

eth_requestAccounts(address?: string): Promise<string[]>;

eth_accounts(address?: string): Promise<string[]>;

eth_sendTransaction(transaction: Deferrable<TransactionRequest>): Promise<TransactionResponse>;

eth_signTransaction(transaction: TransactionRequest): Promise<string>;
}

export interface Web3Provider {
send(payload: any, callback: (err: any, response?: any) => any): any;
}

export interface TransactionResponse extends Transaction {
hash: string;

// Only if a transaction has been mined
blockNumber?: number,
blockHash?: string,
timestamp?: number,

confirmations: number,

// Not optional (as it is in Transaction)
from: string;

// The raw transaction
raw?: string,

// This function waits until the transaction has been mined
wait: (confirmations?: number) => Promise<TransactionReceipt>
};

export interface TransactionReceipt {
to: string;
from: string;
contractAddress: string,
transactionIndex: number,
root?: string,
gasUsed: BigNumber,
logsBloom: string,
blockHash: string,
transactionHash: string,
logs: Array<Log>,
blockNumber: number,
confirmations: number,
cumulativeGasUsed: BigNumber,
effectiveGasPrice: BigNumber,
byzantium: boolean,
type: number;
status?: number
};

export interface Log {
blockNumber: number;
blockHash: string;
transactionIndex: number;

removed: boolean;

address: string;
data: string;

topics: Array<string>;

transactionHash: string;
logIndex: number;
}

export type TransactionRequest = {
to?: string,
from?: string,
nonce?: BigNumberish,

gasLimit?: BigNumberish,
gasPrice?: BigNumberish,

data?: BytesLike,
value?: BigNumberish,
chainId?: number

type?: number;
accessList?: AccessListish;

maxPriorityFeePerGas?: BigNumberish;
maxFeePerGas?: BigNumberish;

customData?: Record<string, any>;
ccipReadEnabled?: boolean;
}

// https://eips.ethereum.org/EIPS/eip-712#parameters
export type MessagePayload = {
domain: EIP712Domain;
types: { EIP712Domain: EIP712Domain } & Record<string, TypedProperty[]>;
primaryType: string;
message: any;
};

// https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator
type EIP712Domain = {
name?: string;
version?: string;
chainId?: number;
verifyingContract?: string;
salt?: string;
};

// https://eips.ethereum.org/EIPS/eip-712#definition-of-typed-structured-data-%F0%9D%95%8A
type TypedProperty = {
name: string;
type: string;
};


export interface RequestArguments {
method: string;
params?: unknown[] | object;
Expand All @@ -31,6 +145,7 @@ export interface WalletConnectConnector {
accounts: string[];
chainId: number;
signPersonalMessage(params: any[]): Promise<any>;
request<T = unknown>(args: RequestArguments): Promise<T>;
on(event: string, callback: (error: Error | null, payload: any | null) => void): void;
}

Expand Down
31 changes: 27 additions & 4 deletions src/sdk/wallet/providers/key.wallet-provider.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Wallet, BytesLike, TypedDataField } from 'ethers';
import { WalletProvider } from './interfaces';
import { Wallet, BytesLike } from 'ethers';
import { Deferrable } from 'ethers/lib/utils';
import { MessagePayload, TransactionRequest, TransactionResponse, WalletProvider } from './interfaces';

export class KeyWalletProvider implements WalletProvider {
readonly type = 'Key';
readonly address: string;
readonly accountAddress: string;

readonly wallet: Wallet;

Expand All @@ -20,7 +22,28 @@ export class KeyWalletProvider implements WalletProvider {
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async signTypedData(typedData: TypedDataField[], message: any, accountAddress: string): Promise<string> {
throw new Error('Not supported in this connectedProvider');
async signTypedData(msg: MessagePayload): Promise<string> {
return this.wallet._signTypedData(msg.domain, msg.types, msg.message)
}

async eth_requestAccounts(address: string): Promise<string[]> {
return [address];
}

async eth_accounts(address: string): Promise<string[]> {
return [address];
}

async signUserOp(message: BytesLike): Promise<string> {
return this.wallet.signMessage(message);
}

async eth_sendTransaction(transaction: Deferrable<TransactionRequest>): Promise<TransactionResponse> {
return this.wallet.sendTransaction(transaction);
}

async eth_signTransaction(transaction: TransactionRequest): Promise<string> {
return this.wallet.signTransaction(transaction);
}

}
Loading

0 comments on commit e4506d8

Please sign in to comment.