UNPKG

@pushchain/ui-kit

Version:

Push Chain is a true universal L1 that is 100% EVM compatible. It allows developers to deploy once and make their apps instantly compatible with users from all other L1s (Ethereum, Solana, etc) with zero on-chain code change.

251 lines 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PhantomProvider = void 0; const ethers_1 = require("ethers"); const BaseWalletProvider_1 = require("../BaseWalletProvider"); const wallet_types_1 = require("../../../types/wallet.types"); const web3_js_1 = require("@solana/web3.js"); const viem_1 = require("viem"); const bytes_1 = require("@coral-xyz/anchor/dist/cjs/utils/bytes"); const chains_1 = require("viem/chains"); const phantomMobile_1 = require("./phantomMobile"); class PhantomProvider extends BaseWalletProvider_1.BaseWalletProvider { constructor() { super('Phantom', 'https://www.phantom.app/img/logo.png', [ wallet_types_1.ChainType.ETHEREUM, wallet_types_1.ChainType.SOLANA, ]); } connectedChainType = null; isInstalled = async () => { return (typeof window !== 'undefined' && (typeof window.phantom !== 'undefined' || (0, phantomMobile_1.isMobileDevice)())); }; connectEthereum = async () => { if (!window.phantom?.ethereum) { throw new Error('Phantom not installed for Ethereum'); } const provider = window.phantom?.ethereum; const accounts = await provider.request({ method: 'eth_requestAccounts' }); const rawAddress = accounts[0]; const checksumAddress = (0, ethers_1.getAddress)(rawAddress); const chainId = await this.getChainId(wallet_types_1.ChainType.ETHEREUM); this.connectedChainType = wallet_types_1.ChainType.ETHEREUM; const caipAddress = this.formatAddress(checksumAddress, wallet_types_1.ChainType.ETHEREUM, chainId); return caipAddress; }; connectSolana = async () => { if (!window.phantom?.solana) { if ((0, phantomMobile_1.shouldOpenPhantomMobileBrowser)(wallet_types_1.ChainType.SOLANA)) { (0, phantomMobile_1.openPhantomMobileBrowser)(wallet_types_1.ChainType.SOLANA); return new Promise(() => undefined); } throw new Error('Phantom not installed for Solana'); } const provider = window.phantom?.solana; const accounts = await provider.connect(); const chainId = await this.getChainId(wallet_types_1.ChainType.SOLANA); this.connectedChainType = wallet_types_1.ChainType.SOLANA; const caipAddress = this.formatAddress(accounts.publicKey.toString(), wallet_types_1.ChainType.SOLANA, chainId); return caipAddress; }; connect = async (chainType) => { let account; if (!chainType || chainType === wallet_types_1.ChainType.SOLANA) { account = this.connectSolana(); } else if (chainType === wallet_types_1.ChainType.ETHEREUM) { account = this.connectEthereum(); } if (!account) { throw new Error('Error in connecting to phantom'); } return account; }; getChainId = async (chainType) => { if (chainType === wallet_types_1.ChainType.ETHEREUM) { const provider = window.phantom?.ethereum; if (!provider) throw new Error('No Phantom Ethereum wallet connected'); const chainId = await provider.request({ method: 'eth_chainId' }); return parseInt(chainId, 16); } else if (chainType === wallet_types_1.ChainType.SOLANA) { const provider = window.phantom?.solana; if (!provider) throw new Error('No Phantom Solana wallet connected'); return provider.chainId || 1; } throw new Error('No Phantom wallet connected'); }; signMessage = async (message) => { const isInstalled = await this.isInstalled(); if (!isInstalled) { throw new Error('No Phantom wallet installed'); } if (this.connectedChainType === wallet_types_1.ChainType.SOLANA && window.phantom?.solana) { try { const provider = window.phantom?.solana; const signedMessage = await provider.signMessage(message, 'utf8'); return signedMessage.signature; } catch (error) { console.error('Phantom Solana signing error:', error); throw error; } } else if (this.connectedChainType === wallet_types_1.ChainType.ETHEREUM && window.phantom?.ethereum) { try { const provider = window.phantom?.ethereum; const accounts = await provider.request({ method: 'eth_accounts', }); if (!accounts || accounts.length === 0) { throw new Error('No connected account'); } const hexMessage = (0, viem_1.bytesToHex)(message); const signature = await provider.request({ method: 'personal_sign', params: [hexMessage, accounts[0]], }); return (0, viem_1.hexToBytes)(signature); } catch (error) { console.error('Phantom Ethereum signing error:', error); throw error; } } else { throw new Error('No Phantom wallet connected'); } }; signAndSendTransaction = async (txn) => { const isInstalled = await this.isInstalled(); if (!isInstalled) { throw new Error('No Phantom wallet installed'); } if (this.connectedChainType === wallet_types_1.ChainType.SOLANA && window.phantom?.solana) { try { const provider = window.phantom?.solana; // VersionedTransaction.deserialize handles both legacy and v0 transactions. // Check the deserialized message version to decide the appropriate type // for Phantom's signAndSendTransaction. const deserialized = web3_js_1.VersionedTransaction.deserialize(txn); let transaction; if (deserialized.message.version === 'legacy') { transaction = web3_js_1.Transaction.from(txn); } else { transaction = deserialized; } const signedTransaction = await provider.signAndSendTransaction(transaction); const signature = typeof signedTransaction === 'string' ? signedTransaction : signedTransaction.signature; return bytes_1.bs58.decode(signature); } catch (error) { console.error('Phantom Solana signing error:', error); throw error; } } else if (this.connectedChainType === wallet_types_1.ChainType.ETHEREUM && window.phantom?.ethereum) { try { const provider = window.phantom?.ethereum; const accounts = await provider.request({ method: 'eth_accounts', }); if (!accounts || accounts.length === 0) { throw new Error('No connected account'); } const hex = (0, viem_1.bytesToHex)(txn); const parsed = (0, viem_1.parseTransaction)(hex); const txParams = { from: accounts[0], to: parsed.to, value: parsed.value ? '0x' + parsed.value.toString(16) : undefined, data: parsed.data, gas: parsed.gas ? '0x' + parsed.gas.toString(16) : undefined, maxPriorityFeePerGas: parsed.maxPriorityFeePerGas ? '0x' + parsed.maxPriorityFeePerGas.toString(16) : undefined, maxFeePerGas: parsed.maxFeePerGas ? '0x' + parsed.maxFeePerGas.toString(16) : undefined, }; const signature = await provider.request({ method: 'eth_sendTransaction', params: [txParams], }); return (0, viem_1.hexToBytes)(signature); } catch (error) { console.error('Phantom Ethereum signing error:', error); throw error; } } else { throw new Error('No Phantom wallet connected'); } }; signTypedData = async (typedData) => { const isInstalled = await this.isInstalled(); if (!isInstalled) { throw new Error('No Phantom wallet installed'); } if (this.connectedChainType === wallet_types_1.ChainType.SOLANA && window.phantom?.solana) { throw new Error('signTypedData is not implemented for this provider'); } else if (this.connectedChainType === wallet_types_1.ChainType.ETHEREUM && window.phantom?.ethereum) { try { const walletClient = (0, viem_1.createWalletClient)({ chain: chains_1.sepolia, transport: (0, viem_1.custom)(window.ethereum), }); const accounts = await walletClient.request({ method: 'eth_accounts', }); if (!accounts || accounts.length === 0) { throw new Error('No connected account'); } const signature = await walletClient.signTypedData({ account: accounts[0], ...typedData, }); return (0, viem_1.hexToBytes)(signature); } catch (error) { console.error('Phantom Ethereum signing error:', error); throw error; } } else { throw new Error('No Phantom wallet connected'); } }; disconnect = async () => { const isInstalled = await this.isInstalled(); if (!isInstalled) return; if (this.connectedChainType === wallet_types_1.ChainType.SOLANA && window.phantom?.solana) { const provider = window.phantom?.solana; this.connectedChainType = null; await provider.disconnect(); } if (this.connectedChainType === wallet_types_1.ChainType.ETHEREUM && window.phantom?.ethereum) { this.connectedChainType = null; //TOOD: find how to disconnect ethereum } return Promise.resolve(); }; } exports.PhantomProvider = PhantomProvider; //# sourceMappingURL=phantom.js.map