Skip to content

Commit

Permalink
Merge pull request #304 from bcnmy/feat-latency-improvements
Browse files Browse the repository at this point in the history
add simulation type param
  • Loading branch information
livingrockrises authored Sep 28, 2023
2 parents 64c97bc + f57d823 commit 6952d63
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 23 deletions.
4 changes: 3 additions & 1 deletion packages/account/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
"@biconomy/node-client": "^3.1.0",
"@biconomy/paymaster": "^3.1.0",
"@ethersproject/providers": "^5.7.2",
"ethers": "^5.7.0"
"ethers": "^5.7.0",
"loglevel": "^1.8.1",
"lru-cache": "^10.0.1"
}
}
16 changes: 13 additions & 3 deletions packages/account/src/BaseSmartAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import { calcPreVerificationGas, DefaultGasLimits } from "./utils/Preverificaito
import { NotPromise, packUserOp, Logger, RPC_PROVIDER_URLS } from "@biconomy/common";
import { IBundler, UserOpResponse } from "@biconomy/bundler";
import { IPaymaster, PaymasterAndDataResponse } from "@biconomy/paymaster";
import { BaseSmartAccountConfig, Overrides, TransactionDetailsForUserOp } from "./utils/Types";
import { BaseSmartAccountConfig, Overrides, SendUserOpOptions, TransactionDetailsForUserOp } from "./utils/Types";
import { GasOverheads } from "./utils/Preverificaiton";
import { EntryPoint, EntryPoint__factory } from "@account-abstraction/contracts";
import { DEFAULT_ENTRYPOINT_ADDRESS } from "./utils/Constants";
import { LRUCache } from 'lru-cache'

Check failure on line 14 in packages/account/src/BaseSmartAccount.ts

View workflow job for this annotation

GitHub Actions / Lint sources (18.x)

Replace `'lru-cache'` with `"lru-cache";`

type UserOperationKey = keyof UserOperation;

