Getting started with post-conditions
Learn how post-conditions protect users from unexpected transaction outcomes
Post-conditions are security features in Stacks that protect users by ensuring transactions execute exactly as expected. They verify that specific asset transfers occur during a transaction, and if the conditions aren't satisfied, the entire transaction fails with no state changes.
What are post-conditions?
Post-conditions act as safeguards that verify asset transfers match your expectations. They can check STX transfers, fungible tokens, and non-fungible token ownership changes.
import { Pc } from '@stacks/transactions';const tx = await makeContractCall({// ...postConditions: [Pc.principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6').willSendEq(1000).ustx(),],});
Post-conditions only verify that assets are sent, not received. They cannot guarantee the final recipient of tokens.
Using the Pc helper
The Pc
helper provides a fluent API for creating post-conditions with better type safety and readability.
import { Pc } from '@stacks/transactions';// STX transfer post-conditionconst stxCondition = Pc.principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6').willSendGte(1000).ustx();// Fungible token post-conditionconst ftCondition = Pc.principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6').willSendEq(50).ft('SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.my-token', 'my-token');// NFT post-conditionconst nftCondition = Pc.principal('STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6').willSendAsset().nft('SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.my-nft::my-asset', Cl.uint(1));
Manual creation
Create post-conditions manually using type definitions when building conditions dynamically.
import {StxPostCondition,FungiblePostCondition,NonFungiblePostCondition} from '@stacks/transactions';// STX post-conditionconst stxPostCondition: StxPostCondition = {type: 'stx-postcondition',address: 'SP2JXKMSH007NPYAQHKJPQMAQYAD90NQGTVJVQ02B',condition: 'gte', // 'eq' | 'gt' | 'gte' | 'lt' | 'lte'amount: '100',};
Available condition types:
eq
: Exactly equal to amountgt
: Greater than amountgte
: Greater than or equal to amountlt
: Less than amountlte
: Less than or equal to amount
Fungible tokens
const ftPostCondition: FungiblePostCondition = {type: 'ft-postcondition',address: 'SP2JXKMSH007NPYAQHKJPQMAQYAD90NQGTVJVQ02B',condition: 'eq',amount: '100',asset: 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.my-ft-token::my-token',};
Non-fungible tokens
const nftPostCondition: NonFungiblePostCondition = {type: 'nft-postcondition',address: 'SP2JXKMSH007NPYAQHKJPQMAQYAD90NQGTVJVQ02B',condition: 'sent', // 'sent' | 'not-sent'asset: 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.my-nft::my-asset',assetId: Cl.uint(602),};
Post-condition mode
Control how unspecified asset transfers are handled with post-condition mode.
import { PostConditionMode } from '@stacks/transactions';const tx = await makeContractCall({// ...postConditionMode: PostConditionMode.Deny,postConditions: [// your conditions],});
type: warn
Using PostConditionMode.Allow
reduces security by permitting unspecified asset transfers. Only use when explicitly needed.