Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wallets): add evm to phantom #349

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 42 additions & 7 deletions wallets/provider-phantom/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,46 @@
export function phantom() {
if ('phantom' in window) {
const instance = window.phantom?.solana;
import type { Network, ProviderConnectResult } from '@rango-dev/wallets-shared';

if (instance?.isPhantom) {
return instance;
}
import { Networks } from '@rango-dev/wallets-shared';

type Provider = Map<Network, any>;

export function phantomInstances(): Provider | null {
const { phantom } = window;

if (!phantom) {
return null;
}

const { solana, ethereum } = phantom;

const instances: Provider = new Map();

if (ethereum && ethereum.isPhantom) {
instances.set(Networks.ETHEREUM, ethereum);
}

if (solana && phantom.isPhantom) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be solana.isPhantom?

instances.set(Networks.SOLANA, solana);
}
return instances;
}

export async function getNonEvmAccounts(
instances: Provider
): Promise<ProviderConnectResult[]> {
const solanaInstance = instances.get(Networks.SOLANA);
const results: ProviderConnectResult[] = [];

if (solanaInstance) {
const solanaResponse = await solanaInstance.connect();

const solanaAccounts: string = solanaResponse.publicKey.toString();

results.push({
accounts: [solanaAccounts],
chainId: Networks.SOLANA,
});
}

return null;
return results;
}
87 changes: 72 additions & 15 deletions wallets/provider-phantom/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,28 @@ import type {
CanEagerConnect,
CanSwitchNetwork,
Connect,
ProviderConnectResult,
Subscribe,
WalletInfo,
} from '@rango-dev/wallets-shared';
import type { BlockchainMeta, SignerFactory } from 'rango-types';

import {
getSolanaAccounts,
canEagerlyConnectToEvm,
canSwitchNetworkToEvm,
chooseInstance,
getEvmAccounts,
Networks,
WalletTypes,
} from '@rango-dev/wallets-shared';
import { solanaBlockchain } from 'rango-types';
import {
evmBlockchains,
isEvmBlockchain,
isSolanaBlockchain,
solanaBlockchain,
} from 'rango-types';

import { phantom as phantom_instance } from './helpers';
import { getNonEvmAccounts, phantomInstances } from './helpers';
import signer from './signer';

const WALLET = WalletTypes.PHANTOM;
Expand All @@ -23,11 +32,47 @@ export const config = {
type: WALLET,
};

export const getInstance = phantom_instance;
export const connect: Connect = getSolanaAccounts;
export const getInstance = phantomInstances;

export const connect: Connect = async ({ instance, meta }) => {
const ethInstance = chooseInstance(instance, meta, Networks.ETHEREUM);

let results: ProviderConnectResult[] = [];

if (ethInstance) {
const evmResult = await getEvmAccounts(ethInstance);
results.push(evmResult);
}

const nonEvmResults = await getNonEvmAccounts(instance);
results = [...results, ...nonEvmResults];

return results;
};

export const subscribe: Subscribe = (options) => {
const { connect, updateAccounts, state, updateChainId, meta, instance } =
options;

const ethInstance = chooseInstance(instance, meta, Networks.ETHEREUM);
const solanaInstance = chooseInstance(instance, meta, Networks.SOLANA);

export const subscribe: Subscribe = ({ instance, updateAccounts, connect }) => {
instance?.on('accountChanged', async (publicKey: string) => {
ethInstance?.on('accountsChanged', (addresses: string[]) => {
const eth_chainId = meta
.filter(isEvmBlockchain)
.find((blockchain) => blockchain.name === Networks.ETHEREUM)?.chainId;
if (state.connected) {
if (state.network != Networks.ETHEREUM && eth_chainId) {
updateChainId(eth_chainId);
}
updateAccounts(addresses);
}
});

solanaInstance?.on('accountChanged', async (publicKey: string) => {
if (state.network != Networks.SOLANA) {
updateChainId(meta.filter(isSolanaBlockchain)[0].chainId);
}
const network = Networks.SOLANA;
if (publicKey) {
const account = publicKey.toString();
Expand All @@ -38,23 +83,35 @@ export const subscribe: Subscribe = ({ instance, updateAccounts, connect }) => {
});
};

export const canSwitchNetworkTo: CanSwitchNetwork = () => false;
export const canSwitchNetworkTo: CanSwitchNetwork = canSwitchNetworkToEvm;

export const getSigners: (provider: any) => SignerFactory = signer;

export const canEagerConnect: CanEagerConnect = async ({ instance }) => {
try {
const result = await instance.connect({ onlyIfTrusted: true });
return !!result;
} catch (error) {
return false;
export const canEagerConnect: CanEagerConnect = async ({ instance, meta }) => {
const evm_instance = chooseInstance(instance, meta, Networks.ETHEREUM);
const solana_instance = chooseInstance(instance, meta, Networks.SOLANA);
if (evm_instance) {
return canEagerlyConnectToEvm({ instance: evm_instance, meta });
}

if (solana_instance) {
try {
const result = await instance.connect({ onlyIfTrusted: true });
return !!result;
} catch (error) {
return false;
}
}

return Promise.resolve(false);
};

export const getWalletInfo: (allBlockChains: BlockchainMeta[]) => WalletInfo = (
allBlockChains
) => {
const solana = solanaBlockchain(allBlockChains);
const evms = evmBlockchains(allBlockChains);

return {
name: 'Phantom',
img: 'https://raw.githubusercontent.com/rango-exchange/rango-assets/main/wallets/phantom/icon.svg',
Expand All @@ -65,6 +122,6 @@ export const getWalletInfo: (allBlockChains: BlockchainMeta[]) => WalletInfo = (
DEFAULT: 'https://phantom.app/',
},
color: '#4d40c6',
supportedChains: solana,
supportedChains: [...evms, ...solana],
};
};
13 changes: 7 additions & 6 deletions wallets/provider-phantom/src/signer.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import type { SignerFactory } from 'rango-types';

import { DefaultEvmSigner } from '@rango-dev/signer-evm';
import { DefaultSolanaSigner } from '@rango-dev/signer-solana';
import { Networks, getNetworkInstance } from '@rango-dev/wallets-shared';
import {
DefaultSignerFactory,
SignerFactory,
TransactionType as TxType,
} from 'rango-types';
import { getNetworkInstance, Networks } from '@rango-dev/wallets-shared';
import { DefaultSignerFactory, TransactionType as TxType } from 'rango-types';

export default function getSigners(provider: any): SignerFactory {
const ethProvider = getNetworkInstance(provider, Networks.ETHEREUM);
const solProvider = getNetworkInstance(provider, Networks.SOLANA);
const signers = new DefaultSignerFactory();
signers.registerSigner(TxType.EVM, new DefaultEvmSigner(ethProvider));
signers.registerSigner(TxType.SOLANA, new DefaultSolanaSigner(solProvider));
return signers;
}