Turnkey signer for Stacks blockchain transactions.
This package provides a class-based signer following the patterns established by @turnkey/solana, @turnkey/ethers, and @turnkey/cosmjs.
npm install @turnkey/stacks @stacks/transactionsimport { TurnkeySigner, broadcastTransaction } from "@turnkey/stacks"
import { Turnkey } from "@turnkey/sdk-server"
// Initialize Turnkey client
const turnkey = new Turnkey({
apiBaseUrl: "https://api.turnkey.com",
apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY!,
apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY!,
defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID!,
})
// Create Stacks signer
const signer = new TurnkeySigner({
client: turnkey.apiClient(),
organizationId: process.env.TURNKEY_ORGANIZATION_ID!,
publicKey: "025afa6566651f6c49d84a482a1af918b25ba7caac0b06d9ab8d79a45b72715aeb",
network: "testnet",
})
// Get address
const address = signer.getAddress()
console.log(`Address: ${address}`)
// Sign and broadcast transfer
const { transaction } = await signer.signSTXTransfer({
recipient: "ST2J6ZY7R94P80Z4CGFRHZ3Q16MF0NKHN3FK4R0N",
amount: 1_000_000n, // 1 STX
})
const txid = await broadcastTransaction(transaction, "testnet")
console.log(`TX: https://explorer.hiro.so/txid/${txid}?chain=testnet`)Class-based signer for Stacks transactions.
new TurnkeySigner(config: TurnkeySignerConfig)| Parameter | Type | Description |
|---|---|---|
config.client |
TurnkeySignerClient |
Turnkey client (use turnkey.apiClient() for SDK server) |
config.organizationId |
string |
Turnkey organization ID |
config.publicKey |
string |
Compressed secp256k1 public key (66 hex chars) |
config.network |
'testnet' | 'mainnet' |
Default network (optional, defaults to 'testnet') |
Returns the Stacks address for this signer.
const address = signer.getAddress() // Uses default network
const mainnetAddr = signer.getAddress("mainnet") // Override networkReturns the compressed public key.
const pubKey = signer.getPublicKey()Signs an STX token transfer.
const { transaction, senderAddress, nonce, fee } = await signer.signSTXTransfer({
recipient: "ST2J6ZY...",
amount: 1_000_000n, // Required: amount in microSTX
memo: "Payment", // Optional: memo string
nonce: 5n, // Optional: fetched if not provided
fee: 200n, // Optional: defaults to 180n
network: "testnet", // Optional: overrides signer default
})Derives a Stacks address without creating a signer.
import { getAddressFromPublicKey } from "@turnkey/stacks"
const address = getAddressFromPublicKey("025afa...", "testnet")Broadcasts a signed transaction.
import { broadcastTransaction } from "@turnkey/stacks"
const txid = await broadcastTransaction(signedTx, "testnet")Signs and broadcasts in one call.
import { signAndBroadcastSTXTransfer } from "@turnkey/stacks"
const { txid, senderAddress, recipient, amount } = await signAndBroadcastSTXTransfer(
signer,
{ recipient: "ST2J6ZY...", amount: 1_000_000n }
)interface TurnkeySignerConfig {
client: TurnkeySignerClient
organizationId: string
publicKey: string
network?: "testnet" | "mainnet"
}interface STXTransferParams {
recipient: string
amount: bigint
nonce?: bigint
fee?: bigint
memo?: string
network?: "testnet" | "mainnet"
}interface SignedTransactionResult {
transaction: StacksTransactionWire
senderAddress: string
nonce: bigint
fee: bigint
}interface BroadcastResult {
txid: string
senderAddress: string
recipient: string
amount: bigint
}The TurnkeySigner works with multiple Turnkey client types:
import { Turnkey } from "@turnkey/sdk-server"
const turnkey = new Turnkey({ ... })
const signer = new TurnkeySigner({
client: turnkey.apiClient(), // Use apiClient()
...
})import { TurnkeyBrowserClient } from "@turnkey/sdk-browser"
const client = new TurnkeyBrowserClient({ ... })
const signer = new TurnkeySigner({
client: client, // Use directly
...
})import { TurnkeyClient } from "@turnkey/http"
const client = new TurnkeyClient({ ... }, stamper)
const signer = new TurnkeySigner({
client: client, // Use directly
...
})This package uses Turnkey's signRawPayload with HASH_FUNCTION_NO_OP because Stacks' sigHashPreSign already produces the final hash to be signed. Turnkey must sign the bytes directly without re-hashing.
Signature flow:
- Build unsigned STX transfer with
makeUnsignedSTXTokenTransfer - Generate pre-sign hash with
sigHashPreSign - Sign with Turnkey using
HASH_FUNCTION_NO_OP - Construct VRS signature (recovery byte + r + s = 65 bytes)
- Attach signature to transaction spending condition
Apache-2.0