Skip to content

Commit

Permalink
chore: paymaster first draft (#19)
Browse files Browse the repository at this point in the history
chore: paymaster first draft
  • Loading branch information
joepegler authored Mar 13, 2024
1 parent 01d4820 commit d5cfd88
Show file tree
Hide file tree
Showing 17 changed files with 182 additions and 10 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
PRIVATE_KEY=
BUNDLER_URL=https://bundler.biconomy.io/api/v2/80001/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44
BUNDLER_URL=
PAYMASTER_URL=
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Build
on:
pull_request:

types: [opened, reopened, synchronize, ready_for_review]
jobs:
build:
name: build
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: coverage
on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
jobs:
coverage:
name: coverage
Expand All @@ -15,4 +16,5 @@ jobs:
run: bun run test:ci
env:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
BUNDLER_URL: ${{ secrets.BUNDLER_URL }}
BUNDLER_URL: ${{ secrets.BUNDLER_URL }}
PAYMASTER_URL: ${{ secrets.PAYMASTER_URL }}
1 change: 1 addition & 0 deletions .github/workflows/pr-lint.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: pr lint
on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
jobs:
enforce_title:
name: pr lint
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/size-report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: size report
on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
size-report:
name: size report
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Clone repository
uses: actions/checkout@v3

- name: Install dependencies
uses: ./.github/actions/install-dependencies

- name: Report bundle size
uses: andresz1/size-limit-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
package_manager: bun
14 changes: 13 additions & 1 deletion .size-limit.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,21 @@
"limit": "10 kB"
},
{
"name": "core (tree-shaking)",
"name": "smartAccount (tree-shaking)",
"path": "./dist/_esm/index.js",
"limit": "5 kB",
"import": "{ createSmartAccount }"
},
{
"name": "bundler (tree-shaking)",
"path": "./dist/_esm/bundler/index.js",
"limit": "5 kB",
"import": "{ createBundlerClient }"
},
{
"name": "paymaster (tree-shaking)",
"path": "./dist/_esm/paymaster/index.js",
"limit": "5 kB",
"import": "{ createPaymasterClient }"
}
]
Binary file modified bun.lockb
Binary file not shown.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"typings": "./dist/_types/index.d.ts",
"homepage": "https://biconomy.io",
"sideEffects": false,
"name": "@biconomy/core",
"name": "@biconomy/sdk",
"author": "Biconomy",
"version": "0.0.1",
"description": "sdk for account abstraction, smart accounts, erc-4337 and erc-7579.",
Expand Down Expand Up @@ -54,7 +54,7 @@
"build:cjs": "tsc --project ./tsconfig/tsconfig.cjs.json && tsc-alias -p ./tsconfig/tsconfig.cjs.json && echo > ./dist/_cjs/package.json '{\"type\":\"commonjs\"}'",
"build:esm": "tsc --project ./tsconfig/tsconfig.esm.json && tsc-alias -p ./tsconfig/tsconfig.esm.json && echo > ./dist/_esm/package.json '{\"type\": \"module\",\"sideEffects\":false}'",
"build:types": "tsc --project ./tsconfig/tsconfig.types.json && tsc-alias -p ./tsconfig/tsconfig.types.json",
"clean": "rimraf ./dist/_esm ./dist/_cjs ./dist/_types ./src/tsconfig",
"clean": "rimraf ./dist/_esm ./dist/_cjs ./dist/_types ./dist/tsconfig",
"test": "vitest dev -c ./tests/vitest.config.ts",
"test:ci": "CI=true vitest -c ./tests/vitest.config.ts --coverage",
"size": "size-limit",
Expand All @@ -78,6 +78,7 @@
"simple-git-hooks": "^2.9.0",
"size-limit": "^11",
"tsc-alias": "^1.8.8",
"tslib": "^2.6.2",
"typedoc": "^0.25.9",
"vitest": "^1.3.1"
},
Expand Down
17 changes: 17 additions & 0 deletions src/paymaster/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { sponsorUserOperation } from "./sponsorUserOperation.js"

export type PaymasterRpcSchema = [
{
Method: "eth_chainId"
Params: []
ReturnType: bigint
}
]

export type PaymasterActions = Record<
"sponsorUserOperation",
() => Promise<number>
>
export const paymasterActions = () => (): PaymasterActions => ({
sponsorUserOperation: () => sponsorUserOperation()
})
Empty file.
3 changes: 3 additions & 0 deletions src/paymaster/actions/sponsorUserOperation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const sponsorUserOperation = async () => {
return 1
}
56 changes: 56 additions & 0 deletions src/paymaster/createPaymasterClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
type Account,
type Chain,
type Client,
type PublicClientConfig,
type Transport,
createClient
} from "viem"
import {
type PaymasterActions,
type PaymasterRpcSchema,
paymasterActions
} from "./actions"

