Skip to main content

Use Turnkey with AbstractionKit

Turkey offers a flexible private key management solution that leverages AWS Nitros Systems to secure users keys.

To fully leverage the potential of Account Abstraction, consider combining Turnkey with AbstractionKit to enable a trusted recoverer. Enabling the Account recovery module will require an onchain transaction. To add convenience for your users, you can batch the recovery transactions and sponsor their gas fees.

Relevant links for additional information during this guide:

Installation

Install required dependencies

npm i abstractionkit && @turnkey/http && @turnkey/api-key-stamper && @turnkey/ethers

Create a Turkey account

Create an account and get the API keys on Turnkey's Dashboard. You will need:

  • Organization ID
  • Public API Key
  • Private API Key
  • Create a private/public key pair on Turkey dashboard. This is Guardian Account.

Configure .env file

Configure the values you created from Turkey dashboard in an .env file, along with a node endpoint.

// turnkey guardian
TURNKEY_PUBLIC_KEY=
TURNKEY_PRIVATE_KEY= // For this demo, we exported the private key of the guardian account. In production, use turkey api
TURNKEY_ORG_ID=
TURNKEY_WALLET_ADDRESS=

// candide
BUNDLER_URL=
JSON_RPC_NODE_PROVIDER=
OWNER_PUBLIC_ADDRESS=
NEW_ONWER_PUBLIC_ADDRESS=

Setup Guardian

This step shows how to contrust the calldata for creating the userop to add a guardian.

import { SocialRecoveryModule } from "abstractionkit";

const srm = new SocialRecoveryModule();

const enableModuleTx = srm.createEnableModuleMetaTransaction(
smartAccount.accountAddress
);
const addGuardianTx = srm.createAddGuardianWithThresholdMetaTransaction(
smartAccount.accountAddress,
process.env.TURNKEY_PUBLIC_KEY, // Turnkey Guardian Address
1n //threshold
);

let userOperation = await smartAccount.createUserOperation(
[enableModuleTx, addGuardianTx],
process.env.JSON_RPC_NODE_PROVIDER,
process.env.BUNDLER_URL,
)

Initiate Recovery

import { SafeAccountV0_2_0 as SafeAccount } from "abstractionkit";

import { TurnkeySigner } from "@turnkey/ethers";
import { TurnkeyClient } from "@turnkey/http";
import { ApiKeyStamper } from "@turnkey/api-key-stamper";

const turnkeyClient = new TurnkeyClient(
{ baseUrl: "https://api.turnkey.com" },
new ApiKeyStamper({
apiPublicKey: process.env.TURNKEY_PUBLIC_KEY as string,
apiPrivateKey: process.env.TURNKEY_PRIVATE_KEY as string,
})
);
const guardianSigner = new TurnkeySigner({
client: turnkeyClient,
organizationId: process.env.TURNKEY_ORG_ID as string,
signWith: process.env.TURNKEY_WALLET_ADDRESS as string, // For this demo, we manually generated the signer on turnkey dashboard
});

const initiateRecoveryMetaTx = createConfirmRecoveryMetaTransaction(
smartAccount.address,
[process.env.NEW_ONWER_PUBLIC_ADDRESS],
1, // new threshold
true, // whether to auto-start execution of recovery
)

// make sure to fund the guardian address on turnkey
const sendTx = guardianSigner.sendTransaction({
to: initiateRecoveryMetaTx.to,
data: initiateRecoveryMetaTx.data,
value: 0,
});

Finilize Recovery

Wait for recovery period to pass before finilizing

const finalizeRecoveryMetaTx = createFinalizeRecoveryMetaTransaction(smartAccount.accountAddress)

// Anyone can call the finilize function after the grace period is over
const sendTx2 = await guardianSigner.sendTransaction({
to: finalizeRecoveryMetaTx.to,
data: finalizeRecoveryMetaTx.data,
})