Skip to content

Commit

Permalink
PRO-1991-Manual CallDataLimit Override (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
vignesha22 authored Dec 13, 2023
1 parent 9729b6c commit 1934acb
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 14 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Changelog
### New
- Added ability to override callDataLimit on estimate step by the user

## [1.3.13] - 2023-11-22
### Bug Fixes
- Removed UnsupportedChainId error and now can add custom network details
Expand Down
56 changes: 56 additions & 0 deletions examples/20-callDataLimit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { ethers } from 'ethers';
import { PrimeSdk } from '../src';
import { printOp } from '../src/sdk/common/OperationUtils';
import * as dotenv from 'dotenv';
import { sleep } from '../src/sdk/common';

dotenv.config();

const recipient = '0x80a1874E1046B1cc5deFdf4D3153838B72fF94Ac'; // recipient wallet address
const value = '0.0001'; // transfer value

async function main() {
// initializating sdk...
const primeSdk = new PrimeSdk({ privateKey: process.env.WALLET_PRIVATE_KEY }, { chainId: Number(process.env.CHAIN_ID), projectKey: 'public-prime-testnet-key' })

console.log('address: ', primeSdk.state.walletAddress)

// get address of EtherspotWallet...
const address: string = await primeSdk.getCounterFactualAddress();
console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${address}`);

// clear the transaction batch
await primeSdk.clearUserOpsFromBatch();

// add transactions to the batch
const transactionBatch = await primeSdk.addUserOpsToBatch({to: recipient, value: ethers.utils.parseEther(value)});
console.log('transactions: ', transactionBatch);

// get balance of the account address
const balance = await primeSdk.getNativeBalance();

console.log('balances: ', balance);

// estimate transactions added to the batch and get the fee data for the UserOp
// passing callGasLimit as 40000 to manually set it
const op = await primeSdk.estimate(null, null, 40000);
console.log(`Estimate UserOp: ${await printOp(op)}`);

// sign the UserOp and sending to the bundler...
const uoHash = await primeSdk.send(op);
console.log(`UserOpHash: ${uoHash}`);

// get transaction hash...
console.log('Waiting for transaction...');
let userOpsReceipt = null;
const timeout = Date.now() + 60000; // 1 minute timeout
while((userOpsReceipt == null) && (Date.now() < timeout)) {
await sleep(2);
userOpsReceipt = await primeSdk.getUserOpReceipt(uoHash);
}
console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt);
}

main()
.catch(console.error)
.finally(() => process.exit());
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@etherspot/prime-sdk",
"version": "1.3.13",
"version": "1.3.14",
"description": "Etherspot Prime (Account Abstraction) SDK",
"keywords": [
"ether",
Expand Down
16 changes: 12 additions & 4 deletions src/sdk/base/HttpRpcClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,21 @@ export class HttpRpcClient {
}

async getBundlerVersion(): Promise<string> {
const version = await this.userOpJsonRpcProvider.send('web3_clientVersion', []);
return version;
try {
const version = await this.userOpJsonRpcProvider.send('web3_clientVersion', []);
return version;
} catch (err) {
return null;
}
}

async getUserOpsReceipt(uoHash: string): Promise<any> {
const response = await this.userOpJsonRpcProvider.send('eth_getUserOperationReceipt', [uoHash]);
return response;
try {
const response = await this.userOpJsonRpcProvider.send('eth_getUserOperationReceipt', [uoHash]);
return response;
} catch (err) {
return null;
}
}

private async printUserOperation(
Expand Down
4 changes: 3 additions & 1 deletion src/sdk/common/getGasFee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export interface Gas {
export async function getGasFee(provider: ethers.providers.JsonRpcProvider): Promise<Gas> {
try {
const [fee, block] = await provider.send('eth_maxPriorityFeePerGas', []);
if (BigNumber.from(0).eq(fee)) return { maxFeePerGas: BigNumber.from(1), maxPriorityFeePerGas: BigNumber.from(1) };
if (BigNumber.from(0).eq(fee)) {
throw new Error('failed to get priorityFeePerGas');
}
const tip = ethers.BigNumber.from(fee);
const buffer = tip.div(100).mul(bufferPercent);
const maxPriorityFeePerGas = tip.add(buffer);
Expand Down
24 changes: 18 additions & 6 deletions src/sdk/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { Factory, PaymasterApi, SdkOptions } from './interfaces';
import { Network } from "./network";
import { BatchUserOpsRequest, Exception, getGasFee, onRampApiKey, openUrl, UserOpsRequest } from "./common";
import { BigNumber, ethers, providers } from 'ethers';
import { BigNumber, BigNumberish, ethers, providers } from 'ethers';
import { getNetworkConfig, Networks, onRamperAllNetworks } from './network/constants';
import { UserOperationStruct } from './contracts/account-abstraction/contracts/core/BaseAccount';
import { EtherspotWalletAPI, HttpRpcClient, VerifyingPaymasterAPI } from './base';
Expand Down Expand Up @@ -169,7 +169,7 @@ export class PrimeSdk {
return this.etherspotWallet.getCounterFactualAddress();
}

async estimate(paymasterDetails?: PaymasterApi, gasDetails?: TransactionGasInfoForUserOp) {
async estimate(paymasterDetails?: PaymasterApi, gasDetails?: TransactionGasInfoForUserOp, callDataLimit?: BigNumberish) {
if (this.userOpsBatch.to.length < 1) {
throw new ErrorHandler('cannot sign empty transaction batch', 1);
}
Expand All @@ -186,12 +186,20 @@ export class PrimeSdk {
...gasDetails,
}

const gasInfo = await this.getGasFee()

const partialtx = await this.etherspotWallet.createUnsignedUserOp({
...tx,
maxFeePerGas: 1,
maxPriorityFeePerGas: 1,
maxFeePerGas: gasInfo.maxFeePerGas,
maxPriorityFeePerGas: gasInfo.maxPriorityFeePerGas,
});

if (callDataLimit) {
partialtx.callGasLimit = BigNumber.from(callDataLimit).toHexString();
}

partialtx.signature = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c";

/**
* Dummy signature used only in the case of zeroDev factory contract
*/
Expand Down Expand Up @@ -219,7 +227,11 @@ export class PrimeSdk {
if (bundlerGasEstimate.preVerificationGas) {
partialtx.preVerificationGas = BigNumber.from(bundlerGasEstimate.preVerificationGas);
partialtx.verificationGasLimit = BigNumber.from(bundlerGasEstimate.verificationGasLimit ?? bundlerGasEstimate.verificationGas);
partialtx.callGasLimit = BigNumber.from(bundlerGasEstimate.callGasLimit);
const expectedCallGasLimit = BigNumber.from(bundlerGasEstimate.callGasLimit);
if (!callDataLimit)
partialtx.callGasLimit = expectedCallGasLimit;
else if (BigNumber.from(callDataLimit).lt(expectedCallGasLimit))
throw new ErrorHandler(`CallGasLimit is too low. Expected atleast ${expectedCallGasLimit.toString()}`);
}

return partialtx;
Expand All @@ -228,7 +240,7 @@ export class PrimeSdk {

async getGasFee() {
const version = await this.bundler.getBundlerVersion();
if (version.includes('skandha'))
if (version && version.includes('skandha'))
return this.bundler.getSkandhaGasPrice();
return getGasFee(this.etherspotWallet.provider as providers.JsonRpcProvider);
}
Expand Down

0 comments on commit 1934acb

Please sign in to comment.