### Install @windoge98/pnp-okx Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/okx/README.md Install the OKX adapter using npm. ```bash npm install @windoge98/pnp-okx ``` -------------------------------- ### Install Phantom and Plug-n-Play Packages Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/phantom/README.md Install the necessary packages for the Phantom wallet adapter and the Plug-n-Play library using npm. ```bash npm install @windoge98/pnp-phantom @windoge98/plug-n-play ``` -------------------------------- ### Install Plug N Play Core and Wallet Packages Source: https://github.com/microdao-corporation/plug-n-play/blob/main/README.md Install the core package for IC wallets or individual packages for specific wallet integrations like MetaMask, Phantom, Solflare, WalletConnect, OKX, and Coinbase. ```bash # Core (IC wallets) npm install @windoge98/plug-n-play@beta # Individual wallet packages npm install @windoge98/pnp-metamask@beta # Ethereum - MetaMask npm install @windoge98/pnp-phantom@beta # Solana - Phantom npm install @windoge98/pnp-solflare@beta # Solana - Solflare npm install @windoge98/pnp-walletconnect@beta # Solana - WalletConnect npm install @windoge98/pnp-okx@beta # Solana - OKX npm install @windoge98/pnp-coinbase@beta # Solana - Coinbase Wallet ``` -------------------------------- ### Start Development Server (Main Package) Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Starts the Vite development server for the main Plug N Play package, enabling hot module replacement and rapid development of IC wallet functionality. ```bash npm run dev ``` -------------------------------- ### Declarative Adapter Registration with Extensions Source: https://github.com/microdao-corporation/plug-n-play/blob/main/README.md Register wallet adapter extensions declaratively for easier setup. This example shows registration for MetaMask, Phantom, and WalletConnect, including necessary provider and project IDs. ```typescript import { createPNP } from '@windoge98/plug-n-play'; import { MetaMaskExtension } from '@windoge98/pnp-metamask'; import { PhantomExtension } from '@windoge98/pnp-phantom'; import { WalletConnectExtension } from '@windoge98/pnp-walletconnect'; // Declarative configuration with extensions const pnp = createPNP({ extensions: [MetaMaskExtension, PhantomExtension, WalletConnectExtension], providers: { siws: 'YOUR_SIWS_CANISTER_ID', siwe: 'YOUR_SIWE_CANISTER_ID' }, adapters: { metamask: { enabled: true }, phantom: { enabled: true }, walletconnect: { enabled: true, projectId: 'YOUR_PROJECT_ID' } } }); // Or with builder pattern const pnp2 = ConfigBuilder.create() .withExtensions(MetaMaskExtension, PhantomExtension) .withProviders({ siws: 'YOUR_SIWS_CANISTER_ID', siwe: 'YOUR_SIWE_CANISTER_ID' }) .withAdapter('metamask', { enabled: true }) .build(); ``` -------------------------------- ### Quick Start: Initialize PNP and Connect Wallet Source: https://github.com/microdao-corporation/plug-n-play/blob/main/README.md Initialize the Plug N Play instance with specified network and adapters, then connect to a wallet like Internet Identity. ```typescript import { createPNP } from "@windoge98/plug-n-play"; // Create PNP instance const pnp = createPNP({ network: 'ic', // or 'local' for development adapters: { ii: { enabled: true }, plug: { enabled: true } } }); // Connect wallet const account = await pnp.connect('ii'); // Use with canister const actor = pnp.getActor(canisterId, idl); await actor.someMethod(); ``` -------------------------------- ### Install @windoge98/pnp-coinbase Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/coinbase/README.md Install the Coinbase Wallet adapter using npm. ```bash npm install @windoge98/pnp-coinbase ``` -------------------------------- ### Create PNP Instance with Minimal IC Setup Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Use `createPNP` for a basic Internet Computer-only setup. All built-in IC adapters are included by default. ```typescript import { createPNP } from "@windoge98/plug-n-play"; import { MetaMaskExtension } from "@windoge98/pnp-metamask"; import { PhantomExtension } from "@windoge98/pnp-phantom"; // Minimal IC-only setup const pnp = createPNP({ network: "ic", adapters: { ii: { enabled: true }, plug: { enabled: true }, nfid: { enabled: true }, oisy: { enabled: false }, }, }); ``` -------------------------------- ### Install Solana Support Package Source: https://github.com/microdao-corporation/plug-n-play/blob/main/demo/svelte-demo/README.md Install the separate package for Solana wallet support if needed. This is an optional dependency. ```bash npm install @windoge98/pnp-solana ``` -------------------------------- ### Start Development Server Source: https://github.com/microdao-corporation/plug-n-play/blob/main/demo/svelte-demo/README.md Run the development server to see changes live. Use 'npm run build' for production and 'npm run preview' to test the production build. ```bash # Start development server npm run dev # Build for production npm run build # Preview production build npm run preview ``` -------------------------------- ### Complete PNP Configuration Example Source: https://github.com/microdao-corporation/plug-n-play/blob/main/README.md Demonstrates comprehensive configuration using both object notation and the ConfigBuilder pattern, including network, ports, security, delegation, providers, extensions, and specific wallet adapters. ```typescript import { createPNP, ConfigBuilder } from "@windoge98/plug-n-play"; import { MetaMaskExtension } from "@windoge98/pnp-metamask"; import { PhantomExtension } from "@windoge98/pnp-phantom"; // Option 1: Object configuration with extensions const pnp = createPNP({ network: 'ic', ports: { replica: 8080, frontend: 3000 }, security: { fetchRootKey: false, verifyQuerySignatures: true }, delegation: { timeout: BigInt(24 * 60 * 60 * 1000 * 1000 * 1000), targets: ['canister1', 'canister2'] }, providers: { siws: 'SIWS_CANISTER_ID', siwe: 'SIWE_CANISTER_ID', frontend: 'FRONTEND_CANISTER_ID' }, extensions: [MetaMaskExtension, PhantomExtension], // Modular wallet support adapters: { ii: { enabled: true }, plug: { enabled: true }, metamask: { enabled: true, siweProviderCanisterId: 'YOUR_SIWE_CANISTER_ID' }, phantom: { enabled: true, siwsProviderCanisterId: 'YOUR_SIWS_CANISTER_ID' } } }); // Option 2: Builder pattern const pnp2 = createPNP( ConfigBuilder.create() .withEnvironment('local', { replica: 8080 }) .withSecurity(true, false) .withAdapter('ii', { enabled: true }) .build() ); ``` -------------------------------- ### Install Dependencies Source: https://github.com/microdao-corporation/plug-n-play/blob/main/demo/svelte-demo/README.md Install project dependencies using npm or pnpm. Ensure Node.js 18+ is installed. ```bash cd demo/svelte-demo npm install ``` ```bash cd demo/svelte-demo pnpm install ``` -------------------------------- ### Initialize PNP with OKX Adapter Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/okx/README.md Initialize the Plug-n-Play (PNP) instance with the OKX extension and configure provider canister IDs for SIWS/SIWE. This setup is necessary before connecting to the OKX wallet. ```typescript import { createPNP } from '@windoge98/plug-n-play'; import { OkxExtension } from '@windoge98/pnp-okx'; const pnp = createPNP({ extensions: [OkxExtension], providers: { siws: 'YOUR_SIWS_CANISTER_ID', // For Solana siwe: 'YOUR_SIWE_CANISTER_ID', // For Ethereum/EVM }, adapters: { okx: { enabled: true, siwsProviderCanisterId: 'YOUR_SIWS_CANISTER_ID', siweProviderCanisterId: 'YOUR_SIWE_CANISTER_ID', } } }); ``` -------------------------------- ### Develop Solana Package Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Starts the development server specifically for the Solana package. Allows for focused development and testing of SIWS adapters. ```bash cd packages/solana && npm run dev ``` -------------------------------- ### Create PNP Instance with Full Multi-Chain Setup Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Configure PNP for multi-chain support, including cross-chain adapters and specific security/delegation settings. Ensure to pass optional extensions like MetaMask and Phantom. ```typescript // Full multi-chain setup const pnpFull = createPNP({ network: "ic", security: { fetchRootKey: false, verifyQuerySignatures: true }, delegation: { timeout: BigInt(24 * 60 * 60 * 1_000_000_000), // 24 h in nanoseconds targets: ["ryjl3-tyaaa-aaaaa-aaaba-cai"], // restrict delegation scope }, providers: { siws: "guktk-fqaaa-aaaao-a4goa-cai", // SIWS canister for Solana wallets siwe: "r4zqx-aiaaa-aaaar-qbuia-cai", // SIWE canister for Ethereum wallets frontend: "bd3sg-teaaa-aaaaa-qaaba-cai", }, extensions: [MetaMaskExtension, PhantomExtension], adapters: { ii: { enabled: true }, metamask: { enabled: true }, phantom: { enabled: true }, }, }); console.log(pnpFull.getEnabledWallets().map(w => w.walletName)); ``` -------------------------------- ### Configure PNP with ConfigBuilder for Local Development Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Use `ConfigBuilder` for a fluent, programmatic approach to configuration, especially for local development environments. This example sets up local replica, delegation, and specific adapters. ```typescript import { createPNP, ConfigBuilder } from "@windoge98/plug-n-play"; import { PhantomExtension } from "@windoge98/pnp-phantom"; import { WalletConnectExtension } from "@windoge98/pnp-walletconnect"; const config = ConfigBuilder.create() .withEnvironment("local", { replica: 8080, frontend: 3000 }) // local dfx replica .withSecurity(true, false) // fetchRootKey=true, verifyQuerySignatures=false for local .withDelegation({ timeout: BigInt(7 * 24 * 60 * 60 * 1_000_000_000), // 7-day delegation targets: [], }) .withProviders({ siws: "aaaaa-aa", // local SIWS canister siwe: "aaaaa-ab", // local SIWE canister }) .withExtensions(PhantomExtension, WalletConnectExtension) .withIcAdapters({ plug: { enabled: true }, ii: { enabled: true }, stoic: false, // explicitly disable }) .withAdapter("phantom", { enabled: true }) .withAdapter("walletconnect", { enabled: true, projectId: "YOUR_WALLETCONNECT_PROJECT_ID", appName: "My dApp", appUrl: "https://example.com", }) .build(); const pnp = createPNP(config); ``` -------------------------------- ### Svelte integration example Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt A complete reactive pattern using Svelte stores, showing initialization, connect/disconnect, and canister interaction wired together. ```APIDOC ## Svelte integration example — full reactive store ### Description A complete reactive pattern using Svelte stores, showing initialization, connect/disconnect, and canister interaction wired together. ### Code Example ```typescript // stores/wallet.ts import { writable, derived, get } from "svelte/store"; import { createPNP } from "@windoge98/plug-n-play"; import { PhantomExtension } from "@windoge98/pnp-phantom"; import { MetaMaskExtension } from "@windoge98/pnp-metamask"; import { idlFactory, type _SERVICE } from "../declarations/my_canister"; const MY_CANISTER_ID = "ryjl3-tyaaa-aaaaa-aaaba-cai"; const pnp = createPNP({ network: "ic", providers: { siws: "guktk-fqaaa-aaaao-a4goa-cai", siwe: "r4zqx-aiaaa-aaaar-qbuia-cai" }, extensions: [PhantomExtension, MetaMaskExtension], adapters: { ii: { enabled: true }, phantom: { enabled: true }, metamask: { enabled: true } }, }); export const connected = writable(false); export const principal = writable(null); export const walletId = writable(null); export const wallets = derived(connected, () => pnp.getEnabledWallets()); export async function connect(id: string) { await pnp.openChannel(); // Safari compat const account = await pnp.connect(id); connected.set(true); principal.set(account.owner); walletId.set(id); localStorage.setItem("wallet", id); return account; } export async function disconnect() { await pnp.disconnect(); connected.set(false); principal.set(null); walletId.set(null); localStorage.removeItem("wallet"); } export function getCanisterActor() { if (!pnp.isAuthenticated()) throw new Error("Not connected"); return pnp.getActor<_SERVICE>({ canisterId: MY_CANISTER_ID, idl: idlFactory, }); } // Auto-reconnect non-cross-chain wallets const stored = localStorage.getItem("wallet"); if (stored && !["phantom", "metamask"].includes(stored)) { connect(stored).catch(() => localStorage.removeItem("wallet")); } ``` ``` -------------------------------- ### Get Enabled Wallets with pnp.getEnabledWallets() Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Retrieves a list of enabled wallet configurations. The result is cached and updated when configuration changes. ```typescript const wallets = pnp.getEnabledWallets(); // Render a wallet picker wallets.forEach(wallet => { console.log(`[${wallet.id}] ${wallet.walletName} — chain: ${wallet.chain}`); // → [ii] Internet Identity — chain: ICP // → [plug] Plug — chain: ICP // → [metamask] MetaMask — chain: ETH // → [phantom] Phantom — chain: SOL }); ``` -------------------------------- ### Connect to OKX Wallet and Get Network Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/okx/README.md Connect to the OKX wallet using the PNP instance and retrieve the current network information. This is a fundamental step after initializing the adapter. ```typescript // Connect to OKX wallet const account = await pnp.connect('okx'); // Get current network const adapter = pnp.getAdapter('okx'); const network = adapter.getCurrentNetwork(); console.log('Connected to:', network); ``` -------------------------------- ### Register Solana Adapters Source: https://github.com/microdao-corporation/plug-n-play/blob/main/demo/svelte-demo/README.md Register Solana adapters with the PNP library after installing the Solana support package. This makes Solana wallets available for connection. ```typescript import { SolanaAdapters } from '@windoge98/pnp-solana'; // Register Solana adapters Object.entries(SolanaAdapters).forEach(([id, config]) => { PNP.registerAdapter(id, config); }); ``` -------------------------------- ### Create Custom Adapter Extension Source: https://github.com/microdao-corporation/plug-n-play/blob/main/README.md Defines a factory function `createAdapterExtension` for creating custom wallet adapter extensions. This example shows the structure for defining a new wallet adapter with its ID, name, chain, adapter, and configuration. ```typescript import { createAdapterExtension } from '@windoge98/plug-n-play'; export const MyCustomExtension = createAdapterExtension({ myWallet: { id: 'myWallet', walletName: 'My Custom Wallet', chain: 'ICP', adapter: MyWalletAdapter, config: { /* adapter specific config */ } } }); ``` -------------------------------- ### Get Current Account Information Source: https://github.com/microdao-corporation/plug-n-play/blob/main/README.md Retrieves the currently connected account information. Returns the account details if connected, otherwise returns null. ```typescript pnp.getAccount(): Account | null ``` -------------------------------- ### Create a Signed Canister Actor using pnp.getActor() Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Returns a signed canister actor backed by the connected wallet's identity. Pass `anon: true` to get an unauthenticated actor usable before login. The actor is LRU-cached. ```typescript import { createPNP } from "@windoge98/plug-n-play"; import { idlFactory, type _SERVICE } from "./declarations/my_canister"; const pnp = createPNP({ network: "ic", adapters: { ii: { enabled: true } } }); await pnp.connect("ii"); // Authenticated actor — uses wallet identity for update calls const actor = pnp.getActor<_SERVICE>({ canisterId: "ryjl3-tyaaa-aaaaa-aaaba-cai", idl: idlFactory, }); const result = await actor.my_update_method({ value: 42n }); console.log("Result:", result); // Anonymous actor — no wallet required, for query-only canisters const anonActor = pnp.getActor<_SERVICE>({ canisterId: "ryjl3-tyaaa-aaaaa-aaaba-cai", idl: idlFactory, anon: true, }); const data = await anonActor.my_query_method(); console.log("Public data:", data); ``` -------------------------------- ### Initialize PNP with Coinbase Extension Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/coinbase/README.md Initialize Plug-n-Play with the Coinbase extension and configure adapter settings. Ensure 'siwsProviderCanisterId' and 'solanaNetwork' are correctly set for your environment. ```typescript import { createPNP } from '@windoge98/plug-n-play'; import { CoinbaseExtension } from '@windoge98/pnp-coinbase'; // Initialize PNP with Coinbase extension const pnp = createPNP({ extensions: [CoinbaseExtension], adapters: { coinbase: { enabled: true, siwsProviderCanisterId: 'your-siws-canister-id', solanaNetwork: WalletAdapterNetwork.Mainnet, // or Devnet } } }); ``` -------------------------------- ### Get IC Principal Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/coinbase/README.md Obtain the Internet Computer Principal from the connected wallet. ```typescript // Get IC Principal const principal = await pnp.getPrincipal(); ``` -------------------------------- ### Get Solana Address Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/coinbase/README.md Retrieve the Solana address associated with the connected Coinbase wallet. ```typescript // Get Solana address const solAddress = await pnp.getAddress('coinbase', 'sol'); ``` -------------------------------- ### PNP Initialization Configuration Source: https://github.com/microdao-corporation/plug-n-play/blob/main/demo/svelte-demo/README.md Configure the simplified PNP library for Internet Computer mainnet. Set fetchRootKey to true only for local development. ```typescript const pnp = createPNP({ dfxNetwork: 'ic', // IC mainnet fetchRootKey: false, // Only true for local dev verifyQuerySignatures: true, // Verify responses // Wallet configurations (all enabled by default) adapters: { ii: { enabled: true }, // Internet Identity plug: { enabled: true }, // Plug wallet oisy: { enabled: true }, // OISY (UnifiedSignerAdapter) nfid: { enabled: true }, // NFID (UnifiedSignerAdapter) stoic: { enabled: true } // Stoic (UnifiedSignerAdapter) } }); ``` -------------------------------- ### Configure PNP with Extensions and Adapters Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Shows how to configure the PNP instance using an object-based approach, specifying the network, extensions, providers, and adapters. This method allows for modular wallet support. ```typescript // Object-based configuration with extensions const pnp = createPNP({ network: 'ic', extensions: [SolanaExtension], providers: { siws: 'SIWS_CANISTER_ID', siwe: 'SIWE_CANISTER_ID' }, adapters: { ii: { enabled: true }, phantomSiws: { enabled: true } } }); ``` -------------------------------- ### Build All Packages Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Builds the main IC package along with the Solana and Ethereum modular packages. Ensures all parts of the library are compiled. ```bash npm run build:all ``` -------------------------------- ### Initialize PNP with Phantom Adapter Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/phantom/README.md Initialize the Plug-n-Play (PNP) instance, including the PhantomExtension and configuring SIWS provider and Phantom adapter details. Ensure 'YOUR_SIWS_CANISTER_ID' is replaced with your actual SIWS canister ID. ```typescript import { createPNP } from '@windoge98/plug-n-play'; import { PhantomExtension } from '@windoge98/pnp-phantom'; const pnp = createPNP({ network: 'ic', extensions: [PhantomExtension], providers: { siws: 'YOUR_SIWS_CANISTER_ID' }, adapters: { phantom: { enabled: true, siwsProviderCanisterId: 'YOUR_SIWS_CANISTER_ID', solanaNetwork: WalletAdapterNetwork.Mainnet } } }); ``` -------------------------------- ### Build Individual Ethereum Package Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Navigates to the Ethereum package directory and builds it independently. Useful for local development and testing of the Ethereum module. ```bash cd packages/ethereum && npm run build ``` -------------------------------- ### Build Core Package (IC Wallets) Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Builds the main IC wallet package with production optimizations and minification. Outputs ES module format. ```bash npm run build ``` -------------------------------- ### Connect to a Wallet using pnp.connect() Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Initiates the wallet-specific authentication flow. Returns a WalletAccount with IC owner principal and derived subaccount. Throws if connection fails or user cancels. Safari requires openChannel() before connect() to avoid popup blocking. ```typescript import { createPNP } from "@windoge98/plug-n-play"; const pnp = createPNP({ network: "ic", adapters: { ii: { enabled: true } } }); async function signIn() { try { // Safari requires openChannel() before connect() to avoid popup blocking await pnp.openChannel(); const account = await pnp.connect("ii"); console.log("Principal:", account.owner); // → "rdmx6-jaaaa-aaaaa-aaadq-cai" console.log("ICP Account ID:", account.subaccount); // → "a1b2c3..." (64-char hex) } catch (err) { if (err.message.includes("cancelled")) { console.warn("User cancelled sign-in"); } else { console.error("Connection failed:", err.message); } } } // Auto-reconnect on page reload using localStorage const stored = localStorage.getItem("pnpConnectedWallet"); if (stored) { pnp.connect(stored) .then(account => console.log("Restored session for", account.owner)) .catch(() => localStorage.removeItem("pnpConnectedWallet")); } ``` -------------------------------- ### Build Ethereum Package Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Builds only the Ethereum package, which includes SIWE adapters. Useful for focused development or deployment. ```bash npm run build:ethereum ``` -------------------------------- ### Preview Production Build Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Previews the production build of the main package locally. Useful for testing the final output before deployment. ```bash npm run preview ``` -------------------------------- ### Configure PNP using ConfigBuilder Pattern Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Illustrates an alternative configuration method for PNP using the ConfigBuilder pattern, providing a fluent API to set the environment, extensions, and adapters. This approach enhances readability and maintainability. ```typescript // Builder pattern alternative const pnp2 = createPNP( ConfigBuilder.create() .withEnvironment('local') .withExtensions(SolanaExtension) .withAdapter('ii', { enabled: true }) .build() ); ``` -------------------------------- ### Connect to Coinbase Wallet Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/coinbase/README.md Connect to the Coinbase wallet using the initialized PNP instance. ```typescript // Connect to Coinbase wallet await pnp.connect('coinbase'); ``` -------------------------------- ### createAdapterExtension(adapters) Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Creates a shareable adapter extension package. This function bundles one or more adapter configurations into a typed `AdapterExtension` object, which can then be passed to `createPNP({ extensions: [...] })`. This is the standard method used by external wallet packages to expose their adapters. ```APIDOC ## `createAdapterExtension(adapters)` — Create a shareable adapter extension package ### Description Packages one or more adapter configs into a typed `AdapterExtension` object that can be passed to `createPNP({ extensions: [...] })`. This is how the external wallet packages (e.g., `@windoge98/pnp-phantom`) expose their adapters. ### Usage ```typescript import { createAdapterExtension, BaseAdapter } from "@windoge98/plug-n-play"; class MyAdapter extends BaseAdapter { /* ... */ } export const MyWalletExtension = createAdapterExtension({ myWallet: { id: "myWallet", walletName: "My Custom Wallet", logo: "https://cdn.example.com/logo.svg", chain: "ICP" as const, enabled: true, adapter: MyAdapter, config: {}, }, }); // In consumer code: import { createPNP } from "@windoge98/plug-n-play"; import { MyWalletExtension } from "./my-wallet-extension"; const pnp = createPNP({ extensions: [MyWalletExtension], adapters: { myWallet: { enabled: true } }, }); ``` ``` -------------------------------- ### Build Individual Solana Package Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Navigates to the Solana package directory and builds it independently. Useful for local development and testing of the Solana module. ```bash cd packages/solana && npm run build ``` -------------------------------- ### Create Shareable Adapter Extension with createAdapterExtension() Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Packages adapter configurations into a typed `AdapterExtension` object for use with `createPNP({ extensions: [...] })`. This is the standard way external wallet packages expose their adapters. ```typescript import { createAdapterExtension, BaseAdapter } from "@windoge98/plug-n-play"; class MyAdapter extends BaseAdapter { /* ... */ } export const MyWalletExtension = createAdapterExtension({ myWallet: { id: "myWallet", walletName: "My Custom Wallet", logo: "https://cdn.example.com/logo.svg", chain: "ICP" as const, enabled: true, adapter: MyAdapter, config: {}, }, }); // In consumer code: import { createPNP } from "@windoge98/plug-n-play"; import { MyWalletExtension } from "./my-wallet-extension"; const pnp = createPNP({ extensions: [MyWalletExtension], adapters: { myWallet: { enabled: true } }, }); ``` -------------------------------- ### Build Solana Package Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Builds only the Solana package, which includes SIWS adapters. Useful for focused development or deployment. ```bash npm run build:solana ``` -------------------------------- ### createPNP(config) Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Factory function to create a Plug N Play instance. It accepts configuration arguments to set up network, security, delegation, providers, and extensions. ```APIDOC ## createPNP(config) — Factory function to create a PNP instance ### Description The primary entry point. Accepts either a plain `CreatePnpArgs` object or the output of `ConfigBuilder.build()`. It merges defaults (IC mainnet, 24 h delegation, no root-key fetch) with the provided configuration and returns a ready-to-use `PNP` instance. All built-in IC adapters are included automatically; cross-chain adapters must be passed via `extensions`. ### Parameters * **config** (`CreatePnpArgs` | `GlobalPnpConfig`) - Required - The configuration object for the PNP instance. ### Request Example ```typescript import { createPNP } from "@windoge98/plug-n-play"; import { MetaMaskExtension } from "@windoge98/pnp-metamask"; import { PhantomExtension } from "@windoge98/pnp-phantom"; // Minimal IC-only setup const pnp = createPNP({ network: "ic", adapters: { ii: { enabled: true }, plug: { enabled: true }, nfid: { enabled: true }, oisy: { enabled: false }, }, }); // Full multi-chain setup const pnpFull = createPNP({ network: "ic", security: { fetchRootKey: false, verifyQuerySignatures: true }, delegation: { timeout: BigInt(24 * 60 * 60 * 1_000_000_000), // 24 h in nanoseconds targets: ["ryjl3-tyaaa-aaaaa-aaaba-cai"], // restrict delegation scope }, providers: { siws: "guktk-fqaaa-aaaao-a4goa-cai", // SIWS canister for Solana wallets siwe: "r4zqx-aiaaa-aaaar-qbuia-cai", // SIWE canister for Ethereum wallets frontend: "bd3sg-teaaa-aaaaa-qaaba-cai", }, extensions: [MetaMaskExtension, PhantomExtension], adapters: { ii: { enabled: true }, metamask: { enabled: true }, phantom: { enabled: true }, }, }); console.log(pnpFull.getEnabledWallets().map(w => w.walletName)); // → ["Internet Identity", "MetaMask", "Phantom", ...] ``` ``` -------------------------------- ### Prepare Adapter for Safari Popup Wallets Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Call `openChannel()` before user actions to initialize the AuthClient early. This minimizes async operations before popup creation, preventing Safari's popup blocker. ```javascript button.onclick = async () => { await pnp.openChannel(); // Initialize AuthClient early await pnp.connect('ii'); // Popup opens without blocking }; ``` -------------------------------- ### Connection Methods Source: https://github.com/microdao-corporation/plug-n-play/blob/main/README.md Methods for managing the connection to the Plug-n-Play service, including connecting, disconnecting, and checking authentication status. ```APIDOC ## connect ### Description Establishes a connection to the Plug-n-Play service using a provided wallet ID. ### Method `connect(walletId: string): Promise` ### Parameters #### Path Parameters - **walletId** (string) - Required - The ID of the wallet to connect with. ### Response #### Success Response (200) - **Account** - Information about the connected account. ## disconnect ### Description Disconnects the current session from the Plug-n-Play service. ### Method `disconnect(): Promise` ## isAuthenticated ### Description Checks if the user is currently authenticated with the Plug-n-Play service. ### Method `isAuthenticated(): boolean` ``` -------------------------------- ### Switch Network with OKX Adapter Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/okx/README.md Programmatically switch the network for EVM-compatible chains using the OKX adapter. Ensure the adapter is initialized and the target network is supported. ```typescript // Switch network (EVM chains only) await adapter.switchNetwork('polygon'); ``` -------------------------------- ### Pre-initialize Auth Channel for Safari with pnp.openChannel() Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Opens an authentication channel, which must be called synchronously within an event handler before `connect()` to avoid Safari's popup blocker. Useful for initiating authentication flows. ```typescript const btn = document.getElementById("connect-btn")!; btn.addEventListener("click", async () => { await pnp.openChannel(); // must run synchronously before any await const account = await pnp.connect("ii"); console.log("Connected:", account.owner); }); ``` -------------------------------- ### Import and Use PNP Packages in Code Source: https://github.com/microdao-corporation/plug-n-play/blob/main/link-usage-example.md After linking, import and use the PNP packages and their adapters in your JavaScript code. Register adapters before creating the PNP instance. ```javascript // Main package import { createPNP, PNP } from '@windoge98/plug-n-play'; // Solana adapters import { SolanaAdapters } from '@windoge98/pnp-solana'; // Ethereum adapters import { EthereumAdapters } from '@windoge98/pnp-ethereum'; // Register adapters Object.entries(SolanaAdapters).forEach(([id, config]) => { PNP.registerAdapter(id, { ...config, enabled: true }); }); Object.entries(EthereumAdapters).forEach(([id, config]) => { PNP.registerAdapter(id, { ...config, enabled: true }); }); // Create PNP instance const pnp = createPNP({ dfxNetwork: 'ic', siwsProviderCanisterId: 'xkbqi-2qaaa-aaaah-qbpqq-cai', siweProviderCanisterId: 'r4zqx-aiaaa-aaaar-qbuia-cai', adapters: { // IC wallets ii: { enabled: true }, plug: { enabled: true }, // Solana wallets phantomSiws: { enabled: true }, solflareSiws: { enabled: true }, // Ethereum wallets metamaskSiwe: { enabled: true }, walletConnectSiwe: { enabled: true } } }); ``` -------------------------------- ### Implement Custom Wallet Adapter with BaseAdapter Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Extend `BaseAdapter` to create a custom wallet adapter. This requires implementing methods for connection, disconnection, checking connection status, retrieving the principal, and creating actors internally. It provides built-in caching and error handling. ```typescript import { BaseAdapter, type AdapterConstructorArgs, } from "@windoge98/plug-n-play"; import { type ActorSubclass } from "@dfinity/agent"; import { type Wallet } from "@windoge98/plug-n-play"; interface MyConfig { hostUrl: string; fetchRootKey: boolean; } export class MyWalletAdapter extends BaseAdapter { private identity: any = null; async connect(): Promise { this.setState("CONNECTING" as any); try { // ... wallet-specific auth flow ... this.identity = await myWalletSDK.login(); const principal = this.identity.getPrincipal().toText(); this.setState("CONNECTED" as any); return { owner: principal, subaccount: (await import("@windoge98/plug-n-play")).deriveAccountId(principal), }; } catch (err) { this.handleError("connect failed", err); throw err; } } async isConnected(): Promise { return this.identity !== null; } async getPrincipal(): Promise { if (!this.identity) throw new Error("Not connected"); return this.identity.getPrincipal().toText(); } protected createActorInternal( canisterId: string, idl: any, ): ActorSubclass { const agent = this.buildHttpAgentSync({ identity: this.identity }); return this.createActorWithAgent(agent, canisterId, idl); } } ``` -------------------------------- ### BaseAdapter Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Abstract base class for custom wallet adapters. Extend this to create a fully custom wallet adapter with built-in actor caching, HTTP agent construction, standardized error handling, and a lifecycle based on `Adapter.Status`. ```APIDOC ## `BaseAdapter` — Abstract base class for custom adapters ### Description The root of the adapter hierarchy. Extend this to create a fully custom wallet adapter with built-in actor caching, HTTP agent construction, standardized error handling, and a lifecycle based on `Adapter.Status`. Must implement `connect()`, `disconnect()` (via `disconnectInternal()`), `isConnected()`, `getPrincipal()`, and `createActorInternal()`. ### Methods to Implement - `connect()`: Initiates the connection process. - `disconnect()`: Disconnects the wallet (calls `disconnectInternal()` internally). - `isConnected()`: Checks if the wallet is currently connected. - `getPrincipal()`: Retrieves the principal of the connected user. - `createActorInternal()`: Creates an actor instance for a given canister. ### Example Usage (Extending BaseAdapter) ```typescript import { BaseAdapter, type AdapterConstructorArgs, } from "@windoge98/plug-n-play"; import { type ActorSubclass } from "@dfinity/agent"; import { type Wallet } from "@windoge98/plug-n-play"; interface MyConfig { hostUrl: string; fetchRootKey: boolean; } export class MyWalletAdapter extends BaseAdapter { private identity: any = null; async connect(): Promise { this.setState("CONNECTING" as any); try { // ... wallet-specific auth flow ... this.identity = await myWalletSDK.login(); const principal = this.identity.getPrincipal().toText(); this.setState("CONNECTED" as any); return { owner: principal, subaccount: (await import("@windoge98/plug-n-play")).deriveAccountId(principal), }; } catch (err) { this.handleError("connect failed", err); throw err; } } async isConnected(): Promise { return this.identity !== null; } async getPrincipal(): Promise { if (!this.identity) throw new Error("Not connected"); return this.identity.getPrincipal().toText(); } protected createActorInternal( canisterId: string, idl: any, ): ActorSubclass { const agent = this.buildHttpAgentSync({ identity: this.identity }); return this.createActorWithAgent(agent, canisterId, idl); } } ``` ``` -------------------------------- ### pnp.openChannel() Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Pre-initializes the authentication channel, specifically for Safari to bypass popup blockers. This function must be called synchronously within the same event handler that triggers the connect popup, before calling `connect()`. ```APIDOC ## `pnp.openChannel()` — Pre-initialize auth channel (Safari) ### Description Safari's popup blocker requires the AuthClient to be instantiated within the same synchronous event handler that triggers the connect popup. Call `openChannel()` during the click handler setup (or at app start) before calling `connect()` to prevent the popup from being blocked. ### Usage ```typescript const btn = document.getElementById("connect-btn")!; btn.addEventListener("click", async () => { await pnp.openChannel(); // must run synchronously before any await const account = await pnp.connect("ii"); console.log("Connected:", account.owner); }); ``` ``` -------------------------------- ### Connect to Phantom Wallet Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/phantom/README.md Connect to the Phantom wallet using the initialized PNP instance to authenticate the user. This action initiates the SIWS flow. ```typescript // Connect to Phantom const account = await pnp.connect('phantom'); ``` -------------------------------- ### Register Solana Extension Automatically Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Demonstrates automatic registration of Solana adapters by importing and including the SolanaExtension in the createPNP configuration. This avoids manual loop-based registration. ```typescript // Instead of manual loops import { SolanaExtension } from '@windoge98/pnp-solana'; const pnp = createPNP({ extensions: [SolanaExtension], adapters: { phantomSiws: { enabled: true } } }); ``` -------------------------------- ### Link PNP Packages Locally Source: https://github.com/microdao-corporation/plug-n-play/blob/main/link-usage-example.md In your target project directory, use `npm link` to connect the globally symlinked PNP packages. Link the main package and any specific adapters needed. ```bash # Link the main package npm link @windoge98/plug-n-play # Link Solana package (if needed) npm link @windoge98/pnp-solana # Link Ethereum package (if needed) npm link @windoge98/pnp-ethereum ``` -------------------------------- ### Development Workflow with Linked Packages Source: https://github.com/microdao-corporation/plug-n-play/blob/main/link-usage-example.md After linking, changes made in the w98-pnp project and rebuilt with `npm run build:all` are immediately reflected in the linked project without needing to relink. ```bash 1. Make changes in w98-pnp 2. Run `npm run build:all` to rebuild all packages 3. Changes will be immediately available in your linked project (no need to re-link) ``` -------------------------------- ### Connect and Disconnect from Wallet Source: https://github.com/microdao-corporation/plug-n-play/blob/main/README.md Establishes a connection to a wallet using the provided wallet ID and disconnects from the current session. Ensure a wallet is enabled before connecting. ```typescript await pnp.connect(walletId: string): Promise await pnp.disconnect(): Promise ``` -------------------------------- ### Run Vitest UI Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Launches the Vitest UI for interactive test running, debugging, and visualization of test results. ```bash npm run test:ui ``` -------------------------------- ### pnp.getEnabledWallets() Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Retrieves a list of enabled wallets. It returns an array of `AdapterConfig` objects for wallets where `enabled` is not set to `false`. The results are cached and updated when configuration changes. ```APIDOC ## `pnp.getEnabledWallets()` — List available wallets ### Description Returns an array of `AdapterConfig` objects for all wallets where `enabled !== false`. The result is cached internally and invalidated whenever the configuration changes. ### Usage ```typescript const wallets = pnp.getEnabledWallets(); // Render a wallet picker wallets.forEach(wallet => { console.log(`[${wallet.id}] ${wallet.walletName} — chain: ${wallet.chain}`); }); ``` ``` -------------------------------- ### OKX Adapter Configuration Options Source: https://github.com/microdao-corporation/plug-n-play/blob/main/packages/okx/README.md Configure the OKX adapter with various options, including enabling the adapter, specifying supported networks, Solana network details, and canister IDs for SIWS/SIWE providers. ```typescript { okx: { enabled: true, supportedNetworks: ['ethereum', 'solana'], // Optional: limit networks solanaNetwork: WalletAdapterNetwork.Mainnet, siwsProviderCanisterId: 'canister-id', // For Solana siweProviderCanisterId: 'canister-id', // For Ethereum/EVM } } ``` -------------------------------- ### Link PNP Packages Globally Source: https://github.com/microdao-corporation/plug-n-play/blob/main/link-usage-example.md Run these commands in the w98-pnp directory to create global symlinks for the PNP packages. This is a prerequisite for linking them into other projects. ```bash npm run link:all # or ./link-all.sh ``` -------------------------------- ### Retrieve Enabled Wallets Source: https://github.com/microdao-corporation/plug-n-play/blob/main/README.md Fetches a list of all currently enabled wallet adapters. This is useful for presenting wallet options to the user. ```typescript pnp.getEnabledWallets(): AdapterConfig[] ``` -------------------------------- ### Wallet Information Methods Source: https://github.com/microdao-corporation/plug-n-play/blob/main/README.md Methods for retrieving information about enabled wallets and the current account. ```APIDOC ## getEnabledWallets ### Description Retrieves a list of all enabled wallet configurations. ### Method `getEnabledWallets(): AdapterConfig[]` ### Response #### Success Response (200) - **AdapterConfig[]** - An array of wallet adapter configurations. ## getAccount ### Description Retrieves the currently connected account information. ### Method `getAccount(): Account | null` ### Response #### Success Response (200) - **Account | null** - The connected account information, or null if not connected. ``` -------------------------------- ### ConfigBuilder Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt A fluent builder class for creating a `GlobalPnpConfig` object, useful for programmatic configuration assembly. ```APIDOC ## ConfigBuilder — Fluent configuration builder ### Description A chainable builder that produces a `GlobalPnpConfig` object. Useful when configuration logic is spread across multiple steps or needs to be assembled programmatically. Every method returns `this` for chaining; call `.build()` at the end to finalize. ### Methods * **create()**: Initializes a new `ConfigBuilder` instance. * **withEnvironment(envName, options)**: Sets environment-specific configurations (e.g., local replica port). * **withSecurity(fetchRootKey, verifyQuerySignatures)**: Configures security settings. * **withDelegation(options)**: Configures delegation settings, including timeout and targets. * **withProviders(providers)**: Sets the canisters for SIWS, SIWE, and frontend. * **withExtensions(...extensions)**: Adds wallet extensions to the configuration. * **withIcAdapters(adapters)**: Configures built-in Internet Computer adapters. * **withAdapter(adapterName, options)**: Configures a specific adapter with its options. * **build()**: Finalizes the configuration and returns a `GlobalPnpConfig` object. ### Request Example ```typescript import { createPNP, ConfigBuilder } from "@windoge98/plug-n-play"; import { PhantomExtension } from "@windoge98/pnp-phantom"; import { WalletConnectExtension } from "@windoge98/pnp-walletconnect"; const config = ConfigBuilder.create() .withEnvironment("local", { replica: 8080, frontend: 3000 }) // local dfx replica .withSecurity(true, false) // fetchRootKey=true, verifyQuerySignatures=false for local .withDelegation({ timeout: BigInt(7 * 24 * 60 * 60 * 1_000_000_000), // 7-day delegation targets: [], }) .withProviders({ siws: "aaaaa-aa", // local SIWS canister siwe: "aaaaa-ab", // local SIWE canister }) .withExtensions(PhantomExtension, WalletConnectExtension) .withIcAdapters({ plug: { enabled: true }, ii: { enabled: true }, stoic: false, // explicitly disable }) .withAdapter("phantom", { enabled: true }) .withAdapter("walletconnect", { enabled: true, projectId: "YOUR_WALLETCONNECT_PROJECT_ID", appName: "My dApp", appUrl: "https://example.com", }) .build(); const pnp = createPNP(config); ``` ``` -------------------------------- ### Register Custom Adapter Globally with PNP.registerAdapter() Source: https://context7.com/microdao-corporation/plug-n-play/llms.txt Statically registers a custom wallet adapter for use with all PNP instances. Must be called before creating any PNP instances. Remember to unregister when no longer needed. ```typescript import { PNP, createPNP } from "@windoge98/plug-n-play"; import { MyCustomWalletAdapter } from "./my-wallet-adapter"; PNP.registerAdapter("myWallet", { id: "myWallet", walletName: "My Wallet", logo: "https://example.com/logo.png", chain: "ICP", enabled: true, adapter: MyCustomWalletAdapter, config: { someOption: true }, }); const pnp = createPNP({ adapters: { myWallet: { enabled: true } } }); const wallets = pnp.getEnabledWallets(); console.log(wallets.find(w => w.id === "myWallet")?.walletName); // → "My Wallet" // Unregister when no longer needed PNP.unregisterAdapter("myWallet"); ``` -------------------------------- ### Troubleshooting Linked Packages Source: https://github.com/microdao-corporation/plug-n-play/blob/main/link-usage-example.md If you encounter errors related to missing packages after linking, ensure global linking was successful and try relinking. ```bash 1. Make sure you ran `npm run link:all` in the w98-pnp directory first 2. Check that the packages are linked globally with: `npm ls -g --depth=0 --link=true` 3. Try unlinking and relinking again ``` -------------------------------- ### Run All Tests Source: https://github.com/microdao-corporation/plug-n-play/blob/main/CLAUDE.md Executes all tests within the project using Vitest, typically in watch mode for continuous feedback during development. ```bash npm test ```