8000 Use `TransactionMessageWithinSizeLimit` in helper functions by lorisleiva · Pull Request #468 · anza-xyz/kit · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Use TransactionMessageWithinSizeLimit in helper functions #468

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/better-crabs-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@solana/transaction-messages': minor
'@solana/transactions': minor
'@solana/signers': minor
---

Add, remove and forward the `TransactionMessageWithinSizeLimit` and `TransactionWithinSizeLimit` types in all helpers that may affect the size of a transaction or transaction message.
20 changes: 20 additions & 0 deletions packages/signers/src/__typetests__/sign-transaction-typetest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import {
CompilableTransactionMessage,
TransactionMessageWithBlockhashLifetime,
TransactionMessageWithDurableNonceLifetime,
TransactionMessageWithinSizeLimit,
} from '@solana/transaction-messages';
import {
FullySignedTransaction,
Transaction,
TransactionWithBlockhashLifetime,
TransactionWithDurableNonceLifetime,
TransactionWithinSizeLimit,
TransactionWithLifetime,
} from '@solana/transactions';

Expand Down Expand Up @@ -49,6 +51,15 @@ type CompilableTransactionMessageWithSigners = CompilableTransactionMessage & Tr
>;
}

{
// [partiallySignTransactionMessageWithSigners]: returns a transaction with a `TransactionWithinSizeLimit` flag
const transacti 10000 as unknown as CompilableTransactionMessageWithSigners &
TransactionMessageWithinSizeLimit;
partiallySignTransactionMessageWithSigners(transactionMessage) satisfies Promise<
Readonly<Transaction & TransactionWithinSizeLimit>
>;
}

{
// [signTransactionMessageWithSigners]: returns a fully signed transaction with a blockhash lifetime
const transactionMessage = null as unknown as CompilableTransactionMessageWithSigners &
Expand All @@ -75,6 +86,15 @@ type CompilableTransactionMessageWithSigners = CompilableTransactionMessage & Tr
>;
}

{
// [signTransactionMessageWithSigners]: returns a transaction with a `TransactionWithinSizeLimit` flag
const transactionMessage = null as unknown as CompilableTransactionMessageWithSigners &
TransactionMessageWithinSizeLimit;
signTransactionMessageWithSigners(transactionMessage) satisfies Promise<
Readonly<FullySignedTransaction & Transaction & TransactionWithinSizeLimit>
>;
}

