import type { ChainInfo } from '@particle-network/chains'; import { AAFeeMode, getChainInfo, isHexString, type Env, } from '@particle-network/rn-base'; import { NativeModules, Platform } from 'react-native'; import { AccountInfo, CommonError, CommonResp, DappMetaData, LoginResp, ParticleConnectConfig, RpcUrl, WalletType, } from './Models'; import { ConnectKitConfig } from './Models/ConnectKitConfig'; const LINKING_ERROR = `The package '@particle-network/rn-connect' doesn't seem to be linked. Make sure: \n\n` + Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n'; const ParticleConnectPlugin = NativeModules.ParticleConnectPlugin ? NativeModules.ParticleConnectPlugin : new Proxy( {}, { get() { throw new Error(LINKING_ERROR); }, } ); export const ParticleConnectEvent = NativeModules.ParticleConnectEvent ? NativeModules.ParticleConnectEvent : new Proxy( {}, { get() { // throw new Error(LINKING_ERROR); }, } ); /** * Init Particle Connect Service * @param chainInfo ChainInfo * @param env Env * @param metadata Dapp meta data * @param rpcUrl Custom RpcUrl */ export function init( chainInfo: ChainInfo, env: Env, metadata: DappMetaData, rpcUrl?: RpcUrl | null ) { const obj = { chain_name: chainInfo.name, chain_id: chainInfo.id, env: env, metadata: metadata, rpc_url: rpcUrl, }; const json = JSON.stringify(obj); ParticleConnectPlugin.initialize(json); } /** * Set WalletConnect ProjectId */ export function setWalletConnectProjectId( walletConnectProjectId: string, ) { ParticleConnectPlugin.setWalletConnectProjectId(walletConnectProjectId); } /** * Set the required chains for wallet connect v2. If not set, the current chain connection will be used. * @param chainInfos Chain info list */ export function setWalletConnectV2SupportChainInfos(chainInfos: ChainInfo[]) { const chainInfoObjects = chainInfos.map((info) => ({ chain_name: info.name, chain_id_name: info.network, chain_id: info.id, })); const json = JSON.stringify(chainInfoObjects); ParticleConnectPlugin.setWalletConnectV2SupportChainInfos(json); } /** * Get accounts * @param walletType Wallet type * @returns Account list */ export async function getAccounts(walletType: WalletType): Promise { return new Promise((resolve, reject) => { ParticleConnectPlugin.getAccounts(walletType, (result: string) => { const rawData = JSON.parse(result); if (rawData.status) { const accountInfoArray: AccountInfo[] = rawData.data.map((item: any) => { return { icons: item.icons, name: item.name, publicAddress: item.publicAddress, url: item.url, description: item.description, chainId: item.chainId, mnemonic: item.mnemonic, walletType: walletType }; }); resolve(accountInfoArray); } else { reject(rawData.data as CommonError); } }); }); } /** * Connect wallet * @param walletType Wallet type * @param config Optional, works when connect with partile * @returns Result, account or error */ export async function connect( walletType: WalletType, config?: ParticleConnectConfig ): Promise { const obj = { walletType: walletType, particleConnectConfig: config } const configJson = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.connect(configJson, (result: string) => { const rawData = JSON.parse(result); if (rawData.status) { let accountInfo: AccountInfo = { icons: rawData.data.icons, name: rawData.data.name, publicAddress: rawData.data.publicAddress, url: rawData.data.url, description: rawData.data.description, chainId: rawData.data.chainId, mnemonic: rawData.data.mnemonic, walletType: rawData.data.walletType }; if (Platform.OS === 'ios') { const value = Object.keys(rawData.data.walletType)[0]; accountInfo.walletType = getWalletType(value!); resolve(accountInfo); } else { resolve(accountInfo); } } else { reject(rawData.data as CommonError); } }); }); } /** * connectWithConnectKitConfig is one click login function, which can present a customizable login UI * @param config can be derived from ConnectKitConfig * @returns */ export async function connectWithConnectKitConfig(config: ConnectKitConfig): Promise { const configJson = JSON.stringify(config); return new Promise((resolve, reject) => { ParticleConnectPlugin.connectWithConnectKitConfig(configJson, (result: string) => { const rawData = JSON.parse(result); if (rawData.status) { let accountInfo: AccountInfo = { icons: rawData.data.icons, name: rawData.data.name, publicAddress: rawData.data.publicAddress, url: rawData.data.url, description: rawData.data.description, chainId: rawData.data.chainId, mnemonic: rawData.data.mnemonic, walletType: rawData.data.walletType }; if (Platform.OS === 'ios') { const value = Object.keys(rawData.data.walletType)[0]; accountInfo.walletType = getWalletType(value!); resolve(accountInfo); } else { resolve(accountInfo); } } else { reject(rawData.data as CommonError); } }); }); } /** * Disconnect * @param walletType Wallet type * @param publicAddress Public address * @returns Result, success or error */ export async function disconnect( walletType: WalletType, publicAddress: string ): Promise { const obj = { wallet_type: walletType, public_address: publicAddress }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.disconnect(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as string); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Is connected * @param walletType Wallet type * @param publicAddress Public address * @returns Result, success or failure or error */ export async function isConnected( walletType: WalletType, publicAddress: string ): Promise { const obj = { wallet_type: walletType, public_address: publicAddress }; const json = JSON.stringify(obj); return new Promise((resolve) => { ParticleConnectPlugin.isConnected(json, (result: string) => { resolve(JSON.parse(result)); }); }); } /** * Sign message * @param walletType Wallet type * @param publicAddress Public address * @param message Message that you want user to sign * @returns Result, signed message or error */ export async function signMessage( walletType: WalletType, publicAddress: string, message: string ): Promise { let serializedMessage: string; let chainInfo = await getChainInfo(); if (chainInfo.name.toLowerCase() == 'solana') { serializedMessage = message; } else { if (isHexString(message)) { serializedMessage = message; } else { serializedMessage = '0x' + Buffer.from(message).toString('hex'); } } const obj = { wallet_type: walletType, public_address: publicAddress, message: serializedMessage, }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.signMessage(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as string); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Sign transaction * @param walletType Wallet type * @param publicAddress Public address * @param transaction Transaction that you want user to sign * @returns Result, signed transaction or error */ export async function signTransaction( walletType: WalletType, publicAddress: string, transaction: string ): Promise { const obj = { wallet_type: walletType, public_address: publicAddress, transaction: transaction, }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.signTransaction(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as string); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Sign all transactions * @param walletType Wallet type * @param publicAddress Public address * @param transactions Transactions that you want user to sign * @returns Result, signed transactions or error */ export async function signAllTransactions( walletType: WalletType, publicAddress: string, transactions: string[] ): Promise { const obj = { wallet_type: walletType, public_address: publicAddress, transactions: transactions, }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.signAllTransactions(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as string[]); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Sign and send transaction * @param walletType Wallet type * @param publicAddress Public address * @param transaction Transaction that you want user to sign and send * @returns Result, signature or error */ export async function signAndSendTransaction( walletType: WalletType, publicAddress: string, transaction: string, feeMode?: AAFeeMode ): Promise { const obj = { wallet_type: walletType, public_address: publicAddress, transaction: transaction, fee_mode: { option: feeMode?.getOption(), fee_quote: feeMode?.getFeeQuote(), token_paymaster_address: feeMode?.getTokenPaymasterAddress(), whole_fee_quote: feeMode?.getWholeFeeQuote(), }, }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.signAndSendTransaction(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as string); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Batch send transactions, works with particle aa service * @param transactions Transactions that you want user to sign and send * @param feeMode Optional, default is native * @returns Result, signature or error */ export async function batchSendTransactions( walletType: WalletType, publicAddress: string, transactions: string[], feeMode?: AAFeeMode ): Promise { const obj = { wallet_type: walletType, public_address: publicAddress, transactions: transactions, fee_mode: { option: feeMode?.getOption(), fee_quote: feeMode?.getFeeQuote(), token_paymaster_address: feeMode?.getTokenPaymasterAddress(), whole_fee_quote: feeMode?.getWholeFeeQuote(), }, }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.batchSendTransactions(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as string); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Sign typed data * @param walletType Wallet type * @param publicAddress Public address * @param typedData Typed data that you want user to sign and send, support typed data version v4 * @returns Result, signature or error */ export async function signTypedData( walletType: WalletType, publicAddress: string, typedData: string ): Promise { let serializedMessage: string; if (isHexString(typedData)) { serializedMessage = typedData; } else { serializedMessage = '0x' + Buffer.from(typedData).toString('hex'); } const obj = { wallet_type: walletType, public_address: publicAddress, message: serializedMessage, }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.signTypedData(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as string); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Sign in with Ethereum/Solana (EIP4361) * @param walletType Wallet type * @param publicAddress Public address * @param domain Domain, example "particle.network" * @param uri Uri, example "https://particle.network/demo#login" * @returns Result, source message and signature or error */ export function signInWithEthereum( walletType: WalletType, publicAddress: string, domain: string, uri: string ): Promise { const obj = { wallet_type: walletType, public_address: publicAddress, domain: domain, uri: uri, }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.signInWithEthereum(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as LoginResp); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Verify * @param walletType Wallet type * @param publicAddress Public address * @param message Source message * @param signature Signature * @returns Result, bool or error */ export function verify( walletType: WalletType, publicAddress: string, message: string, signature: string ): Promise { const obj = { wallet_type: walletType, public_address: publicAddress, message: message, signature: signature, }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.verify(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as boolean); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Import private key * @param walletType Wallet type, EvmPrivateKey or SolanaPrivateKey * @param privateKey Private key * @returns Result, account or error */ export function importPrivateKey( walletType: WalletType, privateKey: string ): Promise> { const obj = { wallet_type: walletType, private_key: privateKey }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.importPrivateKey(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as AccountInfo); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Import mnemonic * @param walletType Wallet type, EvmPrivateKey or SolanaPrivateKey * @param mnemonic Mnemonic, example "word1 work2 ... " at least 12 words. * @returns Result, account or error */ export function importMnemonic( walletType: WalletType, mnemonic: string ): Promise> { const obj = { wallet_type: walletType, mnemonic: mnemonic }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.importMnemonic(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as AccountInfo); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Export private key * @param walletType Wallet type, EvmPrivateKey or SolanaPrivateKey * @param publicAddress Public address * @returns Result, private key or error */ export function exportPrivateKey( walletType: WalletType, publicAddress: string ): Promise { const obj = { wallet_type: walletType, public_address: publicAddress }; const json = JSON.stringify(obj); return new Promise((resolve, reject) => { ParticleConnectPlugin.exportPrivateKey(json, (result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as string); } else { reject(parsedResult.data as CommonError); } }); }); } /** * Connect get a wallet connect qrcode uri, should use with NativeEventEmitter, event name 'qrCodeUri', * you can explore example for more details. * @returns Account */ export function connectWalletConnect(): Promise { return new Promise((resolve, reject) => { ParticleConnectPlugin.connectWalletConnect((result: string) => { const parsedResult: CommonResp = JSON.parse(result); if (parsedResult.status) { resolve(parsedResult.data as AccountInfo); } else { reject(parsedResult.data as CommonError); } }); }); } function getWalletType(value: string): WalletType | undefined { const normalizedValue = value.toLowerCase(); for (const key in WalletType) { if (key.toLowerCase() === normalizedValue) { return WalletType[key as keyof typeof WalletType]; } } return undefined; } export * from './Models'; export { ParticleConnectProvider } from './provider';