Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/chain-integrations/with-zcash/.env.local.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
API_PUBLIC_KEY="<Turnkey API Public Key (that starts with 02 or 03)>"
API_PRIVATE_KEY="<Turnkey API Private Key>"
BASE_URL="https://api.turnkey.com"
ORGANIZATION_ID="<Turnkey organization ID>"

# Use an ADDRESS_FORMAT_COMPRESSED wallet account address or a private key id.
# If SIGN_WITH is the compressed public key address, SIGNER_COMPRESSED_PUBLIC_KEY can be omitted.
SIGN_WITH="<Turnkey compressed public key address or private key id>"
SIGNER_COMPRESSED_PUBLIC_KEY="<33-byte compressed secp256k1 public key hex>"

# mainnet or testnet
ZCASH_NETWORK="testnet"

# zcashd-compatible JSON-RPC endpoint. Broadcast is performed here, not via Turnkey.
ZCASH_RPC_URL="http://127.0.0.1:18232"
ZCASH_RPC_USERNAME="<optional RPC username>"
ZCASH_RPC_PASSWORD="<optional RPC password>"

# Optional if your RPC node exposes getaddressutxos or listunspent for SOURCE_TADDRESS.
SOURCE_TADDRESS="<optional sender t-address; derived from SIGNER_COMPRESSED_PUBLIC_KEY when omitted>"
UTXOS_JSON='[{"txid":"<txid>","vout":0,"valueZatoshis":1000000,"scriptPubKey":"<optional hex>"}]'

DESTINATION_TADDRESS="<recipient transparent t-address>"
SEND_AMOUNT_ZATOSHIS="10000"
FEE_ZATOSHIS="1000"

# Defaults to SOURCE_TADDRESS.
CHANGE_TADDRESS="<optional transparent change address>"

# The script prints the raw signed transaction unless BROADCAST is set to true.
BROADCAST="false"

# Optional. Defaults to current chain height + 20.
EXPIRY_DELTA="20"

# Optional. If getblockchaininfo does not expose consensus.chaintip/nextblock,
# set this to the active consensus branch ID, for example c2d6d0b4.
CONSENSUS_BRANCH_ID="<optional 8-hex-character branch id>"
80 changes: 80 additions & 0 deletions examples/chain-integrations/with-zcash/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Example: `with-zcash`

This example sends transparent Zcash with:

- Turnkey `signRawPayload` for secp256k1 ECDSA signatures.
- A local transparent-only Zcash transaction builder for v5 / NU5+ transactions.
- A zcashd-compatible JSON-RPC endpoint for UTXO lookup and `sendrawtransaction`.

Turnkey-native broadcast is intentionally out of scope here. The final signed transaction is submitted to the RPC endpoint you configure in `.env.local`.

## Scope

This is deliberately a Tier 1 style integration:

- Supports transparent P2PKH sender addresses derived from `ADDRESS_FORMAT_COMPRESSED` accounts.
- Supports transparent P2PKH and P2SH recipient/change addresses.
- Uses ZIP-244 `SIGHASH_ALL`.
- Does not support shielded Sapling/Orchard spends, unified addresses, transparent multisig/P2SH inputs, coinbase inputs, or Turnkey `SignTransaction`.

## Getting started

From the repo root:

```bash
corepack enable
pnpm install -r
pnpm run build-all
cd examples/chain-integrations/with-zcash
cp .env.local.example .env.local
```

Fill in `.env.local`:

- `API_PUBLIC_KEY`, `API_PRIVATE_KEY`, `BASE_URL`, `ORGANIZATION_ID`
- `SIGN_WITH`: an `ADDRESS_FORMAT_COMPRESSED` Turnkey wallet account address, or a private key ID
- `SIGNER_COMPRESSED_PUBLIC_KEY`: required when `SIGN_WITH` is not itself the compressed public key
- `ZCASH_RPC_URL`: zcashd-compatible JSON-RPC endpoint
- `DESTINATION_TADDRESS`
- `SEND_AMOUNT_ZATOSHIS`
- `FEE_ZATOSHIS`

If your RPC endpoint does not support `getaddressutxos`, set `UTXOS_JSON` manually. Each UTXO needs:

```json
[
{
"txid": "previous transaction id",
"vout": 0,
"valueZatoshis": 1000000,
"scriptPubKey": "optional previous output script hex"
}
]
```

Run without broadcasting first:

```bash
pnpm start
```

Set `BROADCAST=true` to submit through your configured Zcash RPC:

```bash
BROADCAST=true pnpm start
```

## Flow

1. Derive the sender transparent P2PKH address from the compressed public key.
2. Fetch or load UTXOs.
3. Build a transparent v5 transaction with recipient and change outputs.
4. Compute ZIP-244 per-input signature digests.
5. Ask Turnkey to sign each digest with `HASH_FUNCTION_NO_OP`.
6. Insert DER signatures into each P2PKH `scriptSig`.
7. Serialize and optionally broadcast with `sendrawtransaction`.

References:

- Zcash protocol specification, sections 5.6.1.1 and 7.1
- ZIP-244 transaction and signature digest algorithm
16 changes: 16 additions & 0 deletions examples/chain-integrations/with-zcash/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "@turnkey/example-with-zcash",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "tsx src/createZcashTx.ts",
"clean": "rimraf ./dist ./.cache",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@noble/hashes": "1.4.0",
"@turnkey/sdk-server": "workspace:*",
"dotenv": "16.0.3",
"path": "0.12.7"
}
}
Loading