{
// [signAndSendTransactionMessageWithSigners]: returns a signature
const transactionMessage = null as unknown as CompilableTransactionMessageWithSigners &
Expand Down
80 changes: 13 additions & 67 deletions packages/signers/src/sign-transaction.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import { SOLANA_ERROR__SIGNER__TRANSACTION_SENDING_SIGNER_MISSING, SolanaError } from '@solana/errors';
import { SignatureBytes } from '@solana/keys';
import {
CompilableTransactionMessage,
TransactionMessageWithBlockhashLifetime,
TransactionMessageWithDurableNonceLifetime,
} from '@solana/transaction-messages';
import { CompilableTransactionMessage } from '@solana/transaction-messages';
import {
assertTransactionIsFullySigned,
compileTransaction,
FullySignedTransaction,
Transaction,
TransactionWithBlockhashLifetime,
TransactionWithDurableNonceLifetime,
TransactionFromCompilableTransactionMessage,
TransactionWithLifetime,
} from '@solana/transactions';

Expand Down Expand Up @@ -72,36 +67,11 @@ type CompilableTransactionMessageWithSigners = CompilableTransactionMessage & Tr
* @see {@link signAndSendTransactionMessageWithSigners}
*/
export async function partiallySignTransactionMessageWithSigners<
TTransactionMessage extends CompilableTransactionMessageWithSigners &
TransactionMessageWithBlockhashLifetime = CompilableTransactionMessageWithSigners &
TransactionMessageWithBlockhashLifetime,
>(
transactionMessage: TTransactionMessage,
config?: TransactionPartialSignerConfig,
): Promise<Transaction & TransactionWithBlockhashLifetime>;

export async function partiallySignTransactionMessageWithSigners<
TTransactionMessage extends CompilableTransactionMessageWithSigners &
TransactionMessageWithDurableNonceLifetime = CompilableTransactionMessageWithSigners &
TransactionMessageWithDurableNonceLifetime,
>(
transactionMessage: TTransactionMessage,
config?: TransactionPartialSignerConfig,
): Promise<Readonly<Transaction & TransactionWithDurableNonceLifetime>>;

export async function partiallySignTransactionMessageWithSigners<
TTransactionMessage extends CompilableTransactionMessageWithSigners = CompilableTransactionMessageWithSigners,
>(
transactionMessage: TTransactionMessage,
config?: TransactionPartialSignerConfig,
): Promise<Readonly<Transaction & TransactionWithLifetime>>;

export async function partiallySignTransactionMessageWithSigners<
TTransactionMessage extends CompilableTransactionMessageWithSigners = CompilableTransactionMessageWithSigners,
TTransactionMessage extends CompilableTransactionMessageWithSigners,
>(
transactionMessage: TTransactionMessage,
config?: TransactionPartialSignerConfig,
): Promise<Readonly<Transaction & TransactionWithLifetime>> {
): Promise<TransactionFromCompilableTransactionMessage<TTransactionMessage>> {
const { partialSigners, modifyingSigners } = categorizeTransactionSigners(
deduplicateSigners(getSignersFromTransactionMessage(transactionMessage).filter(isTransactionSigner)),
{ identifySendingSigner: false },
Expand Down Expand Up @@ -142,36 +112,11 @@ export async function partiallySignTransactionMessageWithSigners<
* @see {@link signAndSendTransactionMessageWithSigners}
*/
export async function signTransactionMessageWithSigners<
TTransactionMessage extends CompilableTransactionMessageWithSigners &
TransactionMessageWithBlockhashLifetime = CompilableTransactionMessageWithSigners &
TransactionMessageWithBlockhashLifetime,
TTransactionMessage extends CompilableTransactionMessageWithSigners,
>(
transactionMessage: TTransactionMessage,
config?: TransactionPartialSignerConfig,
): Promise<Readonly<FullySignedTransaction & TransactionWithBlockhashLifetime>>;

export async function signTransactionMessageWithSigners<
TTransactionMessage extends CompilableTransactionMessageWithSigners &
TransactionMessageWithDurableNonceLifetime = CompilableTransactionMessageWithSigners &
TransactionMessageWithDurableNonceLifetime,
>(
transactionMessage: TTransactionMessage,
config?: TransactionPartialSignerConfig,
): Promise<Readonly<FullySignedTransaction & TransactionWithDurableNonceLifetime>>;

export async function signTransactionMessageWithSigners<
TTransactionMessage extends CompilableTransactionMessageWithSigners = CompilableTransactionMessageWithSigners,
>(
transactionMessage: TTransactionMessage,
config?: TransactionPartialSignerConfig,
): Promise<Readonly<FullySignedTransaction & TransactionWithLifetime>>;

export async function signTransactionMessageWithSigners<
TTransactionMessage extends CompilableTransactionMessageWithSigners = CompilableTransactionMessageWithSigners,
>(
transactionMessage: TTransactionMessage,
config?: TransactionPartialSignerConfig,
): Promise<Readonly<FullySignedTransaction & TransactionWithLifetime>> {
): Promise<FullySignedTransaction & TransactionFromCompilableTransactionMessage<TTransactionMessage>> {
const signedTransaction = await partiallySignTransactionMessageWithSigners(transactionMessage, config);
assertTransactionIsFullySigned(signedTransaction);
return signedTransaction;
Expand Down Expand Up @@ -334,13 +279,15 @@ function identifyTransactionModifyingSigners(
* sequentially followed by the TransactionPartialSigners in parallel.
*/
async function signModifyingAndPartialTransactionSigners<
TTransactionMessage extends CompilableTransactionMessageWithSigners = CompilableTransactionMessageWithSigners,
TTransactionMessage extends CompilableTransactionMessageWithSigners,
>(
transactionMessage: TTransactionMessage,
modifyingSigners: readonly TransactionModifyingSigner[] = [],
partialSigners: readonly TransactionPartialSigner[] = [],
config?: TransactionModifyingSignerConfig,
): Promise<Readonly<Transaction & TransactionWithLifetime>> {
): Promise<TransactionFromCompilableTransactionMessage<TTransactionMessage>> {
type ReturnType = TransactionFromCompilableTransactionMessage<TTransactionMessage>;

// serialize the transaction
const transaction = compileTransaction(transactionMessage);

Expand All @@ -362,14 +309,13 @@ async function signModifyingAndPartialTransactionSigners<
return signatures;
}),
);
const signedTransaction: Readonly<Transaction & TransactionWithLifetime> = {

return Object.freeze({
...modifiedTransaction,
signatures: Object.freeze(
signatureDictionaries.reduce((signatures, signatureDictionary) => {
return { ...signatures, ...signatureDictionary };
}, modifiedTransaction.signatures ?? {}),
),
};

return Object.freeze(signedTransaction);
}) as ReturnType;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createTransactionMessage } from '../create-transaction-message';
import { TransactionMessage } from '../transaction-message';
import { TransactionMessageWithinSizeLimit } from '../transaction-message-size';

type LegacyTransactionMessage = Extract<TransactionMessage, { version: 'legacy' }>;
type V0TransactionMessage = Extract<TransactionMessage, { version: 0 }>;
Expand All @@ -19,3 +20,9 @@ type V0TransactionMessage = Extract<TransactionMessage, { version: 0 }>;
// @ts-expect-error Should not be legacy.
message satisfies LegacyTransactionMessage;
}

// It returns an empty transaction message with size limit type safety.
{
createTransactionMessage({ version: 'legacy' }) satisfies TransactionMessageWithinSizeLimit;
createTransactionMessage({ version: 0 }) satisfies TransactionMessageWithinSizeLimit;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Address } from '@solana/addresses';
import { pipe } from '@solana/functional';
import { IInstruction } from '@solana/instructions';

import { TransactionMessageWithBlockhashLifetime } from '../blockhash';
import { CompilableTransactionMessage } from '../compilable-transaction-message';
import { createTransactionMessage } from '../create-transaction-message';
import {
Expand All @@ -15,6 +16,7 @@ import { AdvanceNonceAccountInstruction } from '../durable-nonce-instruction';
import { setTransactionMessageFeePayer } from '../fee-payer';
import { appendTransactionMessageInstruction } from '../instructions';
import { BaseTransactionMessage, TransactionMessage } from '../transaction-message';
import { TransactionMessageWithinSizeLimit } from '../transaction-message-size';

const mockNonceConfig = {
nonce: null as unknown as Nonce<'nonce'>,
Expand Down Expand Up @@ -124,4 +126,31 @@ type V0TransactionMessage = Extract<TransactionMessage, { version: 0 }>;
InstructionA,
];
}

// It keeps the size limit type safety if we are only updating the durable nonce lifetime.
{
const message = null as unknown as BaseTransactionMessage &
TransactionMessageWithDurableNonceLifetime &
TransactionMessageWithinSizeLimit;
const newMessage = setTransactionMessageLifetimeUsingDurableNonce(mockNonceConfig, message);
newMessage satisfies TransactionMessageWithinSizeLimit;
}

// It removes the size limit type safety if we previously has a blockhash lifetime.
{
const message = null as unknown as BaseTransactionMessage &
TransactionMessageWithBlockhashLifetime &
TransactionMessageWithinSizeLimit;
const newMessage = setTransactionMessageLifetimeUsingDurableNonce(mockNonceConfig, message);
// @ts-expect-error The message may no longer be within size limit.
newMessage satisfies TransactionMessageWithinSizeLimit;
}

// It removes the size limit type safety if we previously had no lifetime set.
{
const message = null as unknown as BaseTransactionMessage & TransactionMessageWithinSizeLimit;
const newMessage = setTransactionMessageLifetimeUsingDurableNonce(mockNonceConfig, message);
// @ts-expect-error The message may no longer be within size limit.
newMessage satisfies TransactionMessageWithinSizeLimit;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
prependTransactionMessageInstructions,
} from '../instructions';
import { BaseTransactionMessage } from '../transaction-message';
import { TransactionMessageWithinSizeLimit } from '../transaction-message-size';

type IInstruction = BaseTransactionMessage['instructions'][number];
type InstructionA = IInstruction & { identifier: 'A' };
Expand Down Expand Up @@ -81,6 +82,14 @@ type InstructionC = IInstruction & { identifier: 'C' };
message satisfies BaseTransactionMessage & TransactionMessageWithDurableNonceLifetime;
message.instructions satisfies readonly [AdvanceNonceAccountInstruction, InstructionA];
}

// It removes the size limit type safety.
{
const message = null as unknown as BaseTransactionMessage & TransactionMessageWithinSizeLimit;
const newMessage = appendTransactionMessageInstruction(null as unknown as IInstruction, message);
// @ts-expect-error Potentially no longer within size limit.
newMessage satisfies TransactionMessageWithinSizeLimit;
}
}

// [DESCRIBE] appendTransactionMessageInstructions
Expand Down Expand Up @@ -115,6 +124,14 @@ type InstructionC = IInstruction & { identifier: 'C' };
);
newMessage.instructions satisfies readonly [...IInstruction[], InstructionA, InstructionB];
}

// It removes the size limit type safety.
{
const message = null as unknown as BaseTransactionMessage & TransactionMessageWithinSizeLimit;
const newMessage = appendTransactionMessageInstructions([null as unknown as IInstruction], message);
// @ts-expect-error Potentially no longer within size limit.
newMessage satisfies TransactionMessageWithinSizeLimit;
}
}

// [DESCRIBE] prependTransactionMessageInstruction
Expand Down Expand Up @@ -195,6 +212,14 @@ type InstructionC = IInstruction & { identifier: 'C' };
// @ts-expect-error No longer a durable nonce lifetime.
message satisfies BaseTransactionMessage & TransactionMessageWithDurableNonceLifetime;
}

