Skip to content

txnbuild: reset CreateClaimableBalance and RevokeSponsorship in FromXDR - #6023

Open
marwen-abid wants to merge 2 commits into
mainfrom
txnbuild-fromxdr-reset
Open

marwen-abid wants to merge 2 commits into
mainfrom
txnbuild-fromxdr-reset

Conversation

@marwen-abid

@marwen-abid marwen-abid commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

What

CreateClaimableBalance.FromXDR and RevokeSponsorship.FromXDR now reset the receiver after the type check, before they read the operation. This is the same change that #6021 made to SetOptions.FromXDR.

RevokeSponsorship.FromXDR now checks the operation type before it sets SourceAccount.

Why

Follow-up to the review of #6021.

CreateClaimableBalance.FromXDR appended the decoded claimants to cb.Destinations and did not reset it. Example: decode an operation with claimant A into a value that already has claimant B. The result has claimants B and A. If the caller builds it again, B can claim the balance, but B is not in the decoded operation.

RevokeSponsorship.FromXDR set only the field for the decoded sponsorship type, so a reused value kept the field of the earlier type. BuildXDR reads only the field that SponsorshipType selects, so the XDR was correct. But the struct showed a stale target, and a comparison with a freshly decoded value failed.

Before, RevokeSponsorship.FromXDR set SourceAccount before the type check, so a wrong operation type changed the receiver and then returned an error. Now the receiver does not change when the type is wrong.

Compatibility

The public API does not change. A caller that decodes into a new value gets the same result as before. A caller that decoded into a populated value and expected the claimants to merge now gets only the decoded claimants.

CreateClaimableBalance.FromXDR appended the decoded claimants to
cb.Destinations and did not reset it. When a caller decoded into a
populated value, the old claimants stayed, and a rebuild let them claim
the balance.

RevokeSponsorship.FromXDR set only the field for the decoded
sponsorship type and kept the field of the earlier type. BuildXDR reads
only the field that SponsorshipType selects, so the XDR was correct,
but the struct showed a stale target.

Both methods now reset the receiver after the type check, as
SetOptions.FromXDR does since #6021. RevokeSponsorship.FromXDR now
checks the operation type before it sets SourceAccount, so a wrong
operation type leaves the receiver unchanged.
Copilot AI lite review requested due to automatic review settings October 9, 2026 17:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes are fully reviewed, tested, and have no unresolved blocking issues.

0 open findings

What changed in this PR

Updates FromXDR decoding to safely reset reused receivers and avoid stale fields for claimable-balance and sponsorship operations.

Changes:

  • Reset decoded operation state.
  • Validate operation types before mutating receivers.
  • Add regression tests and changelog documentation.
File Description
txnbuild/​revoke_sponsorship.go Validates type before mutation and clears stale fields.
txnbuild/​revoke_sponsorship_test.go Tests reuse and wrong-type behavior.
txnbuild/​create_claimable_balance.go Resets decoded claimable-balance fields.
txnbuild/​create_claimable_balance_test.go Tests receiver reuse and rebuild behavior.
txnbuild/​CHANGELOG.md Documents the fixes.

🧠 Review effort: Lite


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@marwen-abid marwen-abid self-assigned this Oct 9, 2026
Copilot AI lite review requested due to automatic review settings October 9, 2026 22:53
@marwen-abid
marwen-abid force-pushed the txnbuild-fromxdr-reset branch from d2da1ee to ae18d56 Compare October 9, 2026 22:53
@marwen-abid
marwen-abid force-pushed the txnbuild-fromxdr-reset branch from ae18d56 to ddce05f Compare October 9, 2026 22:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Functional changes and regression coverage are complete; only a non-blocking documentation nit remains.

0 open findings

🧠 Review effort: Lite

Copilot AI lite review requested due to automatic review settings October 9, 2026 22:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No unresolved issues were identified.

0 open findings

🧠 Review effort: Lite

Copilot AI lite review requested due to automatic review settings October 9, 2026 23:05
@marwen-abid
marwen-abid force-pushed the txnbuild-fromxdr-reset branch from ddce05f to 131cb5e Compare October 9, 2026 23:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes are covered by regression tests and no blocking issues remain.

0 open findings

🧠 Review effort: Lite

@marwen-abid
marwen-abid requested a balanced review from Copilot October 9, 2026 23:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused changes correctly address receiver reuse and are covered by relevant regression tests.

0 open findings

🧠 Review effort: Balanced

@tamirms

tamirms commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

Thanks, this looks good. Decoding into a local and assigning only on success also leaves the receiver unchanged on every error, which is nice.

Could you handle LiquidityPoolDeposit.FromXDR here too? It copies MinPrice/MaxPrice only when they're non-zero (liquidity_pool_deposit.go:99-104), so decoding an op with a 0/0 price into a populated value keeps the old price, passes Validate, and rebuilds with a price that isn't in the decoded op. Only a malformed op has a 0/0 price, so the impact is small, but assigning both prices unconditionally (or decoding into a local like you did here) would close the last case of this pattern in txnbuild.

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.

3 participants