export type PaymasterClient<
TChain extends Chain | undefined = Chain | undefined
> = Client<
Transport,
TChain,
Account | undefined,
PaymasterRpcSchema,
PaymasterActions
>

/**
* Creates a Paymaster Client with a given [Transport](https://viem.sh/docs/clients/intro.html) configured for a [Chain](https://viem.sh/docs/clients/chains.html).
*
* A Paymaster Client is an interface to "paymaster endpoints" [JSON-RPC API](https://docs..io/reference/verifying-paymaster/endpoints) methods such as sponsoring user operation, etc through Paymaster Actions.
*
* @param config - {@link PublicClientConfig}
* @returns A Paymaster Client. {@link PaymasterClient}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { polygonMumbai } from 'viem/chains'
*
* const PaymasterClient = createPaymasterClient({
* chain: polygonMumbai,
* transport: http("https://paymaster.biconomy.io/api/v1/80001/YOUR_API_KEY_HERE"),
* })
*/
export const createPaymasterClient = <
transport extends Transport = Transport,
chain extends Chain | undefined = undefined
>(
parameters: PublicClientConfig<transport, chain>
): PaymasterClient => {
const { key = "public", name = "Paymaster Client" } = parameters
const client = createClient({
...parameters,
key,
name,
type: "PaymasterClient"
})
return client.extend(paymasterActions())
}
3 changes: 3 additions & 0 deletions src/paymaster/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type { PaymasterRpcSchema, PaymasterActions } from "./actions/index.js"
export { paymasterActions } from "./actions/index.js"
export { createPaymasterClient } from "./createPaymasterClient.js"
18 changes: 18 additions & 0 deletions src/paymaster/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Extracts the chain ID from a paymaster URL.
* @param url - The bundler URL.
* @returns The extracted chain ID.
* @throws Error if the chain ID cannot be extracted or is invalid.
*/
export const extractChainIdFromPaymasterUrl = (url: string): number => {
try {
const regex = /\/api\/v\d+\/(\d+)\//
const match = regex.exec(url)
if (!match) {
throw new Error("Invalid URL format")
}
return Number.parseInt(match[1])
} catch (error) {
throw new Error("Invalid chain id")
}
}
4 changes: 1 addition & 3 deletions tests/account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,8 @@ describe("Biconomy Smart Account core tests", () => {

test("Should get account address + nonce", async () => {
const address = smartAccount.address
console.log("Smart Account Address: ", address)

const nonce = await smartAccount.getNonce()
console.log("Smart Account Nonce: ", nonce)
expect(address).toBeTypeOf("string")
})

test("Should sign a user operation", async () => {
Expand Down
33 changes: 33 additions & 0 deletions tests/paymaster.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { http } from "viem"
import { describe, expect, it } from "vitest"

import { privateKeyToAccount } from "viem/accounts"
import { getChain } from "../src/account/utils/helpers.js"
import { createPaymasterClient } from "../src/paymaster/createPaymasterClient.js"
import { extractChainIdFromPaymasterUrl } from "../src/paymaster/utils/helpers.js"

describe("Paymaster tests", () => {
const paymasterUrl = process.env.PAYMASTER_URL ?? ""
const chainId = extractChainIdFromPaymasterUrl(paymasterUrl)
const chain = getChain(chainId)
const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`)

it("Should have the properties of a viem client", async () => {
const paymasterClient = createPaymasterClient({
chain,
transport: http(paymasterUrl)
})
expect(paymasterClient.uid).toBeDefined()
expect(paymasterClient?.chain?.id).toBe(chainId)
expect(paymasterClient.pollingInterval).toBeDefined()
})

it("Should have a paymaster specific action", async () => {
const paymasterClient = createPaymasterClient({
chain,
transport: http(paymasterUrl)
})
const result = await paymasterClient.sponsorUserOperation()
expect(result).toBeTruthy()
})
})
2 changes: 1 addition & 1 deletion tests/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const envCheck = () => {
const fields = ["BUNDLER_URL", "PRIVATE_KEY"]
const fields = ["BUNDLER_URL", "PRIVATE_KEY", "PAYMASTER_URL"]
const errorFields = fields.filter((field) => !process.env[field])
if (errorFields.length) {
throw new Error(
Expand Down

0 comments on commit d5cfd88

Please sign in to comment.