Skip to content

How to use a DFNS signer with permissionless.js

Dfns is an MPC/TSS Wallet-as-a-Service API/SDK provider. Dfns aims to optimize the balance of security and UX by deploying key shares into a decentralized network on the backend while enabling wallet access via biometric open standards on the frontend like Webauthn. Reach out here to set up a sandbox environment to get started.


To use Dfns with permissionless.js, first create an application that integrates with Dfns.


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

Set up Dfns

After following the Dfns documentation, you will have access to a dfnsWallet object as shown below:

import { DfnsWallet } from "@dfns/lib-viem"
import { DfnsApiClient } from "@dfns/sdk"
import { AsymmetricKeySigner } from "@dfns/sdk-keysigner"
import { walletClientToSmartAccountSigner } from "permissionless"
import { AccountSource, createWalletClient, http } from "viem"
import { toAccount } from "viem/accounts"
const initDfnsWallet = (walletId: string) => {
	const signer = new AsymmetricKeySigner({
		privateKey: DFNS_PRIVATE_KEY,
		credId: DFNS_CRED_ID,
		appOrigin: DFNS_APP_ORIGIN,
	const dfnsClient = new DfnsApiClient({
		appId: DFNS_APP_ID,
		authToken: DFNS_AUTH_TOKEN,
		baseUrl: DFNS_API_URL,
	return DfnsWallet.init({
		maxRetries: 10,
const sepoliaWallet = await initDfnsWallet(SEPOLIA_WALLET_ID)
const account = toAccount(sepoliaWallet as AccountSource)
const walletClient = createWalletClient({
	transport: http(""),
const smartAccountSigner = walletClientToSmartAccountSigner(walletClient)

Use with permissionless.js

import { signerToSimpleSmartAccount } from "permissionless/accounts"
import { createPublicClient, http } from "viem"
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"
import { sepolia } from "viem/chains"
export const publicClient = createPublicClient({
	transport: http(""),
	chain: sepolia,
const smartAccount = await signerToSimpleSmartAccount(publicClient, {
	signer: smartAccountSigner,
	factoryAddress: "0x9406Cc6185a346906296840746125a0E44976454",
	entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",