import { type ImportSharedPermitOptions, PermitUtils, type CreateSelfPermitOptions, type CreateSharingPermitOptions, type Permit, permitStore, type SerializedPermit, type SelfPermit, type RecipientPermit, type SharingPermit, type PermitHashFields, } from '@/permits'; import { type PublicClient, type WalletClient } from 'viem'; // HELPERS // Helper function to store permit as active permit const storeActivePermit = async (permit: Permit, publicClient: any, walletClient: any) => { const chainId = await publicClient.getChainId(); const account = walletClient.account!.address; permitStore.setPermit(chainId, account, permit); permitStore.setActivePermitHash(chainId, account, permit.hash); }; // Generic function to handle permit creation with error handling const createPermitWithSign = async ( options: T, publicClient: PublicClient, walletClient: WalletClient, permitMethod: (options: T, publicClient: PublicClient, walletClient: WalletClient) => Promise ): Promise => { const permit = await permitMethod(options, publicClient, walletClient); await storeActivePermit(permit, publicClient, walletClient); return permit; }; // CREATE /** * Create a permit usable by the connected user * Stores the permit and selects it as the active permit * @param options - The options for creating a self permit * @returns The created permit or error */ const createSelf = async ( options: CreateSelfPermitOptions, publicClient: PublicClient, walletClient: WalletClient ): Promise => { return createPermitWithSign(options, publicClient, walletClient, PermitUtils.createSelfAndSign); }; const createSharing = async ( options: CreateSharingPermitOptions, publicClient: PublicClient, walletClient: WalletClient ): Promise => { return createPermitWithSign(options, publicClient, walletClient, PermitUtils.createSharingAndSign); }; const importShared = async ( options: ImportSharedPermitOptions | string, publicClient: PublicClient, walletClient: WalletClient ): Promise => { return createPermitWithSign(options, publicClient, walletClient, PermitUtils.importSharedAndSign); }; // PERMIT UTILS const getHash = (permit: PermitHashFields) => { return PermitUtils.getHash(permit); }; const exportShared = (permit: Permit) => { return PermitUtils.export(permit); }; const serialize = (permit: Permit) => { return PermitUtils.serialize(permit); }; const deserialize = (serialized: SerializedPermit) => { return PermitUtils.deserialize(serialized); }; // GET const getPermit = (chainId: number, account: string, hash: string): Permit | undefined => { return permitStore.getPermit(chainId, account, hash); }; const getPermits = (chainId: number, account: string): Record => { return permitStore.getPermits(chainId, account); }; const getActivePermit = (chainId: number, account: string): Permit | undefined => { return permitStore.getActivePermit(chainId, account); }; const getActivePermitHash = (chainId: number, account: string): string | undefined => { return permitStore.getActivePermitHash(chainId, account); }; const selectActivePermit = (chainId: number, account: string, hash: string): void => { permitStore.setActivePermitHash(chainId, account, hash); }; // GET OR CREATE /** * Get the active self permit or create a new one if it doesn't exist * @param publicClient - The public client * @param walletClient - The wallet client * @param chainId - Optional chain ID (will use publicClient if not provided) * @param account - Optional account (will use walletClient if not provided) * @param options - The options for creating a self permit * @returns The existing or newly created permit */ const getOrCreateSelfPermit = async ( publicClient: PublicClient, walletClient: WalletClient, chainId?: number, account?: string, options?: CreateSelfPermitOptions ): Promise => { const _chainId = chainId ?? (await publicClient.getChainId()); const _account = account ?? walletClient.account!.address; // Try to get active permit first const activePermit = await getActivePermit(_chainId, _account); if (activePermit && activePermit.type === 'self') { return activePermit; } // No active permit or wrong type, create new one return createSelf(options ?? { issuer: _account, name: 'Autogenerated Self Permit' }, publicClient, walletClient); }; /** * Get the active sharing permit or create a new one if it doesn't exist * @param publicClient - The public client * @param walletClient - The wallet client * @param options - The options for creating a sharing permit (required) * @param chainId - Optional chain ID (will use publicClient if not provided) * @param account - Optional account (will use walletClient if not provided) * @returns The existing or newly created permit */ const getOrCreateSharingPermit = async ( publicClient: PublicClient, walletClient: WalletClient, options: CreateSharingPermitOptions, chainId?: number, account?: string ): Promise => { const _chainId = chainId ?? (await publicClient.getChainId()); const _account = account ?? walletClient.account!.address; // Try to get active permit first const activePermit = await getActivePermit(_chainId, _account); if (activePermit && activePermit.type === 'sharing') { return activePermit; } return createSharing(options, publicClient, walletClient); }; // REMOVE const removePermit = async (chainId: number, account: string, hash: string): Promise => permitStore.removePermit(chainId, account, hash); const removeActivePermit = async (chainId: number, account: string): Promise => permitStore.removeActivePermitHash(chainId, account); // EXPORT export const permits = { getSnapshot: permitStore.store.getState, subscribe: permitStore.store.subscribe, createSelf, createSharing, importShared, getOrCreateSelfPermit, getOrCreateSharingPermit, getHash, export: exportShared, serialize, deserialize, getPermit, getPermits, getActivePermit, getActivePermitHash, removePermit, selectActivePermit, removeActivePermit, };