Skip to content

fix(connect): allow staking-postcondition and pox-postcondition in serializeParams#503

Open
werner-stacks wants to merge 3 commits into
stx-labs:mainfrom
werner-stacks:patch-1
Open

fix(connect): allow staking-postcondition and pox-postcondition in serializeParams#503
werner-stacks wants to merge 3 commits into
stx-labs:mainfrom
werner-stacks:patch-1

Conversation

@werner-stacks

Copy link
Copy Markdown

Description

As a Stacks app developer, I want to attach staking-postcondition and
pox-postcondition post-conditions to a stx_callContract / stx_deployContract
request via @stacks/connect, so that I can build PoX-5 stacking flows with
deny-mode post-conditions. This is needed because PoX-5 stake locks STX (it is
not sent), so a stx-postcondition can never satisfy it — the protocol requires
the newer staking-postcondition (locked amount) and pox-postcondition
(will-perform) types. These types already exist in @stacks/transactions
(with the Pc.…ustxToLock() and Pc.willPerformPox() builders), but @stacks/connect
does not recognize them and crashes before the request reaches the wallet.

1. Motivation for change
Passing a staking-postcondition or pox-postcondition to request(...) throws:

In serializeParams (packages/connect/src/request.ts), each object with a type
field is routed as POST_CONDITIONS.includes(type) ? postConditionToHex(o) : Cl.serialize(o).
The POST_CONDITIONS allow-list only contains stx/ft/nft, so the two staking
types fall through to Cl.serialize() and fail — a post-condition object is not a
Clarity value.

2. What was changed
Added 'staking-postcondition' and 'pox-postcondition' to the POST_CONDITIONS
allow-list so they are serialized with postConditionToHex:

const POST_CONDITIONS = [
  'stx-postcondition',
  'ft-postcondition',
  'nft-postcondition',
  'staking-postcondition',
  'pox-postcondition',
] satisfies PostCondition['type'][];

PostCondition['type'] (from @stacks/transactions) already includes both, so the
satisfies constraint still holds — no type changes required.

3. How does this impact application developers
Developers can now pass staking/pox post-conditions as objects (or via the Pc
builder) to stx_callContract / stx_deployContract without a manual
postConditionToHex workaround. No change to existing stx/ft/nft behavior.

4. Link to relevant issues and documentation

  • @stacks/transactions post-condition types: StakingPostCondition, PoxPostCondition,
    and the Pc.…ustxToLock() / Pc.willPerformPox() builders.
  • (No existing issue — happy to open one if preferred.)

5. Examples of use cases with code samples and acceptance criteria

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

await request('stx_callContract', {
  contract: 'SP000000000000000000002Q6VF78.pox-5',
  functionName: 'stake',
  functionArgs: [/* ... */],
  postConditionMode: 'deny',
  postConditions: [
    Pc.principal(stacker).willSendEq(50000000000n).ustxToLock(), // staking-postcondition
    Pc.principal(stacker).willPerformPox(),                       // pox-postcondition
  ],
});

Which produce these post-condition objects:

{ "type": "staking-postcondition", "address": "SP…", "condition": "eq", "amount": "50000000000" }
{ "type": "pox-postcondition", "address": "SP…", "condition": "will-perform" }

Acceptance criteria:

  • Requesting with the two post-conditions above no longer throws
    "Unable to serialize. Invalid Clarity Value."
  • The post-conditions are serialized via postConditionToHex and forwarded to the
    wallet (verifiable in the request payload).
  • Existing stx/ft/nft post-conditions are unaffected.

Type of Change

  • New feature
  • Bug fix
  • API reference/documentation update
  • Other

Does this introduce a breaking change?

No. Existing post-condition types and all other params are serialized exactly as before;
this only adds two previously-erroring types to the allow-list.

Are documentation updates required?

  • Link to documentation updates: none required (internal serialization allow-list).
    Optional: post-condition docs could mention staking/pox types are supported via request.

Testing information

  1. Testing required: yes — a small unit test for serializeParams.
  2. Steps to reproduce the bug:
    • Call request('stx_callContract', { … postConditions: [Pc.principal(a).willSendEq(n).ustxToLock()] })
      on main → throws "Unable to serialize. Invalid Clarity Value."
    • With this change → the post-condition is serialized to hex and the request proceeds.
  3. Affected code path: serializeParams in packages/connect/src/request.ts (the
    POST_CONDITIONS allow-list branch).
  4. Other affected projects: any dApp using @stacks/connect for PoX-5 stacking
    (e.g. signer-manager stake).
  5. Watch out for: confirm the serialized hex round-trips via
    @stacks/transactions postConditionToHex / wire deserialization, and that the
    target wallet supports signing these post-condition types.

Checklist

  • Code is commented where needed
  • Unit test coverage for new or modified code paths
  • Changelog is updated
  • Tag @jannik-stacks for review

jannik-stacks
jannik-stacks previously approved these changes Jul 22, 2026
werner-stacks and others added 2 commits July 22, 2026 18:04
fix(connect): allow staking-postcondition and pox-postcondition in serializeParams

`serializeParams` only treats `stx`/`ft`/`nft` post-conditions as post-conditions.
The `staking-postcondition` and `pox-postcondition` types (added to
`@stacks/transactions` alongside `Pc.ustxToLock()` / `Pc.willPerformPox()`) are
missing from the `POST_CONDITIONS` allow-list, so they fall through the object
branch and are passed to `Cl.serialize()` as if they were Clarity values.

Calling `request('stx_callContract', { postConditions: [...] })` with a
`staking-postcondition` or `pox-postcondition` throws:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants