Skip to content

Add getSignatureFromTransactionIfPresent - #1894

Open
mcintyre94 wants to merge 1 commit into
mainfrom
tx-signature-if-present
Open

Add getSignatureFromTransactionIfPresent#1894
mcintyre94 wants to merge 1 commit into
mainfrom
tx-signature-if-present

Conversation

@mcintyre94

@mcintyre94 mcintyre94 commented Aug 7, 2026

Copy link
Copy Markdown
Member

Summary of Changes

This PR adds a new function getSignatureFromTransactionIfPresent, a non-throwing variant of getSignatureFromTransaction

If the transaction has a fee-payer signature then it is returned, otherwise undefined

This allows apps to avoid dealing with the details of a transaction signature, while handling the case where the transaction may not be signed yet.

This is primarily added for use in #1893 , but exported from @solana/transactions because it's useful functionality for apps.

@changeset-bot

changeset-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 43733d1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 48 packages
Name Type
@solana/transactions Major
@solana/compat Major
@solana/instruction-plans Major
@solana/kit Major
@solana/react Major
@solana/rpc-api Major
@solana/rpc-graphql Major
@solana/rpc-subscriptions-api Major
@solana/signers Major
@solana/transaction-confirmation Major
@solana/transaction-introspection Major
@solana/wallet-account-signer Major
@solana/plugin-interfaces Major
@solana/program-client-core Major
@solana/rpc Major
@solana/sysvars Major
@solana/rpc-subscriptions Major
@solana/accounts Major
@solana/addresses Major
@solana/assertions Major
@solana/codecs-core Major
@solana/codecs-data-structures Major
@solana/codecs-numbers Major
@solana/codecs-strings Major
@solana/codecs Major
@solana/errors Major
@solana/fast-stable-stringify Major
@solana/fixed-points Major
@solana/functional Major
@solana/instructions Major
@solana/keys Major
@solana/nominal-types Major
@solana/offchain-messages Major
@solana/options Major
@solana/plugin-core Major
@solana/programs Major
@solana/promises Major
@solana/rpc-parsed-types Major
@solana/rpc-spec-types Major
@solana/rpc-spec Major
@solana/rpc-subscriptions-channel-websocket Major
@solana/rpc-subscriptions-spec Major
@solana/rpc-transformers Major
@solana/rpc-transport-http Major
@solana/rpc-types Major
@solana/subscribable Major
@solana/transaction-messages Major
@solana/webcrypto-ed25519-polyfill Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

mcintyre94 commented Aug 7, 2026

Copy link
Copy Markdown
Member Author

@bundlemon

bundlemon Bot commented Aug 7, 2026

Copy link
Copy Markdown

BundleMon

