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.
Setup
To use Dfns with permissionless.js, first create an application that integrates with Dfns.
- Refer to the Dfns documentation site for instructions on setting up an application with the Dfns.
Integration
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,
signer,
})
return DfnsWallet.init({
walletId,
dfnsClient,
maxRetries: 10,
})
}
const sepoliaWallet = await initDfnsWallet(SEPOLIA_WALLET_ID)
const account = toAccount(sepoliaWallet as AccountSource)
const walletClient = createWalletClient({
account,
transport: http("https://rpc.ankr.com/eth_sepolia"),
})
const smartAccountSigner = walletClientToSmartAccountSigner(walletClient)
Use with permissionless.js
SimpleAccount
import { signerToSimpleSmartAccount } from "permissionless/accounts"
import { createPimlicoBundlerClient, createPimlicoPaymasterClient } from "permissionless/clients/pimlico"
import { createPublicClient, http } from "viem"
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"
import { sepolia } from "viem/chains"
const pimlicoRpcUrl = `https://api.pimlico.io/v2/sepolia/rpc?apikey=<api-key>`
const pimlicoPaymaster = createPimlicoPaymasterClient({
transport: http(pimlicoRpcUrl),
entryPoint: ENTRYPOINT_ADDRESS_V06
})
const bundlerClient = createPimlicoBundlerClient({
transport: http(pimlicoRpcUrl),
entryPoint: ENTRYPOINT_ADDRESS_V06,
})
const publicClient = createPublicClient({
transport: http("https://rpc.ankr.com/eth_sepolia"),
chain: sepolia,
})
const smartAccount = await signerToSimpleSmartAccount(publicClient, {
signer: smartAccountSigner,
entryPoint: ENTRYPOINT_ADDRESS_V06,
})
const smartAccountClient = createSmartAccountClient({
account: smartAccount,
entryPoint: ENTRYPOINT_ADDRESS_V06,
chain: sepolia, // or whatever chain you are using
bundlerTransport: http(pimlicoRpcUrl, {
timeout: 30_000 // optional
}),
middleware: {
gasPrice: async () => (await bundlerClient.getUserOperationGasPrice()).fast,
sponsorUserOperation: pimlicoPaymaster.sponsorUserOperation,
},
})