Skip to content

Commit

Permalink
fix: create new private paymaster client
Browse files Browse the repository at this point in the history
  • Loading branch information
BarryTong65 committed Oct 16, 2024
1 parent babb35e commit 1150f05
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 189 deletions.
63 changes: 43 additions & 20 deletions src/paymasterclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ export type IsSponsorableResponse = {
SponsorWebsite: string
}

export type IsSponsorableOptions = {
PrivatePolicyUUID?: string
}

export type SendRawTransactionOptions = {
PrivatePolicyUUID?: string
UserAgent?: string
}

Expand Down Expand Up @@ -58,19 +53,46 @@ export type Bundle = {
}

export class PaymasterClient extends ethers.JsonRpcProvider {
constructor(url?: string | FetchRequest, network?: Networkish, options?: JsonRpcApiProviderOptions) {
super(url, network, options)
private privatePolicyUUID?: string;

private constructor(
url?: string | FetchRequest,
network?: Networkish,
options?: JsonRpcApiProviderOptions,
privatePolicyUUID?: string
) {
super(url, network, options);
this.privatePolicyUUID = privatePolicyUUID;
}

// Static method to create a new standard PaymasterClient
static new(
url?: string | FetchRequest,
network?: Networkish,
options?: JsonRpcApiProviderOptions
): PaymasterClient {
return new PaymasterClient(url, network, options);
}

// Static method to create a new PaymasterClient with private policy
static newPrivatePaymaster(
url: string | FetchRequest,
privatePolicyUUID: string,
network?: Networkish,
options?: JsonRpcApiProviderOptions
): PaymasterClient {
return new PaymasterClient(url, network, options, privatePolicyUUID);
}

async chainID(): Promise<string> {
return await this.send('eth_chainId', [])
return await this.send('eth_chainId', []);
}

async isSponsorable(tx: TransactionRequest, opts: IsSponsorableOptions = {}): Promise<IsSponsorableResponse> {
if (opts.PrivatePolicyUUID) {
async isSponsorable(tx: TransactionRequest): Promise<IsSponsorableResponse> {
const policyUUID = this.privatePolicyUUID;
if (policyUUID) {
const newConnection = this._getConnection();
newConnection.setHeader("X-MegaFuel-Policy-Uuid", opts.PrivatePolicyUUID);

newConnection.setHeader("X-MegaFuel-Policy-Uuid", policyUUID);
const sponsorProviderWithHeader = new ethers.JsonRpcProvider(
newConnection,
(this as any)._network,
Expand All @@ -80,23 +102,24 @@ export class PaymasterClient extends ethers.JsonRpcProvider {
polling: (this as any).polling
}
);

return await sponsorProviderWithHeader.send('pm_isSponsorable', [tx]);
}
return await this.send('pm_isSponsorable', [tx]);
}

async sendRawTransaction(signedTx: string, opts: SendRawTransactionOptions = {}): Promise<string> {
if (opts.UserAgent || opts.PrivatePolicyUUID) {
const policyUUID = this.privatePolicyUUID;
if (opts.UserAgent || this.privatePolicyUUID) {
const newConnection = this._getConnection();

if (opts.UserAgent) {
newConnection.setHeader("User-Agent", opts.UserAgent);
}
if (opts.PrivatePolicyUUID) {
newConnection.setHeader("X-MegaFuel-Policy-Uuid", opts.PrivatePolicyUUID);
if (policyUUID) {
console.log("X-MegaFuel-Policy-Uuid", policyUUID)
newConnection.setHeader("X-MegaFuel-Policy-Uuid", policyUUID);
}

const sponsorProvider = new ethers.JsonRpcProvider(
newConnection,
(this as any)._network,
Expand All @@ -106,8 +129,8 @@ export class PaymasterClient extends ethers.JsonRpcProvider {
polling: (this as any).polling
}
);

if (opts.PrivatePolicyUUID) {
if (policyUUID) {
return await sponsorProvider.send('eth_sendRawTransaction', [signedTx]);
}
}
Expand All @@ -129,4 +152,4 @@ export class PaymasterClient extends ethers.JsonRpcProvider {
async getBundleByUuid(bundleUuid: string): Promise<Bundle> {
return await this.send('pm_getBundleByUuid', [bundleUuid])
}
}
}
22 changes: 7 additions & 15 deletions src/sponsorclient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { FetchRequest, JsonRpcApiProviderOptions, Networkish } from "ethers"
import { PaymasterClient } from "./paymasterclient"
import type { AddressLike } from "ethers/src.ts/address"
import type { BigNumberish } from "ethers/src.ts/utils"
import {ethers, FetchRequest, JsonRpcApiProviderOptions, Networkish} from 'ethers'
import type {AddressLike} from 'ethers/src.ts/address'
import type {BigNumberish} from 'ethers/src.ts/utils'

export enum WhitelistType {
FromAccountWhitelist = 'FromAccountWhitelist',
Expand Down Expand Up @@ -43,12 +42,8 @@ export type PolicySpendData = {
ChainID: number
}

export class SponsorClient extends PaymasterClient {
constructor(
url?: string | FetchRequest,
network?: Networkish,
options?: JsonRpcApiProviderOptions
) {
export class SponsorClient extends ethers.JsonRpcProvider {
constructor(url?: string | FetchRequest, network?: Networkish, options?: JsonRpcApiProviderOptions) {
super(url, network, options)
}

Expand All @@ -68,14 +63,11 @@ export class SponsorClient extends PaymasterClient {
return this.send('pm_getWhitelist', [params])
}

async getUserSpendData(
fromAddress: AddressLike,
policyUUID: string
): Promise<UserSpendData> {
async getUserSpendData(fromAddress: AddressLike, policyUUID: string): Promise<UserSpendData> {
return this.send('pm_getUserSpendData', [fromAddress, policyUUID])
}

async getPolicySpendData(policyUUID: string): Promise<PolicySpendData> {
return this.send('pm_getPolicySpendData', [policyUUID])
}
}
}
52 changes: 50 additions & 2 deletions tests/paymaster.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
transformIsSponsorableResponse,
transformToGaslessTransaction,
delay, transformSponsorTxResponse, transformBundleResponse,
privatePaymasterClient,
} from './utils'
import {TOKEN_CONTRACT_ADDRESS, CHAIN_ID, RECIPIENT_ADDRESS} from './env'
import {ethers} from 'ethers'
import { TOKEN_CONTRACT_ADDRESS, CHAIN_ID, RECIPIENT_ADDRESS } from './env'
import { ethers } from 'ethers'
import { SendRawTransactionOptions } from '../src'

let TX_HASH = ''

Expand Down Expand Up @@ -96,4 +98,50 @@ describe('paymasterQuery', () => {
expect(sponsorTx.TxHash).toEqual(tx.TxHash)
}, 13000)
})



/**
* Test for checking if a private policy transaction is sponsorable.
*/
describe('isSponsorable', () => {
test('should successfully determine if transaction is sponsorable', async () => {
const tokenContract = new ethers.Contract(TOKEN_CONTRACT_ADDRESS, tokenAbi, wallet)
const tokenAmount = ethers.parseUnits('0', 18)
const nonce = await privatePaymasterClient.getTransactionCount(wallet.address, 'pending')

const transaction = await tokenContract.transfer.populateTransaction(RECIPIENT_ADDRESS.toLowerCase(), tokenAmount)
transaction.from = wallet.address
transaction.nonce = nonce
transaction.gasLimit = BigInt(100000)
transaction.chainId = BigInt(CHAIN_ID)
transaction.gasPrice = BigInt(0)

const safeTransaction = {
...transaction,
gasLimit: transaction.gasLimit.toString(),
chainId: transaction.chainId.toString(),
gasPrice: transaction.gasPrice.toString(),
}

console.log('Prepared transaction:', safeTransaction)

const resRaw = await privatePaymasterClient.isSponsorable(safeTransaction)
const res = transformIsSponsorableResponse(resRaw)
expect(res.Sponsorable).toEqual(true)

const txOpt: SendRawTransactionOptions = {
UserAgent: "TEST USER AGENT"
};

const signedTx = await wallet.signTransaction(safeTransaction)
try {
const tx = await privatePaymasterClient.sendRawTransaction(signedTx,txOpt)
TX_HASH = tx
console.log('Transaction hash received:', TX_HASH)
} catch (error) {
console.error('Transaction failed:', error)
}
}, 100000) // Extends the default timeout as this test involves network calls
})
})
Loading

0 comments on commit 1150f05

Please sign in to comment.