Expand All @@ -35,6 +36,10 @@ export abstract class BaseSmartAccount implements IBaseSmartAccount {
// entryPoint connected to "zero" address. allowed to make static calls (e.g. to getSenderAddress)
private readonly entryPoint!: EntryPoint;

private isContractDeployedCache = new LRUCache({
max: 500,
});

constructor(_smartAccountConfig: BaseSmartAccountConfig) {
this.index = _smartAccountConfig.index ?? 0;
this.overheads = _smartAccountConfig.overheads;
Expand Down Expand Up @@ -176,7 +181,7 @@ export abstract class BaseSmartAccount implements IBaseSmartAccount {
* @description This function call will take 'signedUserOp' as input and send it to the bundler
* @returns
*/
async sendSignedUserOp(userOp: UserOperation): Promise<UserOpResponse> {
async sendSignedUserOp(userOp: UserOperation, params?: SendUserOpOptions): Promise<UserOpResponse> {
const requiredFields: UserOperationKey[] = [
"sender",
"nonce",
Expand All @@ -194,7 +199,7 @@ export abstract class BaseSmartAccount implements IBaseSmartAccount {
Logger.log("userOp validated");
if (!this.bundler) throw new Error("Bundler is not provided");
Logger.log("userOp being sent to the bundler", userOp);
const bundlerResponse = await this.bundler.sendUserOp(userOp);
const bundlerResponse = await this.bundler.sendUserOp(userOp, params);
return bundlerResponse;
}

Expand Down Expand Up @@ -270,10 +275,15 @@ export abstract class BaseSmartAccount implements IBaseSmartAccount {
}

async isAccountDeployed(address: string): Promise<boolean> {
if (this.isContractDeployedCache.get(address)) {
return true;
}

this.isProviderDefined();
let isDeployed = false;
const contractCode = await this.provider.getCode(address);
if (contractCode.length > 2) {
this.isContractDeployedCache.set(address, true);
isDeployed = true;
} else {
isDeployed = false;
Expand Down
28 changes: 19 additions & 9 deletions packages/account/src/BiconomySmartAccountV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ import {
SmartAccount_v200__factory,
SmartAccountFactory_v200__factory,
} from "@biconomy/common";
import { BiconomyTokenPaymasterRequest, BiconomySmartAccountV2Config, CounterFactualAddressParam, BuildUserOpOptions } from "./utils/Types";
import { BaseValidationModule, ModuleInfo } from "@biconomy/modules";
import {
BiconomyTokenPaymasterRequest,
BiconomySmartAccountV2Config,
CounterFactualAddressParam,
BuildUserOpOptions,
SendUserOpOptions,
} from "./utils/Types";
import { BaseValidationModule, ModuleInfo, SendUserOpParams } from "@biconomy/modules";
import { UserOperation, Transaction } from "@biconomy/core-types";
import NodeClient from "@biconomy/node-client";
import INodeClient from "@biconomy/node-client";
Expand All @@ -32,6 +38,7 @@ import {
DEFAULT_FALLBACK_HANDLER_ADDRESS,
PROXY_CREATION_CODE,
} from "./utils/Constants";
import log from "loglevel";

type UserOperationKey = keyof UserOperation;
export class BiconomySmartAccountV2 extends BaseSmartAccount {
Expand Down Expand Up @@ -130,11 +137,14 @@ export class BiconomySmartAccountV2 extends BaseSmartAccount {
// Could call it nonce space
async getNonce(nonceKey?: number): Promise<BigNumber> {
const nonceSpace = nonceKey ?? 0;
if (await this.isAccountDeployed(await this.getAccountAddress())) {
try {
const accountContract = await this._getAccountContract();
return accountContract.nonce(nonceSpace);
const nonce = await accountContract.nonce(nonceSpace);
return nonce;
} catch (e) {
log.debug("Failed to get nonce from deployed account. Returning 0 as nonce");
return BigNumber.from(0);
}
return BigNumber.from(0);
}

/**
Expand Down Expand Up @@ -240,7 +250,7 @@ export class BiconomySmartAccountV2 extends BaseSmartAccount {
return "0x";
}

async signUserOp(userOp: Partial<UserOperation>, params?: ModuleInfo): Promise<UserOperation> {
async signUserOp(userOp: Partial<UserOperation>, params?: SendUserOpParams): Promise<UserOperation> {
this.isActiveValidationModuleDefined();
const requiredFields: UserOperationKey[] = [
"sender",
Expand Down Expand Up @@ -296,11 +306,11 @@ export class BiconomySmartAccountV2 extends BaseSmartAccount {
* @description This function call will take 'unsignedUserOp' as an input, sign it with the owner key, and send it to the bundler.
* @returns Promise<UserOpResponse>
*/
async sendUserOp(userOp: Partial<UserOperation>, params?: ModuleInfo): Promise<UserOpResponse> {
async sendUserOp(userOp: Partial<UserOperation>, params?: SendUserOpOptions): Promise<UserOpResponse> {
Logger.log("userOp received in base account ", userOp);
delete userOp.signature;
const userOperation = await this.signUserOp(userOp, params);
const bundlerResponse = await this.sendSignedUserOp(userOperation);
const bundlerResponse = await this.sendSignedUserOp(userOperation, params);
return bundlerResponse;
}

Expand Down Expand Up @@ -486,7 +496,7 @@ export class BiconomySmartAccountV2 extends BaseSmartAccount {
return userOp;
}

async signUserOpHash(userOpHash: string, params?: ModuleInfo): Promise<string> {
async signUserOpHash(userOpHash: string, params?: SendUserOpParams): Promise<string> {
this.isActiveValidationModuleDefined();
const moduleSig = await this.activeValidationModule.signUserOpHash(userOpHash, params);

Expand Down
10 changes: 5 additions & 5 deletions packages/account/src/SmartAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { IBundler, UserOpResponse } from "@biconomy/bundler";
import { IPaymaster, PaymasterAndDataResponse } from "@biconomy/paymaster";
import { Logger } from "@biconomy/common";
import { IEntryPoint } from "@account-abstraction/contracts";
import { SmartAccountConfig, Overrides } from "./utils/Types";
import { SmartAccountConfig, Overrides, SendUserOpDto } from "./utils/Types";

type UserOperationKey = keyof UserOperation;

Expand Down Expand Up @@ -239,11 +239,11 @@ export abstract class SmartAccount implements ISmartAccount {
* @description This function call will take 'unsignedUserOp' as an input, sign it with the owner key, and send it to the bundler.
* @returns Promise<UserOpResponse>
*/
async sendUserOp(userOp: Partial<UserOperation>): Promise<UserOpResponse> {
async sendUserOp(userOp: Partial<UserOperation>, params?: SendUserOpDto): Promise<UserOpResponse> {
Logger.log("userOp received in base account ", userOp);
delete userOp.signature;
const userOperation = await this.signUserOp(userOp);
const bundlerResponse = await this.sendSignedUserOp(userOperation);
const bundlerResponse = await this.sendSignedUserOp(userOperation, params);
return bundlerResponse;
}

Expand All @@ -253,7 +253,7 @@ export abstract class SmartAccount implements ISmartAccount {
* @description This function call will take 'signedUserOp' as input and send it to the bundler
* @returns
*/
async sendSignedUserOp(userOp: UserOperation): Promise<UserOpResponse> {
async sendSignedUserOp(userOp: UserOperation, params?: SendUserOpDto): Promise<UserOpResponse> {
const requiredFields: UserOperationKey[] = [
"sender",
"nonce",
Expand All @@ -271,7 +271,7 @@ export abstract class SmartAccount implements ISmartAccount {
Logger.log("userOp validated");
if (!this.bundler) throw new Error("Bundler is not provided");
Logger.log("userOp being sent to the bundler", userOp);
const bundlerResponse = await this.bundler.sendUserOp(userOp);
const bundlerResponse = await this.bundler.sendUserOp(userOp, params);
return bundlerResponse;
}
}
13 changes: 13 additions & 0 deletions packages/account/src/utils/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,19 @@ export type NonceOptions = {
nonceOverride?: number;
};

// Used in AccountV1
export type SendUserOpDto = {
signer?: Signer;
simulationType?: SimulationType;
};

// Generic options in AccountV2
export type SendUserOpOptions = {
simulationType?: SimulationType;
};

export type SimulationType = "validation" | "validation_and_execution";

export type Overrides = {
callGasLimit?: BigNumberish;
verificationGasLimit?: BigNumberish;
Expand Down
8 changes: 6 additions & 2 deletions packages/bundler/src/Bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SendUserOpResponse,
UserOpGasResponse,
UserOpByHashResponse,
SendUserOpOptions,
} from "./utils/Types";
import { resolveProperties } from "ethers/lib/utils";
import { deepHexlify, sendRequest, getTimestampInSeconds, HttpMethod, Logger, RPC_PROVIDER_URLS } from "@biconomy/common";
Expand Down Expand Up @@ -78,12 +79,15 @@ export class Bundler implements IBundler {
* @description This function will send signed userOp to bundler to get mined on chain
* @returns Promise<UserOpResponse>
*/
async sendUserOp(userOp: UserOperation): Promise<UserOpResponse> {
async sendUserOp(userOp: UserOperation, simulationParam?: SendUserOpOptions): Promise<UserOpResponse> {
const chainId = this.bundlerConfig.chainId;
// transformUserOP will convert all bigNumber values to string
userOp = transformUserOP(userOp);
const hexifiedUserOp = deepHexlify(await resolveProperties(userOp));
const params = [hexifiedUserOp, this.bundlerConfig.entryPointAddress];
const simType = {
simulation_type: simulationParam?.simulationType || "validation",
};
const params = [hexifiedUserOp, this.bundlerConfig.entryPointAddress, simType];
const bundlerUrl = this.getBundlerUrl();
const sendUserOperationResponse: SendUserOpResponse = await sendRequest({
url: bundlerUrl,
Expand Down
4 changes: 2 additions & 2 deletions packages/bundler/src/interfaces/IBundler.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { UserOpResponse, UserOpGasResponse, UserOpReceipt, UserOpByHashResponse } from "../utils/Types";
import { UserOpResponse, UserOpGasResponse, UserOpReceipt, UserOpByHashResponse, SendUserOpOptions } from "../utils/Types";
import { UserOperation } from "@biconomy/core-types";

export interface IBundler {
estimateUserOpGas(_userOp: Partial<UserOperation>): Promise<UserOpGasResponse>;
sendUserOp(_userOp: UserOperation): Promise<UserOpResponse>;
sendUserOp(_userOp: UserOperation, _simulationParam?: SendUserOpOptions): Promise<UserOpResponse>;
getUserOpReceipt(_userOpHash: string): Promise<UserOpReceipt>;
getUserOpByHash(_userOpHash: string): Promise<UserOpByHashResponse>;
}
6 changes: 6 additions & 0 deletions packages/bundler/src/utils/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export type UserOpReceipt = {
receipt: ethers.providers.TransactionReceipt;
};

export type SendUserOpOptions = {
simulationType?: SimulationType;
};

export type SimulationType = "validation" | "validation_and_execution";

// Converted to JsonRpcResponse with strict type
export type GetUserOperationResponse = {
jsonrpc: string;
Expand Down
6 changes: 6 additions & 0 deletions packages/modules/src/utils/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ export type ModuleInfo = {
batchSessionParams?: SessionParams[];
};

export interface SendUserOpParams extends ModuleInfo {
simulationType?: SimulationType;
}

export type SimulationType = "validation" | "validation_and_execution";

export type CreateSessionDataResponse = {
data: string;
sessionIDInfo: Array<string>;
Expand Down
2 changes: 1 addition & 1 deletion packages/node-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const balanceParams: BalancesDto =
tokenAddresses: [],
};
const balFromSdk = await nodeClient.getAlltokenBalances(balanceParams);
const balFromSdk = await nodeClient.getAllTokenBalances(balanceParams);
console.info("balFromSdk ", balFromSdk);
const usdBalFromSdk = await nodeClient.getTotalBalanceInUsd(balanceParams);
Expand Down

0 comments on commit 6952d63

Please sign in to comment.