Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Paymaster Updates #15

Merged
merged 3 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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