Skip to content

How to use a Passport Protocol signer with permissionless.js

Passport is an MPC-based programmable, distributed, and non-custodial key management system, that allows users to generate wallets, scoped to their application, either via user Passkeys or any developer defined authentication method. Our signer allows you to sign messages and transactions with a Passport Network account.

Setup

To use Passport with permissionless.js, you'll first need to make sure you have configured a scope for your application. For this you can follow the guides below:

  • Refer to the Passport documentation for instructions on setting up your application with Passport.
  • For a primer on setting up your scope you can check here.

Integration

Integrating permissionless.js with Passport is straightforward after setting up the project. Passport provides an Externally Owned Account (EOA) wallet to use as a signer with permissionless.js accounts.

Create the Passport signer

After following the Passport documentation, you will have access to a Passport WalletClient object that you can pass as an owner to createeSmartAccountClient, both examples show how to register a user but if you already have a registered user you can skip the registration step. For Developer Owned Auth, the authentication is handled on the developer's side. For more detail on both you can check the authentication guide.

Passkey Signer
import { Passport, TESTNET_RSA_PUBLIC_KEY } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";
import { createPassportClient } from "@0xpass/passport-viem";=
import { http } from "viem";
import { sepolia } from "viem/chains";
 
const passport = new Passport({
  scope_id: "scope_id",
  signer: new WebauthnSigner({
    rpId: "rpId",
    rpName: "rpName",
  }),
  enclave_public_key: TESTNET_RSA_PUBLIC_KEY,
});
 
const fallbackProvider = http("https://rpc.ankr.com/eth_sepolia");
 
await passport.setupEncryption();
await passport.register({
  username: "test",
  userDisplayName: "test",
});
 
const [authenticatedHeader] = await passport.authenticate({
  username: "test",
  userDisplayName: "test",
});
 
const smartAccountOwner = await createPassportClient(
  authenticatedHeader,
  fallbackProvider,
  sepolia,
  "https://tiramisu.0xpass.io"
);

Use with permissionless.js

SimpleAccount
import { createSmartAccountClient } from "permissionless"
import { toSimpleSmartAccount } from "permissionless/accounts"
import { createPublicClient, http } from "viem"
import { sepolia } from "viem/chains"
import { createPimlicoClient } from "permissionless/clients/pimlico"
import { entryPoint07Address } from "viem/account-abstraction"
 
const publicClient = createPublicClient({
	chain: sepolia, // or whatever chain you are using
	transport: http(),
})
 
const pimlicoUrl = `https://api.pimlico.io/v2/sepolia/rpc?apikey=<PIMLICO_API_KEY>`
 
const pimlicoClient = createPimlicoClient({
	transport: http(pimlicoUrl),
	entryPoint: {
		address: entryPoint07Address,
		version: "0.7",
	},
})
 
const simpleSmartAccount = await toSimpleSmartAccount({
	owner: smartAccountOwner,
	client: publicClient,
	entryPoint: {
		address: entryPoint07Address,
		version: "0.7",
	},
})
 
const smartAccountClient = createSmartAccountClient({
	account: simpleSmartAccount,
	chain: sepolia,
	bundlerTransport: http(pimlicoUrl),
	paymaster: pimlicoClient,
	userOperation: {
		estimateFeesPerGas: async () => {
			return (await pimlicoClient.getUserOperationGasPrice()).fast
		},
	},
})