Files updated (4)
Status Path Size Limits
transactions/dist/index.browser.mjs
4.1KB (+38B +0.91%) -
transactions/dist/index.native.mjs
4.1KB (+38B +0.91%) -
transactions/dist/index.node.mjs
4.1KB (+37B +0.89%) -
@solana/kit production bundle
kit/dist/index.production.min.js
55.66KB (+25B +0.04%) -
Unchanged files (146)
Status Path Size Limits
errors/dist/index.node.mjs
21.81KB -
errors/dist/index.browser.mjs
21.79KB -
errors/dist/index.native.mjs
21.79KB -
rpc-graphql/dist/index.browser.mjs
18.82KB -
rpc-graphql/dist/index.native.mjs
18.82KB -
rpc-graphql/dist/index.node.mjs
18.82KB -
wallet-account-signer/dist/index.node.mjs
18.5KB -
wallet-account-signer/dist/index.browser.mjs
18.48KB -
wallet-account-signer/dist/index.native.mjs
18.48KB -
transaction-messages/dist/index.browser.mjs
11.34KB -
transaction-messages/dist/index.native.mjs
11.34KB -
transaction-messages/dist/index.node.mjs
11.34KB -
instruction-plans/dist/index.browser.mjs
7.02KB -
instruction-plans/dist/index.native.mjs
7.02KB -
instruction-plans/dist/index.node.mjs
7.02KB -
react/dist/index.browser.mjs
5.32KB -
react/dist/index.native.mjs
5.32KB -
react/dist/index.node.mjs
5.32KB -
codecs-data-structures/dist/index.browser.mjs
5.29KB -
codecs-data-structures/dist/index.native.mjs
5.29KB -
codecs-data-structures/dist/index.node.mjs
5.29KB -
offchain-messages/dist/index.browser.mjs
5.25KB -
offchain-messages/dist/index.native.mjs
5.24KB -
offchain-messages/dist/index.node.mjs
5.24KB -
fixed-points/dist/index.browser.mjs
5.08KB -
fixed-points/dist/index.native.mjs
5.07KB -
fixed-points/dist/index.node.mjs
5.07KB -
kit/dist/index.browser.mjs
4.61KB -
kit/dist/index.native.mjs
4.6KB -
kit/dist/index.node.mjs
4.6KB -
codecs-core/dist/index.browser.mjs
3.62KB -
codecs-core/dist/index.native.mjs
3.62KB -
codecs-core/dist/index.node.mjs
3.62KB -
webcrypto-ed25519-polyfill/dist/index.node.mj
s
3.61KB -
webcrypto-ed25519-polyfill/dist/index.browser
.mjs
3.59KB -
webcrypto-ed25519-polyfill/dist/index.native.
mjs
3.57KB -
rpc-subscriptions/dist/index.browser.mjs
3.37KB -
rpc-subscriptions/dist/index.node.mjs
3.34KB -
rpc-subscriptions/dist/index.native.mjs
3.31KB -
signers/dist/index.browser.mjs
3.26KB -
signers/dist/index.native.mjs
3.26KB -
signers/dist/index.node.mjs
3.26KB -
rpc-transformers/dist/index.browser.mjs
3.16KB -
rpc-transformers/dist/index.native.mjs
3.16KB -
rpc-transformers/dist/index.node.mjs
3.15KB -
subscribable/dist/index.node.mjs
3.13KB -
keys/dist/index.node.mjs
3.06KB -
subscribable/dist/index.native.mjs
3.06KB -
subscribable/dist/index.browser.mjs
3.05KB -
addresses/dist/index.browser.mjs
2.93KB -
addresses/dist/index.native.mjs
2.92KB -
addresses/dist/index.node.mjs
2.92KB -
keys/dist/index.browser.mjs
2.85KB -
keys/dist/index.native.mjs
2.85KB -
transaction-introspection/dist/index.browser.
mjs
2.73KB -
transaction-introspection/dist/index.native.m
js
2.73KB -
transaction-introspection/dist/index.node.mjs
2.73KB -
codecs-strings/dist/index.browser.mjs
2.55KB -
codecs-strings/dist/index.node.mjs
2.51KB -
codecs-strings/dist/index.native.mjs
2.47KB -
transaction-confirmation/dist/index.node.mjs
2.42KB -
transaction-confirmation/dist/index.native.mj
s
2.37KB -
sysvars/dist/index.browser.mjs
2.37KB -
sysvars/dist/index.native.mjs
2.37KB -
transaction-confirmation/dist/index.browser.m
js
2.37KB -
sysvars/dist/index.node.mjs
2.37KB -
rpc-subscriptions-spec/dist/index.node.mjs
2.23KB -
rpc-subscriptions-spec/dist/index.native.mjs
2.19KB -
rpc-subscriptions-spec/dist/index.browser.mjs
2.19KB -
rpc/dist/index.node.mjs
1.95KB -
codecs-numbers/dist/index.browser.mjs
1.95KB -
codecs-numbers/dist/index.native.mjs
1.95KB -
codecs-numbers/dist/index.node.mjs
1.94KB -
rpc-types/dist/index.browser.mjs
1.9KB -
rpc-types/dist/index.native.mjs
1.9KB -
rpc-types/dist/index.node.mjs
1.9KB -
rpc-transport-http/dist/index.browser.mjs
1.89KB -
rpc-transport-http/dist/index.native.mjs
1.89KB -
rpc/dist/index.native.mjs
1.81KB -
rpc/dist/index.browser.mjs
1.8KB -
rpc-transport-http/dist/index.node.mjs
1.71KB -
rpc-subscriptions-channel-websocket/dist/inde
x.node.mjs
1.33KB -
rpc-subscriptions-channel-websocket/dist/inde
x.native.mjs
1.27KB -
rpc-subscriptions-channel-websocket/dist/inde
x.browser.mjs
1.26KB -
program-client-core/dist/index.browser.mjs
1.21KB -
program-client-core/dist/index.native.mjs
1.21KB -
program-client-core/dist/index.node.mjs
1.21KB -
plugin-core/dist/index.browser.mjs
1.18KB -
plugin-core/dist/index.native.mjs
1.18KB -
plugin-core/dist/index.node.mjs
1.18KB -
options/dist/index.browser.mjs
1.18KB -
options/dist/index.native.mjs
1.18KB -
options/dist/index.node.mjs
1.17KB -
accounts/dist/index.browser.mjs
1.17KB -
accounts/dist/index.native.mjs
1.17KB -
accounts/dist/index.node.mjs
1.16KB -
rpc-spec-types/dist/index.browser.mjs
1.15KB -
rpc-spec-types/dist/index.native.mjs
1.15KB -
rpc-spec-types/dist/index.node.mjs
1.15KB -
rpc-api/dist/index.browser.mjs
1.04KB -
rpc-api/dist/index.native.mjs
1.04KB -
rpc-api/dist/index.node.mjs
1.04KB -
compat/dist/index.browser.mjs
969B -
compat/dist/index.native.mjs
968B -
compat/dist/index.node.mjs
966B -
rpc-spec/dist/index.browser.mjs
898B -
rpc-spec/dist/index.native.mjs
897B -
rpc-spec/dist/index.node.mjs
896B -
rpc-subscriptions-api/dist/index.native.mjs
871B -
rpc-subscriptions-api/dist/index.browser.mjs
870B -
rpc-subscriptions-api/dist/index.node.mjs
870B -
promises/dist/index.native.mjs
841B -
promises/dist/index.node.mjs
840B -
promises/dist/index.browser.mjs
839B -
assertions/dist/index.browser.mjs
783B -
instructions/dist/index.browser.mjs
771B -
instructions/dist/index.native.mjs
770B -
instructions/dist/index.node.mjs
768B -
fast-stable-stringify/dist/index.browser.mjs
726B -
fast-stable-stringify/dist/index.native.mjs
725B -
assertions/dist/index.native.mjs
724B -
fast-stable-stringify/dist/index.node.mjs
724B -
assertions/dist/index.node.mjs
723B -
programs/dist/index.browser.mjs
329B -
programs/dist/index.native.mjs
327B -
programs/dist/index.node.mjs
325B -
fs-impl/dist/index.browser.mjs
245B -
event-target-impl/dist/index.node.mjs
230B -
functional/dist/index.browser.mjs
154B -
functional/dist/index.native.mjs
152B -
text-encoding-impl/dist/index.native.mjs
152B -
functional/dist/index.node.mjs
151B -
codecs/dist/index.browser.mjs
145B -
codecs/dist/index.native.mjs
144B -
codecs/dist/index.node.mjs
142B -
event-target-impl/dist/index.browser.mjs
133B -
ws-impl/dist/index.node.mjs
131B -
text-encoding-impl/dist/index.browser.mjs
122B -
fs-impl/dist/index.node.mjs
120B -
text-encoding-impl/dist/index.node.mjs
119B -
ws-impl/dist/index.browser.mjs
113B -
crypto-impl/dist/index.node.mjs
111B -
crypto-impl/dist/index.browser.mjs
109B -
rpc-parsed-types/dist/index.browser.mjs
66B -
rpc-parsed-types/dist/index.native.mjs
65B -
rpc-parsed-types/dist/index.node.mjs
63B -

