stint-signer
Version:
Short-lived, non-custodial session signer using passkeys for Cosmos SDK
160 lines (152 loc) • 5.68 kB
TypeScript
import { OfflineSigner, DirectSecp256k1Wallet, EncodeObject } from '@cosmjs/proto-signing';
import { SigningStargateClient, StdFee, DeliverTxResponse } from '@cosmjs/stargate';
import { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
import { Any } from 'cosmjs-types/google/protobuf/any';
/**
* Logger interface that can be implemented by users
*/
interface Logger {
debug(message: string, context?: Record<string, unknown>): void;
info(message: string, context?: Record<string, unknown>): void;
warn(message: string, context?: Record<string, unknown>): void;
error(message: string, error?: Error, context?: Record<string, unknown>): void;
}
/**
* Simple console-based logger implementation
* Users can provide their own logger that implements the Logger interface
*/
declare const consoleLogger: Logger;
interface SessionSignerConfig {
primaryClient: SigningStargateClient;
saltName?: string;
stintWindowHours?: number;
usePreviousWindow?: boolean;
logger?: Logger;
keyMode?: 'passkey' | 'random';
}
interface DelegationConfig {
sessionExpiration?: Date;
spendLimit?: {
denom: string;
amount: string;
};
gasLimit?: {
denom: string;
amount: string;
};
allowedRecipients?: string[];
}
interface AuthzGrantInfo {
authorization: any;
expiration?: Date;
}
interface FeegrantInfo {
allowance: any;
expiration?: Date;
}
interface ExecuteHelpers {
/**
* Send tokens using session signer with authz delegation
* Automatically wraps in MsgExec and handles feegrant
*/
send(params: {
toAddress: string;
amount: Coin[];
memo?: string;
fee?: StdFee | 'auto';
}): Promise<DeliverTxResponse>;
/**
* Execute custom messages with authz delegation
* For advanced use cases with pre-encoded Any messages
*/
custom(params: {
messages: Any[];
memo?: string;
fee?: StdFee | 'auto';
}): Promise<DeliverTxResponse>;
}
interface SessionSigner {
primarySigner: OfflineSigner;
sessionSigner: DirectSecp256k1Wallet;
client: SigningStargateClient;
primaryAddress(): string;
sessionAddress(): string;
hasAuthzGrant(messageType?: string): Promise<AuthzGrantInfo | null>;
hasFeegrant(): Promise<FeegrantInfo | null>;
generateDelegationMessages(config: DelegationConfig): EncodeObject[];
generateConditionalDelegationMessages(config: DelegationConfig): Promise<EncodeObject[]>;
revokeDelegationMessages(msgTypeUrl?: string): EncodeObject[];
execute: ExecuteHelpers;
}
/**
* Create a complete session signer in one step
* Combines passkey creation, signer derivation, and chain connection
* @param config - Configuration with primary client and optional salt name
* @returns Initialized SessionSigner ready for use
*/
declare function newSessionSigner(config: SessionSignerConfig): Promise<SessionSigner>;
/**
* Helper to wrap any message in MsgExec for authz delegation
*/
declare function wrapInMsgExec(granteeAddress: string, messages: Any[]): EncodeObject;
/**
* Create fee object with granter for feegrant usage
*/
declare function createFeeWithGranter(granterAddress: string, fee?: StdFee | 'auto'): StdFee | 'auto';
/**
* Send tokens using session signer with authz delegation
*/
declare function send(sessionSigner: SessionSigner, params: {
toAddress: string;
amount: Coin[];
memo?: string;
fee?: StdFee | 'auto';
}, logger: Logger): Promise<DeliverTxResponse>;
/**
* Execute custom messages with authz delegation
*/
declare function custom(sessionSigner: SessionSigner, params: {
messages: Any[];
memo?: string;
fee?: StdFee | 'auto';
}, logger: Logger): Promise<DeliverTxResponse>;
/**
* Get the current window boundaries for debugging and validation
* @param windowHours The window size in hours
* @returns Object with start and end timestamps of current window
*/
declare function getWindowBoundaries(windowHours?: number): {
start: Date;
end: Date;
windowNumber: number;
};
/**
* Custom error class for Stint-specific errors
*/
declare class StintError extends Error {
readonly code: string;
readonly details?: Record<string, unknown> | undefined;
constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
}
/**
* Standard error codes used throughout the library
*/
declare const ErrorCodes: {
readonly WEBAUTHN_NOT_SUPPORTED: "WEBAUTHN_NOT_SUPPORTED";
readonly PASSKEY_CREATION_FAILED: "PASSKEY_CREATION_FAILED";
readonly PASSKEY_AUTHENTICATION_FAILED: "PASSKEY_AUTHENTICATION_FAILED";
readonly PRF_NOT_SUPPORTED: "PRF_NOT_SUPPORTED";
readonly USER_CANCELLED: "USER_CANCELLED";
readonly CLIENT_INITIALIZATION_FAILED: "CLIENT_INITIALIZATION_FAILED";
readonly SIGNER_EXTRACTION_FAILED: "SIGNER_EXTRACTION_FAILED";
readonly RPC_URL_EXTRACTION_FAILED: "RPC_URL_EXTRACTION_FAILED";
readonly GRANT_CHECK_FAILED: "GRANT_CHECK_FAILED";
readonly INVALID_RESPONSE: "INVALID_RESPONSE";
readonly INVALID_ADDRESS: "INVALID_ADDRESS";
readonly INVALID_AMOUNT: "INVALID_AMOUNT";
readonly INVALID_DENOMINATION: "INVALID_DENOMINATION";
readonly INVALID_RPC_URL: "INVALID_RPC_URL";
readonly KEY_GENERATION_FAILED: "KEY_GENERATION_FAILED";
};
type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
export { type DelegationConfig, type ErrorCode, ErrorCodes, type ExecuteHelpers, type Logger, type SessionSigner, type SessionSignerConfig, StintError, consoleLogger, createFeeWithGranter, custom, getWindowBoundaries, newSessionSigner, send, wrapInMsgExec };