Skip to content

Commit

Permalink
feat: add paymaster top up
Browse files Browse the repository at this point in the history
  • Loading branch information
akasuv committed Sep 11, 2023
1 parent 3718f39 commit 68e3008
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 9 deletions.
93 changes: 93 additions & 0 deletions src/ABIs/TokenReceiverAbi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
export const TokenReceiverAbi = [
{
inputs: [{ internalType: "address", name: "owner", type: "address" }],
stateMutability: "nonpayable",
type: "constructor",
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: "address",
name: "from",
type: "address",
},
{ indexed: false, internalType: "address", name: "to", type: "address" },
{
indexed: false,
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "Deposit",
type: "event",
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: "address", name: "user", type: "address" },
{
indexed: true,
internalType: "address",
name: "newOwner",
type: "address",
},
],
name: "OwnershipTransferred",
type: "event",
},
{
anonymous: false,
inputs: [
{ indexed: false, internalType: "address", name: "to", type: "address" },
{
indexed: false,
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "Withdraw",
type: "event",
},
{
inputs: [{ internalType: "address", name: "to", type: "address" }],
name: "depositTo",
outputs: [],
stateMutability: "payable",
type: "function",
},
{
inputs: [{ internalType: "address", name: "", type: "address" }],
name: "deposits",
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "owner",
outputs: [{ internalType: "address", name: "", type: "address" }],
stateMutability: "view",
type: "function",
},
{
inputs: [{ internalType: "address", name: "newOwner", type: "address" }],
name: "transferOwnership",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{ internalType: "address", name: "to", type: "address" },
{ internalType: "uint256", name: "amount", type: "uint256" },
],
name: "withdraw",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
];
1 change: 1 addition & 0 deletions src/ABIs/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { KernelAccountAbi } from "./KernelAccountAbi";
export { KernelFactoryAbi } from "./KernelFactoryAbi";
export { EntryPointAbi } from "./EntryPointAbi";
export { TokenReceiverAbi } from "./TokenReceiverAbi";
4 changes: 2 additions & 2 deletions src/CyberAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class CyberAccount {
public owner: CyberAccountOwner;
public chain: Partial<Chain> & { id: Chain["id"]; rpcUrl?: string };
public factory: CyberFactory;
private publicClient: PublicClient;
public publicClient: PublicClient;
public address: Address;
public isDeployed?: boolean;
private initCode?: Hex;
Expand All @@ -56,7 +56,7 @@ class CyberAccount {
this.address = this.factory.calculateContractAccountAddress();
this.publicClient = this.getRpcClient(chain);
this.bundler = bundler.connect(chain.id);
this.paymaster = paymaster?.connect(chain.id, this.address);
this.paymaster = paymaster?.connect(this);
}

private getRpcClient(
Expand Down
69 changes: 65 additions & 4 deletions src/CyberPaymaster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import {
custom,
type CustomTransport,
RpcRequestError,
type PublicClient,
BaseError,
createWalletClient,
ChainDoesNotSupportContract,
} from "viem";
import { mainnet } from "viem/chains";
import type {
Expand All @@ -13,6 +17,9 @@ import type {
EstimatedPaymasterData,
SponsoredPaymasterData,
} from "./types";
import { TokenReceiverAbi } from "./ABIs";
import CyberAccount from "./CyberAccount";
import { supportedChains } from "./rpcClients";

type Params = {
appId: string;
Expand All @@ -26,6 +33,13 @@ class CyberPaymaster {
private clients: Record<number, PaymasterClient<CustomTransport>>;
public generateJwt: (cyberAccountAddress: Address) => Promise<string>;
public jwt?: string;
public publicClients: Record<number, PublicClient>;
public cyberAccount?: CyberAccount;
static testnetTokenReceiverAddress: Address =
"0x52b90f8e69ac72fe0f46726eadda13835cbb01fa";
static mainnetTokenReceiverAddress: Address =
"0xcd97405fb58e94954e825e46db192b916a45d412";

static needAuthMethods = [
"cc_sponsorUserOperation",
"cc_rejectUserOperation",
Expand All @@ -36,9 +50,10 @@ class CyberPaymaster {
this.rpcUrl = rpcUrl;
this.generateJwt = generateJwt;
this.clients = {};
this.publicClients = {};
}

public connect(chainId: number, cyberAccountAddress: Address) {
public connect(cyberAccount: CyberAccount) {
const self = this;
let id = 0;

Expand All @@ -53,7 +68,7 @@ class CyberPaymaster {
if (self.jwt) {
jwt = self.jwt;
} else {
jwt = await self.generateJwt(cyberAccountAddress);
jwt = await self.generateJwt(cyberAccount.address);
self.jwt = jwt;
}

Expand All @@ -68,7 +83,7 @@ class CyberPaymaster {
};

const response = await fetch(
`${self.rpcUrl}?chainId=${chainId}&appId=${self.appId}`,
`${self.rpcUrl}?chainId=${cyberAccount.chain.id}&appId=${self.appId}`,
{
method: "POST",
body: JSON.stringify(requestBody),
Expand Down Expand Up @@ -129,7 +144,9 @@ class CyberPaymaster {
},
}));

this.clients[chainId] = client;
this.clients[cyberAccount.chain.id] = client;
this.publicClients[cyberAccount.chain.id] = cyberAccount.publicClient;
this.cyberAccount = cyberAccount;

return this;
}
Expand Down Expand Up @@ -163,6 +180,50 @@ class CyberPaymaster {
?.listPendingUserOperations(address)
.then((res) => res.userOperations);
}

public async topUp({
sender,
amount,
chainId,
to,
}: {
sender?: Address;
amount: bigint;
chainId: number;
to?: Address;
}) {
const chain = supportedChains.find((chain) => chain.id === chainId);

if (!chain) {
throw new ChainDoesNotSupportContract({
//@ts-ignore
chain: {
//@ts-ignore
name: chainId.toString(),
},
contract: { name: "CyberPaymaster Token Receiver" },
});
}

const walletClient = createWalletClient({
chain,
// @ts-ignore
transport: custom(globalThis.ethereum),
});

const { request } = await this.publicClients[chain.id]?.simulateContract({
account: sender || this.cyberAccount?.owner.address,
address: chain.testnet
? CyberPaymaster.testnetTokenReceiverAddress
: CyberPaymaster.mainnetTokenReceiverAddress,
abi: TokenReceiverAbi,
functionName: "depositTo",
args: [to || this.cyberAccount?.address],
value: amount,
});

return await walletClient.writeContract(request);
}
}

export default CyberPaymaster;
14 changes: 11 additions & 3 deletions src/rpcClients.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { createPublicClient, http, type PublicClient } from "viem";
import {
createPublicClient,
http,
type PublicClient,
type WalletClient,
createWalletClient,
custom,
Chain,
} from "viem";
import {
optimismGoerli,
optimism,
Expand All @@ -21,7 +29,7 @@ const testnetChains = [
];
const mainnetChains = [optimism, polygon, base, linea, arbitrum];

const supportedChains = [...testnetChains, ...mainnetChains];
const supportedChains: Chain[] = [...testnetChains, ...mainnetChains];

const publicClients: Record<string, (url?: string) => PublicClient> =
supportedChains.reduce(
Expand All @@ -36,4 +44,4 @@ const publicClients: Record<string, (url?: string) => PublicClient> =
{}
);

export { publicClients };
export { publicClients, supportedChains };

0 comments on commit 68e3008

Please sign in to comment.