Skip to content

How to use a Turnkey signer with permissionless.js

Turnkey is a key infrastructure provider with a great developer API and a powerful security policy engine.

By combining permissionless.js with Turnkey, you can create custodial AA wallets whose security is provided by Turnkey, with powerful functionalities such as sponsoring gas, batching transactions, etc.

Setup

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

  • Refer to the Turnkey documentation site for instructions on setting up an application with the Turnkey.
  • For a quick start, Turnkey provides examples, available here.

Integration

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

Create the TurnkeyClient and a Turnkey viem account

After following the Turnkey documentation, you will have access to a TurnkeyClient. An example is shown below that you can pass as an owner to createeSmartAccountClient:

import { TurnkeyClient } from "@turnkey/http"
import { createAccount } from "@turnkey/viem"
import { createWalletClient, http } from "viem"
 
// Param options here will be specific to your project.  See the Turnkey docs for more info.
const turnkeyClient = new TurnkeyClient({ baseUrl: "" }, stamper)
 
const turnkeyAccount = await createAccount({
	client: turnkeyClient,
	organizationId: subOrganizationId, // Your subOrganization id
	signWith: signWith, // Your suborganization `signWith` param.
})
 
// Create a wallet client from the turnkeyAccount
const smartAccountOwner = createWalletClient({
	account: turnkeyAccount,
	transport: http("https://rpc.ankr.com/eth_sepolia"),
})

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
		},
	},
})