Skip to content

Commit

Permalink
Merge branch 'main' of github.com:pimlicolabs/docs
Browse files Browse the repository at this point in the history
  • Loading branch information
plusminushalf committed Jul 13, 2024
2 parents 7492d1a + dc8beb0 commit 4e67922
Show file tree
Hide file tree
Showing 30 changed files with 1,258 additions and 872 deletions.
6 changes: 3 additions & 3 deletions docs/pages/infra/bundler/usage.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# How to use the bundler

:::tip[Tip]
We recommend using [permissionless.js](/permissionless/reference/bundler-actions/sendUserOperation) as the SDK to interact with the bundler as it provides type-safe wrappers for all bundler methods.
We recommend using [permissionless.js](/permissionless/reference/bundler-actions/sendUserOperation) as the SDK to interact with the bundler as it provides type-safe wrappers for all bundler methods.
:::

ERC-4337 bundlers are relayers that bundle user operations into transactions and submit them to the blockchain. You can interact with bundlers using stndard JSON-RPC requests.
ERC-4337 bundlers are relayers that bundle user operations into transactions and submit them to the blockchain. You can interact with bundlers using standard JSON-RPC requests.

To get access to the bundler, you need to use your [Pimlico API key](https://dashboard.pimlico.io/apikeys). Using the API key, you can make the following JSON-RPC requests to the bundler:

Expand All @@ -17,4 +17,4 @@ To get access to the bundler, you need to use your [Pimlico API key](https://das
- [pimlico_getUserOperationGasPrice](/infra/bundler/endpoints/pimlico_getUserOperationGasPrice)
- [pimlico_getUserOperationStatus](/infra/bundler/endpoints/pimlico_getUserOperationStatus)

If you would like an end-to-end example of how to use the bundler, please refer to [tutorial 1](/permissionless/tutorial/tutorial-1) of the permissionless.js documentation.
If you would like an end-to-end example of how to use the bundler, please refer to [tutorial 1](/permissionless/tutorial/tutorial-1) of the permissionless.js documentation.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Below are the contract addresses for the ERC-20 Paymaster contracts that are cur
| sepolia | [0x000000000041F3aFe8892B48D88b6862efe0ec8d](https://sepolia.etherscan.io/address/0x000000000041F3aFe8892B48D88b6862efe0ec8d) | [USDC: 0x1c7D...7238](https://sepolia.etherscan.io/address/0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238) |
| base-sepolia | [0x00000000002E3A39aFEf1132214fEee5a55ce127](https://sepolia.basescan.org/address/0x00000000002E3A39aFEf1132214fEee5a55ce127) | [USDC: 0x036C...CF7e](https://sepolia.basescan.org/address/0x036CbD53842c5426634e7929541eC2318f3dCF7e) |
| base | [0x0000000000164F4b0508aCf9c7443C9B682E4091](https://basescan.org/address/0x0000000000164F4b0508aCf9c7443C9B682E4091) | [USDC: 0x8335...2913](https://basescan.org/address/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913) |
| bob | [0x000000003CE83Ad13E6A53658Eb03179a37411AE](https://explorer.gobob.xyz/address/0x000000003CE83Ad13E6A53658Eb03179a37411AE) | [WBTC: 0x03c7...cfa3](https://explorer.gobob.xyz/address/0x03c7054bcb39f7b2e5b2c7acb37583e32d70cfa3) |
| bob | [0x00000000D1925888A08895393501545Ea885fbA8](https://explorer.gobob.xyz/address/0x00000000D1925888A08895393501545Ea885fbA8) | [TBTC: 0xBBa2...c2e2](https://explorer.gobob.xyz/address/0xBBa2eF945D523C4e2608C9E1214C2Cc64D4fc2e2) |
| polygon | [0x00000000007672027B2DFbFc9FB2dd2842092EC3](https://polygonscan.com/address/0x00000000007672027B2DFbFc9FB2dd2842092EC3) | [USDC: 0x3c49...3359](https://polygonscan.com/address/0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359) |
| optimism | [0x000000000055a2B69645b4B69B65De6fF00B7468](https://optimistic.etherscan.io/address/0x000000000055a2B69645b4B69B65De6fF00B7468) | [USDC: 0x0b2C...Ff85](https://optimistic.etherscan.io/address/0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85) |
| bsc | [0x0000000000bB595b6Af77D0818a48464e144Fa35](https://bscscan.com/address/0x0000000000bB595b6Af77D0818a48464e144Fa35) | [USDC: 0x8AC7...580d](https://bscscan.com/address/0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d) |
Expand Down
152 changes: 152 additions & 0 deletions docs/pages/infra/paymaster/erc20-paymaster/guides.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# ERC-20 Paymaster Guides

## Estimating Approval Amounts

When using Pimlico's ERC20-paymaster, the paymaster needs approval to spend funds on the payer's behalf. The amount to approve must be atleast equal to the userOperation's prefund value.

You can use the helper function below to get the required approval amount.

```ts
// Calculates amount of tokens that need to be approved for ERC20 paymaster to sponsor userOperation
const getApprovalAmount = async ({
publicClient,
paymasterAddress,
userOperation,
}: EstimateParams) => {
const erc20Paymaster = getContract({
client: publicClient,
address: paymasterAddress,
abi: parseAbi([
"function getPrice() view returns (uint192)",
"function priceMarkup() view returns (uint32)",
"function refundPostOpCost() view returns (uint)",
]),
});

const requiredGas =
userOperation.verificationGasLimit +
userOperation.callGasLimit +
(userOperation.paymasterVerificationGasLimit || 0n) +
(userOperation.paymasterPostOpGasLimit || 0n) +
userOperation.preVerificationGas;

const requiredPreFund = requiredGas * userOperation.maxFeePerGas;

// fetch onchain info
const markup = BigInt(await erc20Paymaster.read.priceMarkup());
const refundPostOpCost = BigInt(await erc20Paymaster.read.refundPostOpCost());
const tokenPrice = BigInt(await erc20Paymaster.read.getPrice());

const maxFeePerGas = userOperation.maxFeePerGas;

return (
((requiredPreFund + refundPostOpCost * maxFeePerGas) *
markup *
tokenPrice) /
(BigInt(1e18) * BigInt(1e6))
);
};
```

## Estimating Gas Cost

The helper function below shows an example on how to accurately estimate the gas cost of a UserOperation when using Pimlico's paymasters. The function expects a valid and signed UserOperation.

```ts
// Returns the cost of the UserOperation (denominated in token)
export const estimateCost = async ({
userOperation,
publicClient,
paymasterAddress,
}: EstimateParams) => {
const beneficiary = privateKeyToAddress(generatePrivateKey());

const erc20Paymaster = getContract({
address: paymasterAddress,
abi: parseAbi(["function token() view returns (address)"]),
client: publicClient,
});
const erc20Token = await erc20Paymaster.read.token();

const multicall3Abi = parseAbi([
"struct Result { bool success; bytes returnData; }",
"struct Call3 { address target; bool allowFailure; bytes callData; }",
"function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData)",
]);

const entrypointAbi = parseAbi([
"struct PackedUserOperation { address sender; uint256 nonce; bytes initCode; bytes callData; bytes32 accountGasLimits; uint256 preVerificationGas; bytes32 gasFees; bytes paymasterAndData; bytes signature; }",
"function handleOps(PackedUserOperation[] calldata ops, address beneficiary)",
"error FailedOp(uint256 opIndex, string reason)",
"error FailedOpWithRevert(uint256 opIndex, string reason, bytes inner)",
"error PostOpReverted(bytes returnData)",
"error SignatureValidationFailed(address aggregator)",
]);
const handleOpsData = encodeFunctionData({
abi: entrypointAbi,
functionName: "handleOps",
args: [[getPackedUserOperation(userOperation)], beneficiary],
});

const getTokenBalanceData = encodeFunctionData({
abi: parseAbi(["function balanceOf(address) returns (uint)"]),
args: [userOperation.sender],
});

const multicallPayload = encodeFunctionData({
abi: multicall3Abi,
functionName: "aggregate3",
args: [
[
{
target: erc20Token,
callData: getTokenBalanceData,
allowFailure: true,
},
{
target: ENTRYPOINT_ADDRESS_V07,
callData: handleOpsData,
allowFailure: true,
},
{
target: erc20Token,
callData: getTokenBalanceData,
allowFailure: true,
},
],
],
});

const response = await publicClient.call({
to: "0xca11bde05977b3631167028862be2a173976ca11",
data: multicallPayload,
gasPrice: await publicClient.getGasPrice(),
});

if (!response.data) {
throw new Error("Failed to estimate erc20Paymaster's gas cost");
}

const [balBefore, handleOps, balAfter] = decodeAbiParameters(
multicall3Abi[0].outputs,
response.data,
)[0];

if (!balBefore.success || !balAfter.success) {
throw new Error("Failed to estimate erc20Paymaster's gas cost");
}

if (!handleOps.success) {
const parsedError = decodeErrorResult({
abi: entrypointAbi,
data: handleOps.returnData,
});

throw new Error(
`Failed to estimate erc20Paymaster's gas cost due to ${parsedError.args}`,
);
}

return hexToBigInt(balBefore.returnData) - hexToBigInt(balAfter.returnData);
};
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# How to debug dropped user operations

If a user operation is dropped in the mempool of the bundler after initially being accepted by it, the error can not be propagated by the bundler to the user. To debug what happened to these user operations, we recommend using the [User Operation Tracking](https://dashboard.pimlico.io/debugging/tracking) page on our dashboard, which will show you the exact flow of the user operation stage-by-stage through Pimlico's bundler with timestamps, including any errors it encounters.

An example screenshot of the User Operation Tracking page is shown below:

![User Operation Tracking page, showing a dropped user operation](/tracking.png)
27 changes: 27 additions & 0 deletions docs/pages/infra/platform/sponsorship-policies/webhook.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# How to use Sponsorship Policy webhook

Webhook allows you to receive real-time notifications when a sponsorship policy is triggered. You can use webhooks to approve or reject sponsoring userops. Start by going to the [sponsorship policies page](https://dashboard.pimlico.io/sponsorship-policies) on the Pimlico dashboard, clicking on the existing policy and clicking on the "Edit button".

Request is sent with POST, where body is a JSON object with the following structure:

```typescript
const body = {
type: 'sponsorshipPolicy.webhook',
data: {
object: {
userOperation,
entryPoint,
chainId,
sponsorshipPolicyId: sponsorshipPolicy.id
}
}
};
```

The returned value should be a JSON with the following structure:

```json
{
"sponsor": true // Boolean
}
```
25 changes: 25 additions & 0 deletions docs/pages/infra/platform/why-pimlico.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Why Pimlico

Are you looking to improve your app's user experience and wondering why you should use Pimlico as your account abstraction infrastructure provider?

Below are some reasons some of the best teams in crypto have chosen to build on Pimlico

## Developer-first experience

Pimlico is a platform built by developers for developers. We understand the importance of a great developer experience and have built our platform with that in mind.

This means you can expect clean, modern, well-typed SDKs, comprehensive documentation, and a support team that's comprised of devleopers who can help you with any issues you might encounter.

## Powerful features

When you build on Pimlico, you're not just getting a simple account abstraction platform. You're getting a powerful set of tools that can help you build the best user experience with the most powerful infrastructure in the space.

This means a comprehensive set of tools, charts, logs, configurations to give you all the scale, observability, security, and debugging capabilities you need to build with smart accounts, as well as accesss to 70+ chains with one API key and one, centrally-managed balance.

## Expert, veteran team

Our team has been working in the account abstraction space for years, and we have a deep understanding of the space. We are co-authors of some of the most important smart account standards, are constantly innovating at the frontier and can make sure you're always ahead of the curve. Our developer-focused team also means you can expect fast, helpful support whenever you need it, and new features being constantly added daily rather than quarterly.

## What's next?

If you're ready to get started, you can sign up to the [Pimlico dashboard](https://dashboard.pimlico.io) or [contact us](https://cal.com/team/pimlico/20min) to start building with Pimlico today, and join the ranks of some of the best teams in crypto such as Zora, WalletConnect, Daimo, Safe, and more.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# How to use ERC 7579 compatible smart accounts with permissionless.js
# How to use an ERC-7579 compatible smart account with permissionless.js

[ERC7579](https://eips.ethereum.org/EIPS/eip-7579) defines a standard for modular smart account interfaces. It also defines behavior for interoperability with minimal restrictions for accounts and modules.
[ERC-7579](https://eips.ethereum.org/EIPS/eip-7579) defines a standard for modular smart account interfaces. It also defines behavior for interoperability with minimal restrictions for accounts and modules.

Currently Safe and Kernel are the only smart accounts that implements ERC7579.
Currently Safe and Kernel are the only smart accounts that implements ERC-7579.

For this guide, we will use the `Safe smart account` as an example.
For this guide, we will use the Safe smart accounts as an example. If you would like to find out more about the Safe smart account, you can check out the [Safe-specific guide](/permissionless/how-to/accounts/use-safe-account).

This guide will show you how to create and use a ERC7579 compatible smart account with permissionless.js.
This guide will show you how to create and use a ERC-7579 compatible smart account with permissionless.js.

## Steps

Expand Down
33 changes: 21 additions & 12 deletions docs/pages/permissionless/how-to/signers/dynamic.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,30 +45,39 @@ export const App = () => {
Create the smart account client using the Dynamic signer. Note: DynamicWagmiConnector internally sets up the WagmiConfig, so there is no need to do it separately. This is where you would configure what smart account implementation (e.g. [Safe](/permissionless/how-to/accounts/use-safe-account), [Kernel](/permissionless/how-to/accounts/use-kernel-account), Biconomy, [TrustWallet](/permissionless/how-to/accounts/use-trustwallet-account) [SimpleAccount](/permissionless/how-to/accounts/use-simple-account)) and what paymaster logic you want to use.

```ts
import { createSmartAccountClient, walletClientToSmartAccountSigner } from "permissionless";
import { createSmartAccountClient, walletClientToSmartAccountSigner, ENTRYPOINT_ADDRESS_V06 } from "permissionless";
import { signerToSimpleSmartAccount } from "permissionless/accounts";
import { useWalletClient } from "wagmi";
import { createPublicClient, http, zeroAddress } from "viem";
import { sepolia } from "viem/chains";

const {
data: walletClient
data: walletClient
} = useWalletClient()

const publicClient = createPublicClient({
chain: sepolia, // or whatever chain you are using
transport: http()
})

const signer = walletClientToSmartAccountSigner(walletClient)

const simpleSmartAccountClient = await signerToSimpleSmartAccount(publicClient, {
entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
signer: signer,
factoryAddress: "0x9406Cc6185a346906296840746125a0E44976454"
entryPoint: ENTRYPOINT_ADDRESS_V06,
signer,
})

const smartAccountClient = createSmartAccountClient({
account: simpleSmartAccountClient,
chain: sepolia, // or whatever chain you are using
bundlerTransport: http("<bundler_endpoint>"),
entryPoint: ENTRYPOINT_ADDRESS_V06,
middleware: {
sponsorUserOperation: paymasterClient.sponsorUserOperation, // optional, if using a paymaster
},
account: simpleSmartAccountClient,
entryPoint: ENTRYPOINT_ADDRESS_V06,
chain: sepolia, // or whatever chain you are using
bundlerTransport: http("<bundler_endpoint>", {
timeout: 30_000 // optional
}),
middleware: {
gasPrice: async () => (await bundlerClient.getUserOperationGasPrice()).fast,
sponsorUserOperation: pimlicoPaymaster.sponsorUserOperation,
},
})
```

Expand Down
34 changes: 22 additions & 12 deletions docs/pages/permissionless/how-to/signers/privy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

permissionless.js allows you to plug in custom signers to control the accounts that you create. Privy is an embedded wallet provider that allows you to easily onboard users to your dapp. It is possible to use Privy as a signer with permissionless.js, allowing you to use Privy to create and control smart accounts and sign transactions.

Additionally you may want to look at Privy's guide on working with permissionless.js [here](https://docs.privy.io/guide/react/recipes/account-abstraction/pimlico).

::::steps

### Install the dependencies
Expand Down Expand Up @@ -56,31 +58,39 @@ useEffect(() => setActiveWallet(embeddedWallet), [embeddedWallet])
Create the smart account client using the Privy signer. This is where you would configure what smart account implementation (e.g. [Safe](/permissionless/how-to/accounts/use-safe-account), [Kernel](/permissionless/how-to/accounts/use-kernel-account), Biconomy, [TrustWallet](/permissionless/how-to/accounts/use-trustwallet-account), [SimpleAccount](/permissionless/how-to/accounts/use-simple-account)) and what paymaster logic you want to use.

```ts
import { createSmartAccountClient, walletClientToSmartAccountSigner } from "permissionless";
import { createSmartAccountClient, walletClientToSmartAccountSigner, ENTRYPOINT_ADDRESS_V06 } from "permissionless";
import { signerToSimpleSmartAccount } from "permissionless/accounts";
import { useWalletClient } from "wagmi";
import { createPublicClient, http, zeroAddress } from "viem";
import { sepolia } from "viem/chains";

const {
data: walletClient
} = useWalletClient()

const publicClient = createPublicClient({
chain: sepolia, // or whatever chain you are using
transport: http()
})

const signer = walletClientToSmartAccountSigner(walletClient)

const simpleSmartAccountClient = await signerToSimpleSmartAccount(publicClient, {
entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
signer: signer,
factoryAddress: "0x9406Cc6185a346906296840746125a0E44976454"
entryPoint: ENTRYPOINT_ADDRESS_V06,
signer,
})

const smartAccountClient = createSmartAccountClient({
account: safeAccount,
entryPoint: ENTRYPOINT_ADDRESS_V06,
chain: sepolia,
bundlerTransport: http("https://api.pimlico.io/v2/sepolia/rpc?apikey=API_KEY"),
middleware: {
gasPrice: async () => (await pimlicoBundlerClient.getUserOperationGasPrice()).fast, // use pimlico bundler to get gas prices, if using pimlico
sponsorUserOperation: paymasterClient.sponsorUserOperation, // optional
},
account: simpleSmartAccountClient,
entryPoint: ENTRYPOINT_ADDRESS_V06,
chain: sepolia, // or whatever chain you are using
bundlerTransport: http("<bundler_endpoint>", {
timeout: 30_000 // optional
}),
middleware: {
gasPrice: async () => (await bundlerClient.getUserOperationGasPrice()).fast,
sponsorUserOperation: pimlicoPaymaster.sponsorUserOperation,
},
})
```

Expand Down
4 changes: 3 additions & 1 deletion docs/pages/permissionless/how-to/signers/web3auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ After following the Web3Auth documentation, you will have access to a `web3auth`

### Use with permissionless.js

<SmartAccounts />
<SmartAccounts />

For a full example, see the [example permissionless + Web3Auth app](https://github.com/pimlicolabs/web3auth-demo/blob/main/src/components/web3auth/web3auth.tsx).
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# accountId

Gets the accountId of the smart account as defined in [ERC7579](https://eips.ethereum.org/EIPS/eip-7579). Check out [this guide](/permissionless/how-to/accounts/user-erc7579-actions) for a complete tutorial.
Gets the accountId of the smart account as defined in [ERC-7579](https://eips.ethereum.org/EIPS/eip-7579). Check out [this guide](/permissionless/how-to/accounts/use-erc7579-account) for a complete tutorial.

## Usage

Expand Down Expand Up @@ -32,4 +32,4 @@ The account id of the smart account.

- **Type:** `SmartAccount`

If your SmartAccountClient doesn't have an account, you should provide one here.
If your `SmartAccountClient` doesn't have an account, you should provide one here.
Loading

0 comments on commit 4e67922

Please sign in to comment.