Skip to content

Commit

Permalink
SimpleAccount Bug Fix (#50)
Browse files Browse the repository at this point in the history
* added execute for simpleAccount

* updated version and changelog

* changed error msg
  • Loading branch information
vignesha22 authored Oct 25, 2023
1 parent a26d405 commit c588f90
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 15 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Changelog
## [1.3.6] - 2023-10-25
### Bug Fixes
- Added addUserOp fn to execute single transaction since simpleAccount transfers native tokens only using execute fn and does not support in userOp batching

## [1.3.4] - 2023-10-24
### New
- Added BNB (BSC) Testnet bundler url
Expand Down
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.5",
"version": "1.3.6",
"description": "Etherspot Prime (Account Abstraction) SDK",
"keywords": [
"ether",
Expand Down
56 changes: 42 additions & 14 deletions src/sdk/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export class PrimeSdk {
private factoryUsed: Factory;

private userOpsBatch: BatchUserOpsRequest = { to: [], data: [], value: [] };
private singleUserOp: UserOpsRequest = { to: '', data: '', value: ''};

constructor(walletProvider: WalletProviderLike, optionsLike: SdkOptions) {

Expand All @@ -57,31 +58,31 @@ export class PrimeSdk {
optionsLike.graphqlEndpoint = networkConfig.graphqlEndpoint;
}

const factoryUsed = optionsLike.factoryWallet ?? Factory.ETHERSPOT;
this.factoryUsed = optionsLike.factoryWallet ?? Factory.ETHERSPOT;

let provider;

if (rpcProviderUrl) {
provider = new providers.JsonRpcProvider(rpcProviderUrl);
} else provider = new providers.JsonRpcProvider(optionsLike.bundlerRpcUrl);

if (Networks[chainId].contracts.walletFactory[factoryUsed] == '') throw new Exception('The selected factory is not deployed in the selected chain_id')
if (Networks[chainId].contracts.walletFactory[this.factoryUsed] == '') throw new Exception('The selected factory is not deployed in the selected chain_id')

if (factoryUsed === Factory.ZERO_DEV) {
if (this.factoryUsed === Factory.ZERO_DEV) {
this.etherspotWallet = new ZeroDevWalletAPI({
provider,
walletProvider: walletConnectProvider ?? walletProvider,
optionsLike,
entryPointAddress: Networks[chainId].contracts.entryPoint,
factoryAddress: Networks[chainId].contracts.walletFactory[factoryUsed],
factoryAddress: Networks[chainId].contracts.walletFactory[this.factoryUsed],
})
} else if (factoryUsed === Factory.SIMPLE_ACCOUNT) {
} else if (this.factoryUsed === Factory.SIMPLE_ACCOUNT) {
this.etherspotWallet = new SimpleAccountAPI({
provider,
walletProvider: walletConnectProvider ?? walletProvider,
optionsLike,
entryPointAddress: Networks[chainId].contracts.entryPoint,
factoryAddress: Networks[chainId].contracts.walletFactory[factoryUsed],
factoryAddress: Networks[chainId].contracts.walletFactory[this.factoryUsed],
})
}
else {
Expand All @@ -90,7 +91,7 @@ export class PrimeSdk {
walletProvider: walletConnectProvider ?? walletProvider,
optionsLike,
entryPointAddress: Networks[chainId].contracts.entryPoint,
factoryAddress: Networks[chainId].contracts.walletFactory[factoryUsed],
factoryAddress: Networks[chainId].contracts.walletFactory[this.factoryUsed],
})
}
this.bundler = new HttpRpcClient(optionsLike.bundlerRpcUrl, Networks[chainId].contracts.entryPoint, Networks[chainId].chainId);
Expand Down Expand Up @@ -155,20 +156,32 @@ export class PrimeSdk {
}

async estimate(paymasterDetails?: PaymasterApi, gasDetails?: TransactionGasInfoForUserOp) {
if (this.userOpsBatch.to.length < 1) {
throw new Error("cannot sign empty transaction batch");
if (this.userOpsBatch.to.length < 1 && !this.singleUserOp) {
// console.log(this.userOpsBatch, this.singleUserOp);
throw new Error("cannot sign empty transaction");
}

if (paymasterDetails?.url) {
const paymasterAPI = new VerifyingPaymasterAPI(paymasterDetails.url, Networks[this.chainId].contracts.entryPoint, paymasterDetails.context ?? {}, paymasterDetails.api_key, this.chainId)
this.etherspotWallet.setPaymasterApi(paymasterAPI)
} else this.etherspotWallet.setPaymasterApi(null);

const tx: TransactionDetailsForUserOp = {
target: this.userOpsBatch.to,
values: this.userOpsBatch.value,
data: this.userOpsBatch.data,
...gasDetails,
let tx: TransactionDetailsForUserOp = null;

if (!this.singleUserOp) {
tx = {
target: this.userOpsBatch.to,
values: this.userOpsBatch.value,
data: this.userOpsBatch.data,
...gasDetails,
}
} else {
tx = {
target: this.singleUserOp.to,
value: this.singleUserOp.value,
data: this.singleUserOp.data,
...gasDetails,
}
}

const partialtx = await this.etherspotWallet.createUnsignedUserOp({
Expand Down Expand Up @@ -239,10 +252,25 @@ export class PrimeSdk {
return this.etherspotWallet.getUserOpHash(userOp);
}

async addUserOp(
tx: UserOpsRequest
): Promise<void> {
if (this.factoryUsed === Factory.ZERO_DEV) throw new Error('Only batching allowed on ZeroDev');
if (!tx.data && !tx.value) throw new Error('Data and Value both cannot be empty');
this.singleUserOp.to = tx.to;
this.singleUserOp.data = tx.data ?? "0x";
this.singleUserOp.value = tx.value ?? BigNumber.from(0);
}

async clearUserOp(): Promise<void> {
this.singleUserOp = null;
}

async addUserOpsToBatch(
tx: UserOpsRequest,
): Promise<BatchUserOpsRequest> {
if (!tx.data && !tx.value) throw new Error('Data and Value both cannot be empty');
if (tx.value && this.factoryUsed === Factory.SIMPLE_ACCOUNT) throw new Error('SimpleAccount: native transfers cant be part of batch');
this.userOpsBatch.to.push(tx.to);
this.userOpsBatch.value.push(tx.value ?? BigNumber.from(0));
this.userOpsBatch.data.push(tx.data ?? '0x');
Expand Down

0 comments on commit c588f90

Please sign in to comment.