Skip to content

Add a function to extract the lifetime from a CompiledTransactionMessage#918

Merged
mcintyre94 merged 2 commits into
mainfrom
transaction-lifetime-construct
Oct 3, 2025
Merged

Add a function to extract the lifetime from a CompiledTransactionMessage#918
mcintyre94 merged 2 commits into
mainfrom
transaction-lifetime-construct

Conversation

@mcintyre94
Copy link
Copy Markdown
Member

@mcintyre94 mcintyre94 commented Sep 30, 2025

Problem

When writing a signer, it is possible that you receive a Transaction from for example an external wallet, and need to determine its lifetime constraint.

Summary of Changes

This PR adds a new function getTransactionLifetimeConstraintFromCompiledTransactionMessage which enables a best-effort extraction of the lifetime constraint from a CompiledTransactionMessage, ie without full information about the transaction.

The check is less robust than the equivalent for a TransactionMessage, because the accounts passed to an advance nonce instruction may be in lookup tables - and therefore we can't verify their address or role. However, we are able to check the program address, program data and number of accounts passed in. A transaction that incorrectly passes this check is one that passes incorrect accounts to the advance nonce instruction. The impact of attempting to confirm it with an incorrect lifetime should be minimal (it will fail to land regardless).

There is one error case I've added - if the first account passed to the instruction is not a static address, then we can't use its address in the returned TransactionDurableNonceLifetime and we throw. I think this is an edge case and not worth the cost of resolving lookup tables.

This function will be used to enable useWalletAccountTransactionSigner to return a lifetime in cases where the wallet modifies the lifetime token of the input transaction. I think it will also be useful to anybody else writing similar signers.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Sep 30, 2025

🦋 Changeset detected

Latest commit: 7171940

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

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

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

@bundlemon
Copy link
Copy Markdown

bundlemon Bot commented Sep 30, 2025

BundleMon

