For the complete documentation index, see llms.txt. This page is also available as Markdown.

Implementation

Learn how to add post-conditions to protect your Stacks transactions.

Post-conditions are a powerful security feature in Stacks that protect users from unexpected transaction outcomes. This tutorial will walk you through implementing post-conditions in your applications to ensure transactions behave exactly as users expect.

What you'll learn

  • Construct post-conditions using the Pc helper API

  • Add post-conditions to different transaction types

  • Configure post-condition modes for transaction security

  • Implement post-conditions for STX, fungible tokens, and NFTs

  • Handle semi-fungible tokens (SFTs) with post-conditions

  • Use Originator mode to protect only the transaction sender's assets (SIP-040)

  • Use the MAY SEND token condition to optionally cover an NFT/SFT transfer (SIP-040)

Constructing post-conditions

The Pc helper in Stacks.js provides a fluent, BDD-inspired API for constructing post-conditions. Start with Pc.principal() to specify which address will be verified, then chain methods to define the condition.

import { Pc } from '@stacks/transactions';

// Basic structure of a post-condition
const postCondition = Pc
  .principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6')
  .willSendEq(1000)
  .ustx();

The Pc helper uses method chaining for intuitive condition building. Your IDE will provide auto-completion for available methods at each step.


Available transfer methods

Post-conditions support different comparison operators and asset types. Choose the appropriate method based on your security requirements.

STX and fungible token methods

Comparison methods available:

  • .willSendEq(amount) - Exactly equal to amount

  • .willSendGte(amount) - Greater than or equal to amount

  • .willSendGt(amount) - Greater than amount

  • .willSendLte(amount) - Less than or equal to amount

  • .willSendLt(amount) - Less than amount

Asset type methods

NFT-specific methods

Use willMaybeSendAsset() when an NFT/SFT transfer is conditional inside the contract and you want the transaction to succeed whether or not it moves. Available from Stacks epoch 3.4 (SIP-040).


Setting the post-condition mode

The post-condition mode determines how the Stacks protocol handles asset transfers not explicitly covered by your post-conditions. This is a critical security setting.

Mode options:

  • PostConditionMode.Deny (default): Transaction fails if any unspecified transfers occur

  • PostConditionMode.Originator: Transaction fails only if unspecified transfers originate from the transaction's origin account; transfers between other principals are allowed (SIP-040, epoch 3.4+, live since March 2026)

  • PostConditionMode.Allow: Transaction allows transfers beyond specified post-conditions

Originator mode is intended for DeFi-style contract calls where intermediate asset routing between contracts is unpredictable. It applies Deny-style protection to the origin account's assets while permitting movements between other principals.


Common implementation patterns

STX transfer post-conditions

Protect STX transfers by specifying exact amounts or ranges.

Fungible token post-conditions

Ensure fungible tokens are transferred as expected in contract calls.

NFT transfer post-conditions

Control NFT ownership changes with specific post-conditions.

Use willNotSendAsset() to protect valuable NFTs from being transferred unexpectedly.

Semi-fungible token (SFT) post-conditions

SFTs require special handling as they have both fungible and non-fungible properties.

Multi-bin withdrawals (Bitflow DLMM, concentrated-liquidity pools) typically produce one willMaybeSendAsset() post-condition per affected bin. The position SFT for each bin may be burned (transferred to the contract) or kept depending on the remaining liquidity after the call. Pairing each per-bin condition with willSendLte conditions on the underlying FTs gives the signer a precise upper bound on what can leave their account while allowing the contract to skip burns for bins that retain liquidity.

Originator-mode post-conditions for DeFi (SIP-040)

When calling a contract that routes assets through several intermediate contracts, listing every hop in Deny mode is brittle. Originator mode restricts only the sender's own outflows and allows asset movement between other principals.

Pc.origin() is a convenience that binds the post-condition to the transaction's origin account (the signer of the standard authorization structure, not tx-sender, and unaffected by as-contract?).

Multiple post-conditions

Complex transactions often require multiple post-conditions to fully protect all asset transfers.

Last updated

Was this helpful?