This is a guide to importing your wallet or private key into Turnkey. For more information about the security of this flow, check out Enclave secure channels.
Follow along with the Turnkey CLI, Embedded iframe, NodeJS, and Local Storage guides.
Install the latest version of Turnkey CLI to access the new import functionality. You can find detailed instructions for installation here.
Generate an encryption key
--user
flag (required) is the id of the user importing the private key; this is required because the underlying encryption keys used for import are scoped to each user.--encryption-key-name
flag is to specify a name for the encryption key. Note that an encryption key !== Turnkey API key; an encryption key is used exclusively for secure activities like import and export.Initialize import
--import-bundle-output
(required) flag is the desired output file path for the “import bundle” that will be received from Turnkey. The “import bundle” contains the ephemeral public key generated by the Turnkey signer enclave for the specified user. The private key plaintext is encrypted to this public key in Step 2.--key-name
flag specifies the name of API key with which to interact with the Turnkey API service. This should be the name of a previously created key. If you do not have one, visit the quickstart guide for help creating one.Encrypt without saving plaintext to filesystem. This can be done offline:
--import-bundle-input
flag (required) is the desired input file path for the “import bundle”.--plaintext-input
flag is the desired input file path for the private key plaintext. You can pass a filename here or feed the plaintext string directly into the standard input as shown above.--encrypted-bundle-output
(required) flag is the desired output file path for the “encrypted bundle” that will be sent to Turnkey in Step 3. The “encrypted bundle” contains the ephemeral public key generated by the CLI as part of the shared secret computation with the Turnkey signer enclave. It also contains the ciphertext, which is the plaintext input encrypted by the Turnkey signer’s ephemeral public key.Import private key
--encrypted-bundle-input
(required) flag is the desired input file path for the “encrypted bundle” that will be sent to Turnkey.--curve
and --address-format
flags.Turnkey CLI also supports importing private keys. Follow the same steps as importing a wallet via CLI but use the turnkey private-keys
commands instead. In Step 2 (encrypt
), pass a --key-format
flag for key-specific formatting; the options for private keys are:
hexadecimal
: Used for Ethereum. Examples: 0x13eff5b3f9c63eab5d53cff5149f01606b69325496e0e98b53afa938d890cd2e, 13eff5b3f9c63eab5d53cff5149f01606b69325496e0e98b53afa938d890cd2e
solana
: Used for Solana. It’s a base58-encoding of the concatenation of the private key and public key bytes. Example: 2P3qgS5A18gGmZJmYHNxYrDYPyfm6S3dJgs8tPW6ki6i2o4yx7K8r5N8CF7JpEtQiW8mx1kSktpgyDG1xuWNzfsM
import.turnkey.com
meant to be embedded as an iframe element (see the code here). This ensures the mnemonics and keys are encrypted to keys that the user has access to, but that your organization does not (because they live in the iframe, on a separate domain).@turnkey/iframe-stamper
In the rest of this guide we’ll assume you are using these helpers.
Here’s a diagram summarizing the wallet import flow step-by-step (direct link):
Let’s review these steps in detail:
When a user on your application clicks “import”, display a new import UI. We recommend setting this import UI as a new hosted page of your application that contains the iframe element that the user will enter their mnemonic into and an import button.
While the UI is in a loading state, your application uses @turnkey/iframe-stamper
to insert a new iframe element:
Your application prompts the user to sign a new INIT_IMPORT_WALLET
activity with the ID of the user importing the wallet.
Your application polls for the activity response, which contains an import bundle.
Need help setting up async polling? Checkout our guide and helper here.
Your application injects the import bundle into the iframe and displays the iframe upon success:
When a user clicks on the import button on your web page, your application can extract the encrypted mnemonic bundle from the iframe:
Your applications passes the encrypted bundle as a parameter in a new IMPORT_WALLET
activity and prompts the user to sign it.
Import is complete!
In your Turnkey dashboard, the imported user Wallet will be flagged as “Imported”.
A full example Node script can be found here: https://github.com/tkhq/sdk/tree/main/examples/import-in-node
Initialize a new Turnkey client
Initialize the import process (Turnkey activity)
Encrypt wallet to bundle
Import wallet (Turnkey activity)
Congrats! You’ve imported your wallet 🎉
The process for importing a private key instead of wallet is largely similar, but has a key difference in that you must specify the format of your imported private key:
Initialize a new Turnkey client
Initialize the import process (Turnkey activity)
Encrypt private key to bundle
Import private key (Turnkey activity)
Congrats! You’ve imported your private key 🎉
If you do not have access to an iframe (e.g. in a mobile context) or would prefer not to use an iframe, you can opt to use other environment-agnostic methods to perform import using Turnkey libraries. So while this section is called Local Storage (for consistency with the Export guide), nothing is stored in Local Storage; instead, the relevant encrypt{Wallet, PrivateKey}ToBundle
method uses an ephemeral key.
Initialize Turnkey client
Initialize the import process (Turnkey activity)
Encrypt wallet to bundle
Import wallet (Turnkey activity)
Congrats! You’ve imported your wallet 🎉
The process for importing a private key instead of wallet is largely similar, but has a key difference in that you must specify the format of your imported private key:
Initialize Turnkey client
Initialize the import process (Turnkey activity)
Encrypt private key to bundle
Import private key (Turnkey activity)
Congrats! You’ve imported your private key 🎉
Turnkey also supports importing Private Keys. Follow the same steps above for importing Wallets as mnemonics, but instead use the INIT_IMPORT_PRIVATE_KEY
and IMPORT_PRIVATE_KEY
activities and the extractKeyEncryptedBundle
method from the @turnkey/iframe-stamper
. You can pass an optional keyFormat
to extractKeyEncryptedBundle(keyFormat)
that will apply either Hexadecimal
or Solana
formatting to the private key that is entered in the iframe. The default key format is hexadecimal
, which is used by MetaMask, MyEtherWallet, Phantom, Ledger, and Trezor for Ethereum keys. For Solana keys, you will need to pass the solana
key format.
Everything is customizable in the import iframe except the sentence of mnemonic words, which is minimally styled: the text is left-aligned and the padding and margins are zero. Here’s an example of how you can configure the styling of the iframe.
This is a guide to importing your wallet or private key into Turnkey. For more information about the security of this flow, check out Enclave secure channels.
Follow along with the Turnkey CLI, Embedded iframe, NodeJS, and Local Storage guides.
Install the latest version of Turnkey CLI to access the new import functionality. You can find detailed instructions for installation here.
Generate an encryption key
--user
flag (required) is the id of the user importing the private key; this is required because the underlying encryption keys used for import are scoped to each user.--encryption-key-name
flag is to specify a name for the encryption key. Note that an encryption key !== Turnkey API key; an encryption key is used exclusively for secure activities like import and export.Initialize import
--import-bundle-output
(required) flag is the desired output file path for the “import bundle” that will be received from Turnkey. The “import bundle” contains the ephemeral public key generated by the Turnkey signer enclave for the specified user. The private key plaintext is encrypted to this public key in Step 2.--key-name
flag specifies the name of API key with which to interact with the Turnkey API service. This should be the name of a previously created key. If you do not have one, visit the quickstart guide for help creating one.Encrypt without saving plaintext to filesystem. This can be done offline:
--import-bundle-input
flag (required) is the desired input file path for the “import bundle”.--plaintext-input
flag is the desired input file path for the private key plaintext. You can pass a filename here or feed the plaintext string directly into the standard input as shown above.--encrypted-bundle-output
(required) flag is the desired output file path for the “encrypted bundle” that will be sent to Turnkey in Step 3. The “encrypted bundle” contains the ephemeral public key generated by the CLI as part of the shared secret computation with the Turnkey signer enclave. It also contains the ciphertext, which is the plaintext input encrypted by the Turnkey signer’s ephemeral public key.Import private key
--encrypted-bundle-input
(required) flag is the desired input file path for the “encrypted bundle” that will be sent to Turnkey.--curve
and --address-format
flags.Turnkey CLI also supports importing private keys. Follow the same steps as importing a wallet via CLI but use the turnkey private-keys
commands instead. In Step 2 (encrypt
), pass a --key-format
flag for key-specific formatting; the options for private keys are:
hexadecimal
: Used for Ethereum. Examples: 0x13eff5b3f9c63eab5d53cff5149f01606b69325496e0e98b53afa938d890cd2e, 13eff5b3f9c63eab5d53cff5149f01606b69325496e0e98b53afa938d890cd2e
solana
: Used for Solana. It’s a base58-encoding of the concatenation of the private key and public key bytes. Example: 2P3qgS5A18gGmZJmYHNxYrDYPyfm6S3dJgs8tPW6ki6i2o4yx7K8r5N8CF7JpEtQiW8mx1kSktpgyDG1xuWNzfsM
import.turnkey.com
meant to be embedded as an iframe element (see the code here). This ensures the mnemonics and keys are encrypted to keys that the user has access to, but that your organization does not (because they live in the iframe, on a separate domain).@turnkey/iframe-stamper
In the rest of this guide we’ll assume you are using these helpers.
Here’s a diagram summarizing the wallet import flow step-by-step (direct link):
Let’s review these steps in detail:
When a user on your application clicks “import”, display a new import UI. We recommend setting this import UI as a new hosted page of your application that contains the iframe element that the user will enter their mnemonic into and an import button.
While the UI is in a loading state, your application uses @turnkey/iframe-stamper
to insert a new iframe element:
Your application prompts the user to sign a new INIT_IMPORT_WALLET
activity with the ID of the user importing the wallet.
Your application polls for the activity response, which contains an import bundle.
Need help setting up async polling? Checkout our guide and helper here.
Your application injects the import bundle into the iframe and displays the iframe upon success:
When a user clicks on the import button on your web page, your application can extract the encrypted mnemonic bundle from the iframe:
Your applications passes the encrypted bundle as a parameter in a new IMPORT_WALLET
activity and prompts the user to sign it.
Import is complete!
In your Turnkey dashboard, the imported user Wallet will be flagged as “Imported”.
A full example Node script can be found here: https://github.com/tkhq/sdk/tree/main/examples/import-in-node
Initialize a new Turnkey client
Initialize the import process (Turnkey activity)
Encrypt wallet to bundle
Import wallet (Turnkey activity)
Congrats! You’ve imported your wallet 🎉
The process for importing a private key instead of wallet is largely similar, but has a key difference in that you must specify the format of your imported private key:
Initialize a new Turnkey client
Initialize the import process (Turnkey activity)
Encrypt private key to bundle
Import private key (Turnkey activity)
Congrats! You’ve imported your private key 🎉
If you do not have access to an iframe (e.g. in a mobile context) or would prefer not to use an iframe, you can opt to use other environment-agnostic methods to perform import using Turnkey libraries. So while this section is called Local Storage (for consistency with the Export guide), nothing is stored in Local Storage; instead, the relevant encrypt{Wallet, PrivateKey}ToBundle
method uses an ephemeral key.
Initialize Turnkey client
Initialize the import process (Turnkey activity)
Encrypt wallet to bundle
Import wallet (Turnkey activity)
Congrats! You’ve imported your wallet 🎉
The process for importing a private key instead of wallet is largely similar, but has a key difference in that you must specify the format of your imported private key:
Initialize Turnkey client
Initialize the import process (Turnkey activity)
Encrypt private key to bundle
Import private key (Turnkey activity)
Congrats! You’ve imported your private key 🎉
Turnkey also supports importing Private Keys. Follow the same steps above for importing Wallets as mnemonics, but instead use the INIT_IMPORT_PRIVATE_KEY
and IMPORT_PRIVATE_KEY
activities and the extractKeyEncryptedBundle
method from the @turnkey/iframe-stamper
. You can pass an optional keyFormat
to extractKeyEncryptedBundle(keyFormat)
that will apply either Hexadecimal
or Solana
formatting to the private key that is entered in the iframe. The default key format is hexadecimal
, which is used by MetaMask, MyEtherWallet, Phantom, Ledger, and Trezor for Ethereum keys. For Solana keys, you will need to pass the solana
key format.
Everything is customizable in the import iframe except the sentence of mnemonic words, which is minimally styled: the text is left-aligned and the padding and margins are zero. Here’s an example of how you can configure the styling of the iframe.