Total files change +138B +0.02%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

Copy link
Copy Markdown
Member Author

@trevor-cortex

@trevor-cortex trevor-cortex left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary

This PR adds getSignatureFromTransactionIfPresent, a non-throwing variant of getSignatureFromTransaction that returns undefined when the fee payer hasn't signed the transaction. The existing throwing function is refactored to delegate to the new one, so there's a single source of truth for the "first signature is the fee payer" extraction logic.

The change is clean and well-scoped:

  • Refactor is soundgetSignatureFromTransaction keeps its exact behavior (same SOLANA_ERROR__TRANSACTION__FEE_PAYER_SIGNATURE_MISSING error) and the existing tests for it are untouched, which confirms no behavioral drift.
  • Tests cover the right cases — signed fee payer, no signatures at all, and the important edge case where a non-fee-payer has signed but the fee payer slot is still null. That last one verifies the function keys off the first entry in the ordered SignaturesMap rather than "any signature present".
  • Docs are thorough — README, TSDoc with cross-@see links in both directions, and a changeset. The minor bump for a new exported function is correct.
  • Since signatures.ts is re-exported via export * from './signatures', the new function flows through to @solana/kit automatically.

Notes for subsequent reviewers

  • The !transactionSignature falsy check in the throwing wrapper is safe: the base58 decoding of 64 signature bytes can never produce an empty string, so the only falsy value is undefined.
  • Nothing else in the monorepo needed updating — existing callers of getSignatureFromTransaction are unaffected.

LGTM. (Submitting as a comment since I don't have approve permissions on this repo.)

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Documentation Preview: https://kit-docs-jpq5lklwq-anza-tech.vercel.app

@mcintyre94
mcintyre94 marked this pull request as ready for review August 7, 2026 08:14
@mcintyre94
mcintyre94 force-pushed the tx-signature-if-present branch from 689f04c to 43733d1 Compare August 7, 2026 08:26

Copy link
Copy Markdown
Member Author

Falsy check is changed to transactionSignature === undefined. This avoids a regression in existing tests that use an empty string signature.

Asking whether a transaction has been signed by its fee payer currently requires either catching `SOLANA_ERROR__TRANSACTION__FEE_PAYER_SIGNATURE_MISSING` from `getSignatureFromTransaction` or reaching into `transaction.signatures` and reimplementing the knowledge that the fee payer occupies the first slot. Neither is something a consumer should have to do, and the first turns an ordinary branch into exception-driven control flow that allocates and formats an error only to discard it.

This adds `getSignatureFromTransactionIfPresent`, which returns `undefined` in that case, and reimplements `getSignatureFromTransaction` on top of it so the two cannot drift and the "first signature is the fee payer" comment lives in exactly one place. Behaviour is unchanged: the throwing variant still raises the same error under the same condition.

The motivating case is a transaction partially signed by an authority and handed to a relayer that will pay for it. Such a transaction has a perfectly valid set of signatures and simply does not have an identifier yet, so callers that hold one need a way to ask without treating the answer as exceptional.
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.

2 participants