Files updated (7)
Status Path Size Limits
transactions/dist/index.browser.mjs
2.71KB (+412B +17.44%) -
transactions/dist/index.native.mjs
2.71KB (+412B +17.45%) -
transactions/dist/index.node.mjs
2.71KB (+411B +17.42%) -
errors/dist/index.browser.mjs
15.5KB (+140B +0.89%) -
errors/dist/index.native.mjs
15.5KB (+139B +0.88%) -
errors/dist/index.node.mjs
15.52KB (+137B +0.87%) -
@solana/kit production bundle
kit/dist/index.production.min.js
35.91KB (+126B +0.34%) -
Unchanged files (123)
Status Path Size Limits
rpc-graphql/dist/index.browser.mjs
18.82KB -
rpc-graphql/dist/index.native.mjs
18.81KB -
rpc-graphql/dist/index.node.mjs
18.81KB -
transaction-messages/dist/index.browser.mjs
7.25KB -
transaction-messages/dist/index.native.mjs
7.25KB -
transaction-messages/dist/index.node.mjs
7.25KB -
codecs-data-structures/dist/index.browser.mjs
4.69KB -
codecs-data-structures/dist/index.native.mjs
4.69KB -
codecs-data-structures/dist/index.node.mjs
4.69KB -
webcrypto-ed25519-polyfill/dist/index.node.mj
s
3.6KB -
webcrypto-ed25519-polyfill/dist/index.browser
.mjs
3.59KB -
webcrypto-ed25519-polyfill/dist/index.native.
mjs
3.57KB -
instruction-plans/dist/index.browser.mjs
3.42KB -
instruction-plans/dist/index.native.mjs
3.42KB -
instruction-plans/dist/index.node.mjs
3.41KB -
rpc-subscriptions/dist/index.browser.mjs
3.37KB -
rpc-subscriptions/dist/index.node.mjs
3.34KB -
rpc-subscriptions/dist/index.native.mjs
3.31KB -
codecs-core/dist/index.browser.mjs
3.31KB -
codecs-core/dist/index.native.mjs
3.31KB -
codecs-core/dist/index.node.mjs
3.31KB -
addresses/dist/index.browser.mjs
2.93KB -
rpc-transformers/dist/index.browser.mjs
2.93KB -
rpc-transformers/dist/index.native.mjs
2.93KB -
addresses/dist/index.native.mjs
2.93KB -
addresses/dist/index.node.mjs
2.93KB -
rpc-transformers/dist/index.node.mjs
2.93KB -
signers/dist/index.browser.mjs
2.63KB -
signers/dist/index.native.mjs
2.63KB -
signers/dist/index.node.mjs
2.62KB -
codecs-strings/dist/index.browser.mjs
2.53KB -
codecs-strings/dist/index.node.mjs
2.48KB -
codecs-strings/dist/index.native.mjs
2.45KB -
transaction-confirmation/dist/index.node.mjs
2.41KB -
transaction-confirmation/dist/index.native.mj
s
2.36KB -
transaction-confirmation/dist/index.browser.m
js
2.35KB -
sysvars/dist/index.browser.mjs
2.35KB -
sysvars/dist/index.native.mjs
2.34KB -
sysvars/dist/index.node.mjs
2.34KB -
rpc-subscriptions-spec/dist/index.node.mjs
2.18KB -
rpc-subscriptions-spec/dist/index.native.mjs
2.13KB -
rpc-subscriptions-spec/dist/index.browser.mjs
2.13KB -
keys/dist/index.browser.mjs
2.08KB -
keys/dist/index.native.mjs
2.08KB -
keys/dist/index.node.mjs
2.08KB -
codecs-numbers/dist/index.native.mjs
2.01KB -
codecs-numbers/dist/index.browser.mjs
2.01KB -
codecs-numbers/dist/index.node.mjs
2.01KB -
react/dist/index.native.mjs
1.99KB -
react/dist/index.browser.mjs
1.99KB -
react/dist/index.node.mjs
1.99KB -
rpc/dist/index.node.mjs
1.95KB -
rpc-transport-http/dist/index.browser.mjs
1.91KB -
rpc-transport-http/dist/index.native.mjs
1.9KB -
rpc/dist/index.native.mjs
1.8KB -
subscribable/dist/index.node.mjs
1.8KB -
rpc/dist/index.browser.mjs
1.8KB -
subscribable/dist/index.native.mjs
1.75KB -
subscribable/dist/index.browser.mjs
1.74KB -
rpc-transport-http/dist/index.node.mjs
1.72KB -
kit/dist/index.browser.mjs
1.68KB -
kit/dist/index.native.mjs
1.68KB -
kit/dist/index.node.mjs
1.67KB -
rpc-types/dist/index.browser.mjs
1.53KB -
rpc-types/dist/index.native.mjs
1.53KB -
rpc-types/dist/index.node.mjs
1.53KB -
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 -
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.13KB -
accounts/dist/index.native.mjs
1.12KB -
accounts/dist/index.node.mjs
1.12KB -
rpc-api/dist/index.browser.mjs
976B -
rpc-api/dist/index.native.mjs
975B -
rpc-api/dist/index.node.mjs
973B -
compat/dist/index.browser.mjs
969B -
compat/dist/index.native.mjs
968B -
compat/dist/index.node.mjs
966B -
rpc-spec-types/dist/index.browser.mjs
962B -
rpc-spec-types/dist/index.native.mjs
961B -
rpc-spec-types/dist/index.node.mjs
959B -
rpc-subscriptions-api/dist/index.native.mjs
870B -
rpc-subscriptions-api/dist/index.node.mjs
869B -
rpc-subscriptions-api/dist/index.browser.mjs
868B -
rpc-spec/dist/index.browser.mjs
852B -
rpc-spec/dist/index.native.mjs
851B -
rpc-spec/dist/index.node.mjs
850B -
promises/dist/index.browser.mjs
799B -
promises/dist/index.native.mjs
798B -
promises/dist/index.node.mjs
797B -
assertions/dist/index.browser.mjs
783B -
instructions/dist/index.browser.mjs
769B -
instructions/dist/index.native.mjs
768B -
instructions/dist/index.node.mjs
767B -
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 -
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
137B -
codecs/dist/index.native.mjs
136B -
codecs/dist/index.node.mjs
134B -
event-target-impl/dist/index.browser.mjs
133B -
ws-impl/dist/index.node.mjs
131B -
text-encoding-impl/dist/index.browser.mjs
122B -
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 +1.74KB +0.49%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

@mcintyre94 mcintyre94 marked this pull request as ready for review September 30, 2025 13:52
@mcintyre94 mcintyre94 force-pushed the transaction-lifetime-construct branch from 9e66c0e to 8052f35 Compare September 30, 2025 13:54
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Sep 30, 2025

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

Copy link
Copy Markdown
Contributor

@steveluscher steveluscher left a comment

Choose a reason for hiding this comment

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

I don't have answers, only questions. Should we take the same approach as with transaction confirmation and split these into one function for blockhash based transactions and one for nonce transactions, presuming that the applications knows which one it prepared, rather than to make one function that autodetects the type of lifetime? I presume the answer is no, because in the next PR it's presumed that the wallet-account-transaction-signer is a TransactionModifyingSigner, meaning that just because the transaction went in with a blockhash-based lifetime doesn't mean it's going to come out with one.

Comment thread packages/transactions/src/lifetime.ts Outdated
Comment thread packages/transactions/src/lifetime.ts Outdated
Comment thread packages/transactions/src/__tests__/lifetime-test.ts
Comment thread packages/transactions/src/lifetime.ts Outdated
Copy link
Copy Markdown
Member

@lorisleiva lorisleiva left a comment

Choose a reason for hiding this comment

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

Thank you for your work on that stack! I'm gradually making my way through your PRs. ☺️

Comment thread packages/transactions/src/__tests__/lifetime-test.ts
Comment thread packages/transactions/src/lifetime.ts Outdated
Comment thread packages/transactions/src/lifetime.ts
@mcintyre94 mcintyre94 force-pushed the transaction-lifetime-construct branch from 11136da to 7171940 Compare October 2, 2025 10:07
Copy link
Copy Markdown
Member Author

mcintyre94 commented Oct 3, 2025

Merge activity

  • Oct 3, 10:36 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Oct 3, 10:36 AM UTC: @mcintyre94 merged this pull request with Graphite.

@mcintyre94 mcintyre94 merged commit 5408f52 into main Oct 3, 2025
14 checks passed
@mcintyre94 mcintyre94 deleted the transaction-lifetime-construct branch October 3, 2025 10:36
mcintyre94 added a commit that referenced this pull request Oct 3, 2025
…nt for the updated transaction (#919)

#### Problem

Currently this signer only returns what is required for the signer interface, a `Transaction`. However, per #891 this interface needs to be changed to return a `Transaction & TransactionWithLifetime`, ie augmented with a `lifetimeConstraint` field.

#### Summary of Changes

The signer now returns a lifetime, by decoding the returned `messageBytes` and comparing the returned `lifetimeToken` with the existing lifetime of the input transaction.

- If the input transaction does not have a lifetime, then we create one for the signed transaction using #918. Otherwise:
- If the input transaction and signed transaction have identical message bytes, then we return the existing lifetime. Ie if the wallet returns the transaction unchanged.
- If the message bytes differ, but the `lifetimeToken` of the signed transaction matches the existing lifetime (either blockhash or nonce field), then we return the existing lifetime. Ie if the wallet modifies the transaction but not its lifetime.
- If the lifetime token of the signed transaction differs from that of the input transaction, then we create a new lifetime for the signed transaction using #918. 

This pre-emptively makes `useWalletAccountTransactionSigner` comply with a stricter interface for `TransactionModifyingSigner` that will require returning `Transaction & TransactionWithLifetime`.
@github-actions
Copy link
Copy Markdown
Contributor

Because there has been no activity on this PR for 14 days since it was merged, it has been automatically locked. Please open a new issue if it requires a follow up.

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Oct 20, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants