← Digital Assets

Bitcoin transaction policies

Decide which Bitcoin transactions your keys can sign and when they need independent approval.

Inputs, outputs, and fees

Check the previous outputs that fund a transaction and every output it creates. Set rules for scripts, amounts, fees, and signature flags.

Integration guide
Edict exampleshowcase-bitcoin.edict
authority "showcase-bitcoin" {
    intent = "bitcoin.transaction"
    version = "1"

    config {
        network = "MAINNET"
    }

    approver treasury {
        type = "reference"
        id = "treasury"
        ref = "treasury@sha256:<digest>"
    }

    approver security {
        type = "reference"
        id = "security"
        ref = "security@sha256:<digest>"
    }

    fn feeWithinBudget(satoshis: Integer, virtualBytes: Integer): Boolean {
        return (virtualBytes > 0
            and satoshis >= 0
            and satoshis <= 50000
            and satoshis <= virtualBytes * 50)
    }

    fn spendableOutputs(items: List<Output>): Boolean {
        if (items.count() == 0 or items.count() > 10) {
            return false
        }

        for (output in items) {
            if (not output.spendable or output.amount <= 0) {
                return false
            }
        }

        return true
    }

    fn paymentTotal(tx: Transaction): Integer {
        let fundingScript = tx.inputs[0].prevout.scriptPubKeyHex
        let paymentOutputs = tx.outputs.filter(output -> output.scriptPubKeyHex != fundingScript)

        return paymentOutputs.sum(output -> output.amount)
    }

    policy "bitcoin-spending" {
        allow when {
            transaction.network == "MAINNET"
            transaction.inputs.count() == 1
            transaction.inputs[0].prevout.scriptType in ["p2pkh", "p2wpkh"]
            transaction.signing.single
            transaction.sighash.all
            not transaction.sighash.anyoneCanPay
            spendableOutputs(transaction.outputs)
            feeWithinBudget(transaction.fee, transaction.vsize)
            paymentTotal(transaction) <= 10000000
        }

        require 2 of [treasury, security] if (
            transaction.inputs.count() == 1 and paymentTotal(transaction) > 1000000
        )
    }
}