// It removes the size limit type safety.
{
const message = null as unknown as BaseTransactionMessage & TransactionMessageWithinSizeLimit;
const newMessage = prependTransactionMessageInstruction(null as unknown as IInstruction, message);
// @ts-expect-error Potentially no longer within size limit.
newMessage satisfies TransactionMessageWithinSizeLimit;
}
}

// [DESCRIBE] prependTransactionMessageInstructions
Expand Down Expand Up @@ -239,4 +264,12 @@ type InstructionC = IInstruction & { identifier: 'C' };
);
newMessage.instructions satisfies readonly [InstructionA, InstructionB, ...IInstruction[]];
}

// It removes the size limit type safety.
{
const message = null as unknown as BaseTransactionMessage & TransactionMessageWithinSizeLimit;
const newMessage = prependTransactionMessageInstructions([null as unknown as IInstruction], message);
// @ts-expect-error Potentially no longer within size limit.
newMessage satisfies TransactionMessageWithinSizeLimit;
}
}
16 changes: 10 additions & 6 deletions packages/transaction-messages/src/create-transaction-message.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { TransactionMessage, TransactionVersion } from './transaction-message';
import { TransactionMessageWithinSizeLimit } from './transaction-message-size';

type TransactionConfig<TVersion extends TransactionVersion> = Readonly<{
version: TVersion;
}>;

type EmptyTransactionMessage<TVersion extends TransactionVersion> = Omit<
Extract<TransactionMessage, { version: TVersion }>,
'instructions'
> &
TransactionMessageWithinSizeLimit & { instructions: readonly [] };

/**
* Given a {@link TransactionVersion} this method will return an empty transaction having the
* capabilities of that version.
Expand All @@ -17,12 +24,9 @@ type TransactionConfig<TVersion extends TransactionVersion> = Readonly<{
*/
export function createTransactionMessage<TVersion extends TransactionVersion>(
config: TransactionConfig<TVersion>,
): Omit<Extract<TransactionMessage, { version: TVersion }>, 'instructions'> & { instructions: readonly [] };
export function createTransactionMessage<TVersion extends TransactionVersion>({
version,
}: TransactionConfig<TVersion>): TransactionMessage {
): EmptyTransactionMessage<TVersion> {
return Object.freeze({
instructions: Object.freeze([]),
version,
}) as TransactionMessage;
version: config.version,
}) as EmptyTransactionMessage<TVersion>;
}
12 changes: 11 additions & 1 deletion packages/transaction-messages/src/durable-nonce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from './durable-nonce-instruction';
import { ExcludeTransactionMessageLifetime } from './lifetime';
import { BaseTransactionMessage } from './transaction-message';
import { ExcludeTransactionMessageWithinSizeLimit } from './transaction-message-size';

type DurableNonceConfig<
TNonceAccountAddress extends string = string,
Expand Down Expand Up @@ -260,7 +261,15 @@ type SetTransactionMessageWithDurableNonceLifetime<
TNonceAccountAddress extends string = string,
TNonceAuthorityAddress extends string = string,
TNonceValue extends string = string,
> = Omit<TTransactionMessage, 'instructions'> & {
> = Omit<
// 1. The transaction message only grows in size if it currently has a different (or no) lifetime.
TTransactionMessage extends TransactionMessageWithDurableNonceLifetime
? TTransactionMessage
: ExcludeTransactionMessageWithinSizeLimit<TTransactionMessage>,
// 2. Remove the instructions array as we are going to replace it with a new one.
'instructions'
> & {
// 3. Replace or prepend the first instruction with the advance nonce account instruction.
readonly instructions: TTransactionMessage['instructions'] extends readonly [
AdvanceNonceAccountInstruction,
...infer TTail extends readonly IInstruction[],
Expand All @@ -270,5 +279,6 @@ type SetTransactionMessageWithDurableNonceLifetime<
AdvanceNonceAccountInstruction<TNonceAccountAddress, TNonceAuthorityAddress>,
...TTransactionMessage['instructions'],
];
// 4. Set the lifetime constraint to the nonce value.
readonly lifetimeConstraint: NonceLifetimeConstraint<TNonceValue>;
};
1 change: 1 addition & 0 deletions packages/transaction-messages/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export * from './durable-nonce';
export { isAdvanceNonceAccountInstruction } from './durable-nonce-instruction';
export * from './fee-payer';
export * from './instructions';
export * from './transaction-message-size';
export * from './transaction-message';

// Remove in the next major version.
Expand Down
Loading
0