@solana/pay
Version:
`@solana/pay` is a JavaScript library for facilitating commerce on Solana by using a token transfer URL scheme. The URL scheme ensures that no matter the wallet or service used, the payment request must be created and interpreted in one standard way.
73 lines (64 loc) • 2.63 kB
text/typescript
import type { Address, GetSignaturesForAddressApi, Rpc } from '@solana/kit';
import type { Commitment, Signature } from '@solana/kit';
import type { Reference } from './types.js';
/**
* Thrown when no transaction signature can be found referencing a given address.
*/
export class FindReferenceError extends Error {
name = 'FindReferenceError';
}
/** Options for {@link findReference}. */
export interface FindReferenceOptions {
/** Limit the number of signatures returned. */
limit?: number;
/** Start searching backwards from this signature. */
before?: Signature;
/** Search until this signature is reached. */
until?: Signature;
/** Commitment level to use for the query. */
commitment?: Exclude<Commitment, 'processed'>;
}
/** A confirmed signature info entry returned by the RPC. */
export interface ConfirmedSignatureInfo {
signature: Signature;
slot: bigint | number;
err: unknown | null;
memo: string | null;
blockTime: bigint | number | null;
confirmationStatus: Commitment | null;
}
/**
* Find the oldest transaction signature referencing a given address.
*
* @param rpc - An RPC client supporting `getSignaturesForAddress`.
* @param reference - `reference` in the [Solana Pay spec](https://github.com/solana-foundation/pay/blob/main/typescript/packages/solana-pay/spec/SPEC.md#reference).
* @param options - Options for `getSignaturesForAddress`.
*
* @throws {FindReferenceError}
*/
export async function findReference(
rpc: Rpc<GetSignaturesForAddressApi>,
reference: Reference,
{ commitment, ...options }: FindReferenceOptions = {},
): Promise<ConfirmedSignatureInfo> {
const signatures = await rpc
.getSignaturesForAddress(reference as Address, { ...options, ...(commitment ? { commitment } : {}) })
.send();
const length = signatures.length;
if (!length) throw new FindReferenceError('not found');
// If one or more transaction signatures are found under the limit, return the oldest one.
const oldest = signatures[length - 1];
if (length < (options?.limit || 1000)) return oldest;
try {
// In the unlikely event that signatures up to the limit are found, recursively find the oldest one.
return await findReference(rpc, reference, {
commitment,
...options,
before: oldest.signature,
});
} catch (error) {
// If the signatures found were exactly at the limit, there won't be more to find, so return the oldest one.
if (error instanceof FindReferenceError) return oldest;
throw error;
}
}