> For the complete documentation index, see [llms.txt](https://fifo-docs.gitbook.io/colibri/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://fifo-docs.gitbook.io/colibri/colibri-core/signer.md).

# Signer

The Signer module defines independent capabilities for transaction envelopes and Soroban authorization entries. A Soroban configuration can mix signers that implement either capability.

## Signer Capabilities

```ts
type EnvelopeSigner = {
  signerKey(): ExtraSignerKey;
  signTransaction(
    tx: SignableTransaction,
  ): Promise<TransactionXDRBase64> | TransactionXDRBase64;
  signsFor(target: Ed25519PublicKey | ContractId): boolean;
};

type PreAuthTransactionSigner = {
  signerKey(): PreAuthTx;
  authorizesTransaction(
    tx: SignableTransaction,
  ): Promise<boolean> | boolean;
  signsFor(target: Ed25519PublicKey | ContractId): boolean;
};

type AuthEntrySigner = {
  signSorobanAuthEntry(
    authEntry: SorobanAuthorizationEntryLike,
    validUntilLedgerSeq: number,
    networkPassphrase: string,
    forAddress?: Ed25519PublicKey | ContractId,
  ): Promise<SorobanAuthorizationEntryLike>;
  signsFor(target: Ed25519PublicKey | ContractId): boolean;
};

type Signer =
  | EnvelopeSigner
  | PreAuthTransactionSigner
  | AuthEntrySigner;
```

`KeypairSigner` is the complete Ed25519 interface for implementations that support detached signatures, envelopes, and authorization entries:

```ts
type KeypairSigner = EnvelopeSigner & AuthEntrySigner & {
  publicKey(): Ed25519PublicKey;
  sign(data: Uint8Array): Uint8Array;
};
```

[`LocalSigner`](/colibri/colibri-core/signer/local-signer.md) implements `KeypairSigner`, while [`DelegatedSigner`](/colibri/colibri-core/signer/delegated-signer.md) implements only `AuthEntrySigner`. [`HashXSigner`](/colibri/colibri-core/signer/hash-x-signer.md) and [`Ed25519SignedPayloadSigner`](/colibri/colibri-core/signer/signed-payload-signer.md) implement `EnvelopeSigner`. [`PreAuthorizedTransactionSigner`](/colibri/colibri-core/signer/pre-authorized-transaction-signer.md) verifies a transaction hash without adding a decorated signature.

A native Stellar SDK signing `Keypair` can be adapted explicitly with [`LocalSigner.fromKeypair(keypair)`](/colibri/colibri-core/signer/local-signer.md#from-a-stellar-sdk-keypair). The result implements the same signer capabilities described above; `Signer` and [`TransactionConfig`](/colibri/colibri-core/transaction-config.md) remain unchanged. See [the Keypair factory](/colibri/colibri-core/signer/local-signer.md#from-a-stellar-sdk-keypair) for targets and ownership.

## Using Signers

Pass every signer through the same [`TransactionConfig.signers`](/colibri/colibri-core/transaction-config.md#signers) list:

```ts
import { createInvokeContractPipeline, NetworkConfig } from "@colibri/core";

const networkConfig = NetworkConfig.TestNet();
const invokeContract = createInvokeContractPipeline({ networkConfig });

const result = await invokeContract({
  operations,
  config: {
    source: signer.publicKey(),
    fee: "100000",
    timeout: 30,
    signers: [signer],
  },
});
```

The pipeline carries `Signer[]` unchanged until a process needs a capability. [`signAuthEntries(...)`](/colibri/colibri-core/processes/sign-auth-entries.md) narrows with `isAuthEntrySigner(...)`, while [`signEnvelope(...)`](/colibri/colibri-core/processes/sign-envelope.md) narrows with `isEnvelopeSigner(...)` and `isPreAuthTransactionSigner(...)`. A signer implementing multiple capabilities passes every applicable guard.

Every transaction authorizer exposes an exact `signerKey()`. Colibri uses that identity to match transaction `extraSigners` and deduplicate a signer selected through both an account requirement and an exact key requirement.

For each required account, selection is intentional:

* no matching target produces [`SIGNER_NOT_FOUND`](/colibri/reference/errors/core-processes-sign-envelope.md);
* one matching signer key is selected;
* multiple instances of one key produce [`DUPLICATE_SIGNER_KEY`](/colibri/reference/errors/core-processes-sign-envelope.md);
* multiple distinct keys produce [`AMBIGUOUS_ACCOUNT_SIGNERS`](/colibri/reference/errors/core-processes-sign-envelope.md).

Colibri does not select by array order or apply implicit signer precedence. Weighted multi-signature policy remains an application-level concern.

## Implementing A Custom Authorization-Entry Signer

This complete adapter declaration forwards the full entry to an application-provided authorizer. Install Core and save it as a TypeScript module; construct it with your contract address and actual wallet/signature function. It does not guess or supply a contract's custom authorization policy.

```ts
import type {
  AuthEntrySigner,
  ContractId,
  Ed25519PublicKey,
  SorobanAuthorizationEntryLike,
} from "@colibri/core";

class CustomAuthEntrySigner implements AuthEntrySigner {
  constructor(
    private readonly address: ContractId,
    private readonly authorize: AuthEntrySigner["signSorobanAuthEntry"],
  ) {}

  signSorobanAuthEntry(
    authEntry: SorobanAuthorizationEntryLike,
    validUntilLedgerSeq: number,
    networkPassphrase: string,
    forAddress?: Ed25519PublicKey | ContractId,
  ): Promise<SorobanAuthorizationEntryLike> {
    return this.authorize(
      authEntry,
      validUntilLedgerSeq,
      networkPassphrase,
      forAddress,
    );
  }

  signsFor(target: Ed25519PublicKey | ContractId) {
    return target === this.address;
  }
}
```

The method receives and returns the entire authorization entry. This keeps custom account policy inside the signer implementation. Colibri does not attempt to interpret custom signature values. Delegated credentials are validated by the account contract during [`enforceSimulation`](/colibri/colibri-core/processes/enforce-simulation.md); other custom authorization remains subject to the network's normal execution checks.

## Available Signers

| Signer                                                                                              | Description                                               |
| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| [LocalSigner](/colibri/colibri-core/signer/local-signer.md)                                         | In-memory Ed25519 envelope and authorization-entry signer |
| [HashXSigner](/colibri/colibri-core/signer/hash-x-signer.md)                                        | Hash-X preimage envelope signer                           |
| [Ed25519SignedPayloadSigner](/colibri/colibri-core/signer/signed-payload-signer.md)                 | Ed25519 signature over a disclosed payload                |
| [PreAuthorizedTransactionSigner](/colibri/colibri-core/signer/pre-authorized-transaction-signer.md) | Exact transaction-hash authorizer                         |
| [DelegatedSigner](/colibri/colibri-core/signer/delegated-signer.md)                                 | Recursive CAP-71 authorization-entry signer               |

## Message signing

[SEP-53 message signing](/colibri/colibri-core/signer/message-signing.md) is an optional capability separate from transaction-envelope and authorization-entry signing. See that guide for message encoding, wallet interoperability and verification.

## Next Steps

* [LocalSigner](/colibri/colibri-core/signer/local-signer.md) — Built-in signer implementation
* [HashXSigner](/colibri/colibri-core/signer/hash-x-signer.md) — Hash-X signer and preimage lifecycle
* [Ed25519SignedPayloadSigner](/colibri/colibri-core/signer/signed-payload-signer.md) — Signed payload flow
* [PreAuthorizedTransactionSigner](/colibri/colibri-core/signer/pre-authorized-transaction-signer.md) — Exact transaction authorization
* [DelegatedSigner](/colibri/colibri-core/signer/delegated-signer.md) — Recursive delegated authorization
* [Transaction Config](/colibri/colibri-core/transaction-config.md) — Where signers are supplied
