Based on the work of the Wallet Provider, this project adds support for various extensions that allow for cryptographic operations in specific contexts.
Extensions are modular components that enhance the capabilities of a wallet or provider. They allow for the addition of specialized features—such as secret management, logging, or custom signing—without bloating the core provider implementation.
An extension typically consists of:
- State: Data managed by the extension (e.g., a list of stored secrets).
- API: A set of methods to interact with the extension and its state.
The following extension packages are available in this workspace:
- Account Store: Reactive store for managing accounts.
- Accounts Keystore Bridge: Reference extension for bridging between the account store and keystore.
- Keystore Core: Core types and interfaces for secret management.
- React Native Keystore: Secure implementation for React Native using Keychain/MMKV.
- Integration Guide: Detailed guide on how to adopt the keystore in React Native.
- Log Store: Generalized logging extension for tracking wallet activity.
To create a new extension, you define an interface that combines your custom state and your API.
Imagine you want an extension that logs all wallet activities.
export interface LoggerState {
logs: string[];
}
export interface LoggerApi {
log: (message: string) => void;
clear: () => void;
}
export interface LoggerExtension extends LoggerState {
logger: LoggerApi;
}import { Store } from "@tanstack/store";
import type { Provider, ExtensionOptions } from "@algorandfoundation/wallet-provider";
const store = new Store<LoggerState>({ logs: [] });
export const loggerExtension: (
provider: Provider,
options: ExtensionOptions,
) => LoggerExtension = () => ({
get logs() {
return store.state.logs;
},
logger: {
log: (message: string) => {
store.setState((state) => ({
logs: [...state.logs, `${new Date().toISOString()}: ${message}`],
}));
},
clear: () => {
store.setState(() => ({ logs: [] }));
},
},
});
export default loggerExtension;Extensions are typically used by extending the base Provider class. This "concrete provider" pattern provides full type safety for both the core provider and all its extensions.
import { Provider } from "@algorandfoundation/wallet-provider";
import { WithKeyStore } from "@algorandfoundation/react-native-keystore";
import { WithLogStore } from "@algorandfoundation/log-store";
import { keyStore } from "./stores/keystore";
import { logStore } from "./stores/logstore";
// 1. Define your application's provider with extensions
export class MyProvider extends Provider<typeof MyProvider.EXTENSIONS> {
static EXTENSIONS = [WithLogStore, WithKeyStore] as const;
// Add properties for type-safe access to extension state/APIs
logs!: string[];
keys!: any[];
status!: string;
}
// 2. Initialize the provider with required options
const provider = new MyProvider(
{
id: "my-app",
name: "My Application",
},
{
logs: { store: logStore },
keystore: {
extension: { store: keyStore },
},
},
);
// 3. Access extension APIs directly on the provider
await provider.keystore.generate({ type: "hd-seed", algorithm: "raw" });
provider.log("Generated a new seed");
console.log(provider.keys); // Reactive list of keysWe would like to acknowledge the following individuals and entities for their contributions and inspiration to this project and the broader Algorand ecosystem:
- Architectural Vision: Algorand Foundation and Bruno Martins (@bmartins) for his role as an Architect.
- use-wallet: TxnLab and Doug Richar (@drichar), along with Gabriel Kuettel (@gabrielkuettel) (currently at Algorand Foundation), for their role in building the
use-wallethook. - Ecosystem Support: The Engineering Teams at Algorand Foundation ranging from AlgoKit, Engineering, and Devrel for their role in providing ecosystem libraries and support.
- Wallets:
- Pera and Will Beaumount (@mjbeau) for their role in the ecosystem as a wallet and the large refactor to React Native.
- Akita for their role in ARC58 adoption. With special thanks to Algorand Foundation engineering to Kyle(@kylebee) and Joe Polny(@joe-p) for their contributions to the ARC58 plugin standards.
- Lute and Andrew Funk (@acfunk) for their contributions to web wallets, readily adopting the latest features.
- Kibis-is and Kieran Roneill (@kieranroneill) for their work as an extension-based wallet and contributions to ARC standards such as ARC27.
- Defly and Kevin Wellenzohn (@k13n) for pioneering wallet features and deep engagement with the Algorand ecosystem and ARC standards.