Signing with Turnkey

Leverage Stacks.js with Turnkey's embedded wallet solutions

Turnkey’s embedded wallet makes STX & sBTC transactions seamless, secure, and user-friendly, letting your users experience Bitcoin-native apps without friction. Using external embedded wallet/signing solutions with Stacks comes down to properly passing in a hashed transaction payload to a provided signing method. We'll show you how to derive that hashed transaction payload in this guide.

Currently, Turnkey does not natively support Stacks, but can be simply integrated together using the example below. Work is in progress for native Stacks support in Turnkey.

Address derivation

Turnkey supports Stacks address derivation with ADDRESS_FORMAT_COMPRESSED and ADDRESS_FORMAT_UNCOMPRESSED address formats. Stacks addresses are derived from the secp256k1 curve, which Turnkey fully supports.

Use a secp256k1 generated public key to derive Stacks addresses and sign Stacks transactions. In most cases with Turnkey, using an Ethereum account's public key would satisfy this.

import { publicKeyToAddress } from "@stacks/transactions"

const stxAddress = publicKeyToAddress(matchingAccount?.publicKey!)

// STX address: SP1Z6MYME47PW04D1J15K368XZE02VWQ2A5SRC4HV
// publicKey: 03169b8f8bbad2cc6435893c5f255cd5201d272befa8556c82136bf9b36aa0d778

Transaction construction and signing

A sample script that demonstrates how to sign a Stacks transaction with Turnkey. Stacks uses the secp256k1 cryptographic curve for transaction signing, but there some specific data formatting that takes place for the signing process.

Simplified step-by-step process of what this example script is showing:

  1. Generate sigHash from unsigned transaction

  2. Generate preSignSigHash

  3. ECDSA sign preSignSigHash with a Turnkey private key

  4. Concatenate outputted raw signature (from step 3) components in the order of V + R + S

  5. The resulting signature of step 4 will be the nextSig

  6. Reassign spendingCondition.signature with the value of nextSig

Note: The hashFunction HASH_FUNCTION_NO_OP should be set this way because the payload has already been hashed.

Signing Stacks transactions works with either Turnkey's Server or React SDKs

Components of a ECDSA signature

  • r (32 bytes): The x-coordinate of a point on the elliptic curve, derived during the signing process.

  • s (32 bytes): A scalar derived from the message hash, private key, and the nonce k.

  • v (1 byte): Indicates which of the two possible public keys was used to generate the signature.

Why Use Turnkey Embedded Wallets for Stacks Apps

  • Seamless onboarding – Users can start interacting with your app immediately, without installing separate wallets or extensions.

  • Simplified authentication – Turnkey handles secure key management and signing, including modern standards like passkeys.

  • Improved UX – Embedded wallets reduce friction in transactions, making dApps feel more like mainstream apps.

  • Multi-chain-ready – Easily support STX, sBTC and other blockchain assets without building your own wallet infrastructure.


Additional Resources

  • [Hiro Blog] Dissecting a Transaction Signature on Stacks

  • [Twitter] Stacks DevRel Office Hours with Turnkey's Michael Lewellen

  • [Twitter] sBTC.Cool - Example project on Stacks integrating Turnkey

  • [Twitter] Turnkey supporting transaction signing for Stacks

Last updated

Was this helpful?