UNPKG

@hashgraph/hedera-wallet-connect

Version:

A library to facilitate integrating Hedera with WalletConnect

291 lines (290 loc) 11.6 kB
import { CoreHelperUtil } from '@reown/appkit'; import { isReownName } from '@reown/appkit-common'; import { AdapterBlueprint, WcHelpersUtil } from '@reown/appkit-controllers'; import { LedgerId } from '@hashgraph/sdk'; import { BrowserProvider, Contract, formatUnits, JsonRpcSigner, parseUnits } from 'ethers'; import { HederaConnector } from './connectors'; import { hederaNamespace, getAccountBalance, HederaChainDefinition } from './utils'; import { createLogger } from '../lib/shared/logger'; export class HederaAdapter extends AdapterBlueprint { constructor(params) { var _a, _b; if (params.namespace !== hederaNamespace && params.namespace !== 'eip155') { throw new Error('Namespace must be "hedera" or "eip155"'); } if (params.namespace == 'eip155') { if ((_a = params.networks) === null || _a === void 0 ? void 0 : _a.some((n) => n.chainNamespace != 'eip155')) { throw new Error('Invalid networks for eip155 namespace'); } } else { if ((_b = params.networks) === null || _b === void 0 ? void 0 : _b.some((n) => n.chainNamespace != hederaNamespace)) { throw new Error('Invalid networks for hedera namespace'); } } super(Object.assign({}, params)); this.logger = createLogger('HederaAdapter'); // Override getCaipNetworks to return appropriate networks based on namespace this.getCaipNetworks = (namespace) => { const targetNamespace = namespace || this.namespace; if (targetNamespace === 'eip155') { // Return EIP155 Hedera networks return [HederaChainDefinition.EVM.Mainnet, HederaChainDefinition.EVM.Testnet]; } else if (targetNamespace === hederaNamespace) { // Return native Hedera networks return [HederaChainDefinition.Native.Mainnet, HederaChainDefinition.Native.Testnet]; } else { // Return all Hedera networks if no specific namespace is requested return [ HederaChainDefinition.EVM.Mainnet, HederaChainDefinition.EVM.Testnet, HederaChainDefinition.Native.Mainnet, HederaChainDefinition.Native.Testnet, ]; } }; } async setUniversalProvider(universalProvider) { this.addConnector(new HederaConnector({ provider: universalProvider, caipNetworks: this.getCaipNetworks() || [], namespace: this.namespace, })); } async connect(params) { this.logger.debug('connect called with params:', params); // Get the WalletConnect connector and ensure it connects with proper namespaces const connector = this.getWalletConnectConnector(); if (connector && 'connectWalletConnect' in connector) { this.logger.debug('Calling HederaConnector.connectWalletConnect'); await connector.connectWalletConnect(); } else { this.logger.warn('HederaConnector not found or connectWalletConnect method missing'); } return Promise.resolve({ id: 'WALLET_CONNECT', type: 'WALLET_CONNECT', chainId: Number(params.chainId), provider: this.provider, address: '', }); } async disconnect(_params) { try { const connector = this.getWalletConnectConnector(); await connector.disconnect(); } catch (error) { this.logger.warn('disconnect - error', error); } return { connections: [] }; } async getAccounts({ namespace, }) { var _a, _b, _c, _d; const provider = this.provider; const addresses = (((_d = (_c = (_b = (_a = provider === null || provider === void 0 ? void 0 : provider.session) === null || _a === void 0 ? void 0 : _a.namespaces) === null || _b === void 0 ? void 0 : _b[namespace]) === null || _c === void 0 ? void 0 : _c.accounts) === null || _d === void 0 ? void 0 : _d.map((account) => { const [, , address] = account.split(':'); return address; }).filter((address, index, self) => self.indexOf(address) === index)) || []); return Promise.resolve({ accounts: addresses.map((address) => CoreHelperUtil.createAccount(namespace, address, 'eoa')), }); } async syncConnectors() { return Promise.resolve(); } async syncConnections(_params) { return Promise.resolve(); } async getBalance(params) { const { address, caipNetwork } = params; if (!caipNetwork) { return Promise.resolve({ balance: '0', decimals: 0, symbol: '', }); } const accountBalance = await getAccountBalance(caipNetwork.testnet ? LedgerId.TESTNET : LedgerId.MAINNET, address); return Promise.resolve({ balance: accountBalance ? formatUnits(accountBalance.hbars.toTinybars().toString(), 8).toString() : '0', decimals: caipNetwork.nativeCurrency.decimals, symbol: caipNetwork.nativeCurrency.symbol, }); } async signMessage(params) { const { provider, message, address } = params; if (!provider) { throw new Error('Provider is undefined'); } const hederaProvider = provider; let signature = ''; if (this.namespace === hederaNamespace) { const response = await hederaProvider.hedera_signMessage({ signerAccountId: address, message, }); signature = response.signatureMap; } else { signature = await hederaProvider.eth_signMessage(message, address); } return { signature }; } async estimateGas(params) { const { provider, caipNetwork, address } = params; if (this.namespace !== 'eip155') { throw new Error('Namespace is not eip155'); } if (!provider) { throw new Error('Provider is undefined'); } const hederaProvider = provider; const result = await hederaProvider.eth_estimateGas({ data: params.data, to: params.to, address: address, }, address, Number(caipNetwork === null || caipNetwork === void 0 ? void 0 : caipNetwork.id)); return { gas: result }; } async sendTransaction(params) { var _a; if (!params.provider) { throw new Error('Provider is undefined'); } const hederaProvider = params.provider; if (this.namespace == 'eip155') { const tx = await hederaProvider.eth_sendTransaction({ value: params.value, to: params.to, data: params.data, gas: params.gas, gasPrice: params.gasPrice, address: params.address, }, params.address, Number((_a = params.caipNetwork) === null || _a === void 0 ? void 0 : _a.id)); return { hash: tx }; } else { throw new Error('Namespace is not eip155'); } } async writeContract(params) { if (!params.provider) { throw new Error('Provider is undefined'); } if (this.namespace !== 'eip155') { throw new Error('Namespace is not eip155'); } const { provider, caipNetwork, caipAddress, abi, tokenAddress, method, args } = params; const browserProvider = new BrowserProvider(provider, Number(caipNetwork === null || caipNetwork === void 0 ? void 0 : caipNetwork.id)); const signer = new JsonRpcSigner(browserProvider, caipAddress); const contract = new Contract(tokenAddress, abi, signer); if (!contract || !method) { throw new Error('Contract method is undefined'); } const contractMethod = contract[method]; if (contractMethod) { const result = await contractMethod(...args); return { hash: result }; } else throw new Error('Contract method is undefined'); } async getEnsAddress(params) { if (this.namespace !== 'eip155') { throw new Error('Namespace is not eip155'); } const { name, caipNetwork } = params; if (caipNetwork) { if (isReownName(name)) { return { address: (await WcHelpersUtil.resolveReownName(name)) || false, }; } } return { address: false }; } parseUnits(params) { return parseUnits(params.value, params.decimals); } formatUnits(params) { return formatUnits(params.value, params.decimals); } async getCapabilities(params) { var _a, _b; if (this.namespace !== 'eip155') { throw new Error('Namespace is not eip155'); } const provider = this.provider; if (!provider) { throw new Error('Provider is undefined'); } const walletCapabilitiesString = (_b = (_a = provider.session) === null || _a === void 0 ? void 0 : _a.sessionProperties) === null || _b === void 0 ? void 0 : _b['capabilities']; if (walletCapabilitiesString) { try { const walletCapabilities = JSON.parse(walletCapabilitiesString); const accountCapabilities = walletCapabilities[params]; if (accountCapabilities) { return accountCapabilities; } // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (error) { throw new Error('Error parsing wallet capabilities'); } } return await provider.request({ method: 'wallet_getCapabilities', params: [params], }); } // Not supported async getProfile() { return Promise.resolve({ profileImage: '', profileName: '', }); } // Not supported async grantPermissions() { return Promise.resolve({}); } // Not supported async revokePermissions() { return Promise.resolve('0x'); } async syncConnection(params) { return Promise.resolve({ id: 'WALLET_CONNECT', type: 'WALLET_CONNECT', chainId: params.chainId, provider: this.provider, address: '', }); } async switchNetwork(params) { const { caipNetwork } = params; const connector = this.getWalletConnectConnector(); connector.provider.setDefaultChain(caipNetwork.caipNetworkId); } getWalletConnectConnector() { const connector = this.connectors.find((c) => c.type == 'WALLET_CONNECT'); if (!connector) { throw new Error('WalletConnectConnector not found'); } return connector; } getWalletConnectProvider() { const connector = this.connectors.find((c) => c.type === 'WALLET_CONNECT'); const provider = connector === null || connector === void 0 ? void 0 : connector.provider; return provider; } async walletGetAssets(_params) { return Promise.resolve({}); } }