Skip to content

Narrowing the signer in TransactionMessageWithSigners<TAddress, TSigner> doesn't work #1036

@mcintyre94

Description

@mcintyre94

Overview

I'm looking into whether we can make the signTransactionMessageWithSigners method return an unmodified specific lifetime (instead of the looser TransactionWithLifetime) in cases where the signers in a transaction message are non-modifying

I think this can be accomplished with some clever overloads, making use of the TransactionMessageWithSigners<TAddress, TSigners> type. As documented, this should allow us to narrow the type of signers permitted in the transaction.

But there's currently a bug where this type does not actually narrow the allowed signers.

Steps to reproduce

import { Address } from "@solana/addresses";
import { pipe } from "@solana/functional";
import { TransactionMessageWithSigners, TransactionModifyingSigner, TransactionPartialSigner, setTransactionMessageFeePayerSigner } from "@solana/signers";
import { createTransactionMessage } from "@solana/transaction-messages";

{
    const signer = null as unknown as TransactionModifyingSigner;

    const transactionMessage = pipe(
        createTransactionMessage({ version: 0 }),
        tx => setTransactionMessageFeePayerSigner(signer, tx),
    )

    // no type error
    transactionMessage satisfies TransactionMessageWithSigners<Address, TransactionPartialSigner>;
}

Description of bug

The issue is that the type is defined to allow eg a non-signer fee payer, or a signer fee payer. TransactionModifyingSigner satisfies {feePayer: Address} since the signer is a superset of the fee payer {address: Address}. This means that the type narrowing on TransactionMessageWithFeePayerSigner<TAddress, TSigner>> is not applied.

The same logic affects instructions, where an instruction with a TransactionModifyingSigner will satisfy the Instruction part of that check and again the narrowing is never applied.

If I'm understanding this correctly, the signer-related types in this function are never actually used currently, because the non-signer subsets are always satisfied by all signers.

We will need to define types like TransactionMessageWithNonSignerFeePayer that signers cannot match, so that the narrowed signer checks are applied when a signer is the fee payer/in an instruction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions