Skip to content

Commit

Permalink
Paymaster Updates (#15)
Browse files Browse the repository at this point in the history
* enabled the use of paymaster

* updated package version
  • Loading branch information
vignesha22 authored Aug 21, 2023
1 parent 34a3255 commit 344aa4f
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 20 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# Changelog
## [1.1.4] - 2023-08-21
### Breaking Changes
- Changed the way of initialising the Paymaster url to string as before it was unreachable code to get VerifyingPaymasterApi class to pass on to the Prime-Sdk
- Changed the response object got from the paymaster to be compatible with our Arka service

## [1.1.2] - 2023-07-31
### New
- Added onRamper to get the 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.1.3",
"version": "1.1.4",
"description": "Etherspot Prime (Account Abstraction) SDK",
"keywords": [
"ether",
Expand Down
13 changes: 10 additions & 3 deletions src/sdk/base/BaseAccountAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ErrorSubject, Exception, getUserOpHash, NotPromise, packUserOp, Service
import { calcPreVerificationGas, GasOverheads } from './calcPreVerificationGas';
import { AccountService, AccountTypes, CreateSessionDto, isWalletProvider, Network, NetworkNames, NetworkService, SdkOptions, Session, SessionService, SignMessageDto, State, StateService, validateDto, WalletProviderLike, WalletService } from '..';
import { Context } from '../context';
import { paymasterResponse } from './VerifyingPaymasterAPI';

export interface BaseApiParams {
provider: Provider;
Expand Down Expand Up @@ -474,16 +475,17 @@ export abstract class BaseAccountAPI {
};


let paymasterAndData: string | undefined;
let paymasterAndData: paymasterResponse | undefined = null;
if (this.paymasterAPI != null) {
// fill (partial) preVerificationGas (all except the cost of the generated paymasterAndData)
const userOpForPm = {
...partialUserOp,
preVerificationGas: this.getPreVerificationGas(partialUserOp),
};
paymasterAndData = await this.paymasterAPI.getPaymasterAndData(userOpForPm);
paymasterAndData = (await this.paymasterAPI.getPaymasterAndData(userOpForPm));
partialUserOp.verificationGasLimit = BigNumber.from(paymasterAndData.verificationGasLimit);
}
partialUserOp.paymasterAndData = paymasterAndData ?? '0x';
partialUserOp.paymasterAndData = paymasterAndData ? paymasterAndData.paymasterAndData : '0x';
return {
...partialUserOp,
preVerificationGas: this.getPreVerificationGas(partialUserOp),
Expand All @@ -497,6 +499,11 @@ export abstract class BaseAccountAPI {
*/
async signUserOp(userOp: UserOperationStruct): Promise<UserOperationStruct> {
const userOpHash = await this.getUserOpHash(userOp);
if (this.paymasterAPI != null) {
const paymasterAndData = await this.paymasterAPI.getPaymasterAndData(userOp);
userOp.paymasterAndData = paymasterAndData.paymasterAndData;
userOp.verificationGasLimit = BigNumber.from(paymasterAndData.verificationGasLimit);
}
const signature = await this.signUserOpHash(userOpHash);
return {
...userOp,
Expand Down
5 changes: 3 additions & 2 deletions src/sdk/base/PaymasterAPI.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { UserOperationStruct } from '../contracts/src/aa-4337/core/BaseAccount';
import { paymasterResponse } from './VerifyingPaymasterAPI';

/**
* an API to external a UserOperation with paymaster info
Expand All @@ -10,7 +11,7 @@ export class PaymasterAPI {
* paymasterAndData value, which will only be returned by this method..
* @returns the value to put into the PaymasterAndData, undefined to leave it empty
*/
async getPaymasterAndData(userOp: Partial<UserOperationStruct>): Promise<string | undefined> {
return '0x';
async getPaymasterAndData(userOp: Partial<UserOperationStruct>): Promise<paymasterResponse | undefined> {
return { paymasterAndData: '0x', verificationGasLimit: '0x' };
}
}
27 changes: 16 additions & 11 deletions src/sdk/base/VerifyingPaymasterAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,23 @@ const SIG_SIZE = 65;
const DUMMY_PAYMASTER_AND_DATA =
'0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101';

interface paymasterResponse {
jsonrpc: string;
id: number;
result: BytesLike;
export interface paymasterResponse {
paymasterAndData: string;
verificationGasLimit: string;
}

export class VerifyingPaymasterAPI extends PaymasterAPI {
private paymasterUrl: string;
private entryPoint: string;
constructor(paymasterUrl: string, entryPoint: string) {
private context: any;
constructor(paymasterUrl: string, entryPoint: string, context: any) {
super();
this.paymasterUrl = paymasterUrl;
this.entryPoint = entryPoint;
this.context = context;
}

async getPaymasterAndData(userOp: Partial<UserOperationStruct>): Promise<string> {
async getPaymasterAndData(userOp: Partial<UserOperationStruct>): Promise<paymasterResponse> {
// Hack: userOp includes empty paymasterAndData which calcPreVerificationGas requires.
try {
// userOp.preVerificationGas contains a promise that will resolve to an error.
Expand All @@ -48,16 +49,20 @@ export class VerifyingPaymasterAPI extends PaymasterAPI {
op.preVerificationGas = calcPreVerificationGas(op);

// Ask the paymaster to sign the transaction and return a valid paymasterAndData value.
return axios
const paymasterAndData = axios
.post<paymasterResponse>(this.paymasterUrl, {
jsonrpc: '2.0',
id: 1,
method: 'pm_sponsorUserOperation',
params: [await toJSON(op), this.entryPoint],
params: [await toJSON(op), this.entryPoint, this.context],
})
.then((res) => res.data.result.toString());
.then((res) => {
return res.data
});

return paymasterAndData;
}
}

export const getVerifyingPaymaster = (paymasterUrl: string, entryPoint: string) =>
new VerifyingPaymasterAPI(paymasterUrl, entryPoint);
export const getVerifyingPaymaster = (paymasterUrl: string, entryPoint: string, context: any) =>
new VerifyingPaymasterAPI(paymasterUrl, entryPoint, context);
7 changes: 6 additions & 1 deletion src/sdk/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ import { StateStorage } from './state';
import { SessionStorage } from './session';
import { VerifyingPaymasterAPI } from './base';

export interface PaymasterApi {
url: string;
context: any;
}

export interface SdkOptions {
chainId: number;
stateStorage?: StateStorage;
sessionStorage?: SessionStorage;
omitWalletProviderNetworkCheck?: boolean;
bundlerRpcUrl?: string;
rpcProviderUrl?: string;
paymasterApi?: VerifyingPaymasterAPI;
paymasterApi?: PaymasterApi;
}
9 changes: 7 additions & 2 deletions src/sdk/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { BatchUserOpsRequest, Exception, getGasFee, onRampApiKey, UserOpsRequest
import { BigNumber, ethers, providers } from 'ethers';
import { getNetworkConfig, Networks, onRamperAllNetworks } from './network/constants';
import { UserOperationStruct } from './contracts/src/aa-4337/core/BaseAccount';
import { EtherspotWalletAPI, HttpRpcClient } from './base';
import { EtherspotWalletAPI, HttpRpcClient, VerifyingPaymasterAPI } from './base';
import { TransactionDetailsForUserOp, TransactionGasInfoForUserOp } from './base/TransactionDetailsForUserOp';
import { CreateSessionDto, OnRamperDto, SignMessageDto, validateDto } from './dto';
import { Session } from '.';
Expand Down Expand Up @@ -53,13 +53,18 @@ export class PrimeSdk {
provider = new providers.JsonRpcProvider(rpcProviderUrl);
} else provider = new providers.JsonRpcProvider(optionsLike.bundlerRpcUrl);

let paymasterAPI = null;
if (optionsLike.paymasterApi && optionsLike.paymasterApi.url) {
paymasterAPI = new VerifyingPaymasterAPI(optionsLike.paymasterApi.url, Networks[chainId].contracts.entryPoint, optionsLike.paymasterApi.context ?? {})
}

this.etherspotWallet = new EtherspotWalletAPI({
provider,
walletProvider,
optionsLike,
entryPointAddress: Networks[chainId].contracts.entryPoint,
factoryAddress: Networks[chainId].contracts.walletFactory,
paymasterAPI: optionsLike.paymasterApi,
paymasterAPI,
})

this.bundler = new HttpRpcClient(optionsLike.bundlerRpcUrl, Networks[chainId].contracts.entryPoint, Networks[chainId].chainId);
Expand Down

0 comments on commit 344aa4f

Please sign in to comment.