forked from cerc-io/laconic-wallet
Send back namespaces object based on chains requested by dApp (#94)
* Refactor pairing modal code * Refactor update session code * Reset state after session proposal is approved * Refactor approve and update session * Remove unused helper methods * Remove completed todos
This commit is contained in:
parent
888302a0dd
commit
15da99a827
@ -25,7 +25,7 @@ import WalletConnect from './screens/WalletConnect';
|
|||||||
import { StackParamsList } from './types';
|
import { StackParamsList } from './types';
|
||||||
import { web3wallet } from './utils/wallet-connect/WalletConnectUtils';
|
import { web3wallet } from './utils/wallet-connect/WalletConnectUtils';
|
||||||
import { EIP155_SIGNING_METHODS } from './utils/wallet-connect/EIP155Data';
|
import { EIP155_SIGNING_METHODS } from './utils/wallet-connect/EIP155Data';
|
||||||
import { getSignParamsMessage } from './utils/wallet-connect/Helpers';
|
import { getSignParamsMessage } from './utils/wallet-connect/helpers';
|
||||||
import ApproveTransaction from './screens/ApproveTransaction';
|
import ApproveTransaction from './screens/ApproveTransaction';
|
||||||
import AddNetwork from './screens/AddNetwork';
|
import AddNetwork from './screens/AddNetwork';
|
||||||
import { COSMOS, EIP155 } from './utils/constants';
|
import { COSMOS, EIP155 } from './utils/constants';
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { ScrollView, TouchableOpacity, View } from 'react-native';
|
import { ScrollView, TouchableOpacity, View } from 'react-native';
|
||||||
import { Button, List, Text, useTheme } from 'react-native-paper';
|
import { Button, List, Text, useTheme } from 'react-native-paper';
|
||||||
import mergeWith from 'lodash/mergeWith';
|
|
||||||
import { setInternetCredentials } from 'react-native-keychain';
|
import { setInternetCredentials } from 'react-native-keychain';
|
||||||
|
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
@ -14,12 +13,10 @@ import HDPathDialog from './HDPathDialog';
|
|||||||
import AccountDetails from './AccountDetails';
|
import AccountDetails from './AccountDetails';
|
||||||
import { useAccounts } from '../context/AccountsContext';
|
import { useAccounts } from '../context/AccountsContext';
|
||||||
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
|
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
|
||||||
import { EIP155_SIGNING_METHODS } from '../utils/wallet-connect/EIP155Data';
|
|
||||||
import { COSMOS_METHODS } from '../utils/wallet-connect/COSMOSData';
|
|
||||||
import { useNetworks } from '../context/NetworksContext';
|
import { useNetworks } from '../context/NetworksContext';
|
||||||
import { COSMOS, EIP155 } from '../utils/constants';
|
import { EIP155 } from '../utils/constants';
|
||||||
import { NETWORK_METHODS } from '../utils/wallet-connect/common-data';
|
|
||||||
import ConfirmDialog from './ConfirmDialog';
|
import ConfirmDialog from './ConfirmDialog';
|
||||||
|
import { getNamespaces } from '../utils/wallet-connect/helpers';
|
||||||
|
|
||||||
const Accounts = ({ currentIndex, updateIndex }: AccountsProps) => {
|
const Accounts = ({ currentIndex, updateIndex }: AccountsProps) => {
|
||||||
const navigation =
|
const navigation =
|
||||||
@ -52,68 +49,17 @@ const Accounts = ({ currentIndex, updateIndex }: AccountsProps) => {
|
|||||||
|
|
||||||
for (const topic in sessions) {
|
for (const topic in sessions) {
|
||||||
const session = sessions[topic];
|
const session = sessions[topic];
|
||||||
const combinedNamespaces = mergeWith(
|
const { optionalNamespaces, requiredNamespaces } = session;
|
||||||
session.requiredNamespaces,
|
|
||||||
session.optionalNamespaces,
|
const updatedNamespaces = await getNamespaces(
|
||||||
(obj, src) =>
|
optionalNamespaces,
|
||||||
Array.isArray(obj) && Array.isArray(src)
|
requiredNamespaces,
|
||||||
? [...src, ...obj]
|
networksData,
|
||||||
: undefined,
|
selectedNetwork,
|
||||||
|
accounts,
|
||||||
|
currentIndex,
|
||||||
);
|
);
|
||||||
|
|
||||||
const namespaceChainId = `${selectedNetwork?.namespace}:${selectedNetwork?.chainId}`;
|
|
||||||
|
|
||||||
let updatedNamespaces;
|
|
||||||
switch (selectedNetwork?.namespace) {
|
|
||||||
case EIP155:
|
|
||||||
updatedNamespaces = {
|
|
||||||
eip155: {
|
|
||||||
chains: [namespaceChainId],
|
|
||||||
// TODO: Debug optional namespace methods and events being required for approval
|
|
||||||
methods: [
|
|
||||||
...Object.values(EIP155_SIGNING_METHODS),
|
|
||||||
...Object.values(NETWORK_METHODS),
|
|
||||||
...(combinedNamespaces.eip155?.methods ?? []),
|
|
||||||
],
|
|
||||||
events: [...(combinedNamespaces.eip155?.events ?? [])],
|
|
||||||
accounts: accounts.map(ethAccount => {
|
|
||||||
return `${namespaceChainId}:${ethAccount.address}`;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
cosmos: {
|
|
||||||
chains: [],
|
|
||||||
methods: [],
|
|
||||||
events: [],
|
|
||||||
accounts: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case COSMOS:
|
|
||||||
updatedNamespaces = {
|
|
||||||
cosmos: {
|
|
||||||
chains: [namespaceChainId],
|
|
||||||
methods: [
|
|
||||||
...Object.values(COSMOS_METHODS),
|
|
||||||
...Object.values(NETWORK_METHODS),
|
|
||||||
...(combinedNamespaces.cosmos?.methods ?? []),
|
|
||||||
],
|
|
||||||
events: [...(combinedNamespaces.cosmos?.events ?? [])],
|
|
||||||
accounts: accounts.map(cosmosAccount => {
|
|
||||||
return `${namespaceChainId}:${cosmosAccount.address}`;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
eip155: {
|
|
||||||
chains: [],
|
|
||||||
methods: [],
|
|
||||||
events: [],
|
|
||||||
accounts: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!updatedNamespaces) {
|
if (!updatedNamespaces) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,8 @@ import styles from '../styles/stylesheet';
|
|||||||
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
|
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
|
||||||
import { useAccounts } from '../context/AccountsContext';
|
import { useAccounts } from '../context/AccountsContext';
|
||||||
import { useWalletConnect } from '../context/WalletConnectContext';
|
import { useWalletConnect } from '../context/WalletConnectContext';
|
||||||
import { EIP155_SIGNING_METHODS } from '../utils/wallet-connect/EIP155Data';
|
|
||||||
import { COSMOS_METHODS } from '../utils/wallet-connect/COSMOSData';
|
|
||||||
import { useNetworks } from '../context/NetworksContext';
|
import { useNetworks } from '../context/NetworksContext';
|
||||||
import { COSMOS, EIP155 } from '../utils/constants';
|
import { getNamespaces } from '../utils/wallet-connect/helpers';
|
||||||
import { NETWORK_METHODS } from '../utils/wallet-connect/common-data';
|
|
||||||
|
|
||||||
const PairingModal = ({
|
const PairingModal = ({
|
||||||
visible,
|
visible,
|
||||||
@ -25,7 +22,7 @@ const PairingModal = ({
|
|||||||
setToastVisible,
|
setToastVisible,
|
||||||
}: PairingModalProps) => {
|
}: PairingModalProps) => {
|
||||||
const { accounts, currentIndex } = useAccounts();
|
const { accounts, currentIndex } = useAccounts();
|
||||||
const { selectedNetwork } = useNetworks();
|
const { selectedNetwork, networksData } = useNetworks();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const dappName = currentProposal?.params?.proposer?.metadata.name;
|
const dappName = currentProposal?.params?.proposer?.metadata.name;
|
||||||
@ -42,6 +39,18 @@ const PairingModal = ({
|
|||||||
walletConnectChains: [],
|
walletConnectChains: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [supportedNamespaces, setSupportedNamespaces] = useState<
|
||||||
|
Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
chains: string[];
|
||||||
|
methods: string[];
|
||||||
|
events: string[];
|
||||||
|
accounts: string[];
|
||||||
|
}
|
||||||
|
>
|
||||||
|
>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!currentProposal) {
|
if (!currentProposal) {
|
||||||
return;
|
return;
|
||||||
@ -79,78 +88,28 @@ const PairingModal = ({
|
|||||||
|
|
||||||
const { setActiveSessions } = useWalletConnect();
|
const { setActiveSessions } = useWalletConnect();
|
||||||
|
|
||||||
const supportedNamespaces = useMemo(() => {
|
useEffect(() => {
|
||||||
if (!currentProposal) {
|
const getSupportedNamespaces = async () => {
|
||||||
return;
|
if (!currentProposal) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Set selected account as the first account in supported namespaces
|
const { optionalNamespaces, requiredNamespaces } = currentProposal.params;
|
||||||
const sortedAccounts = [
|
|
||||||
accounts[currentIndex],
|
|
||||||
...accounts.filter((account, index) => index !== currentIndex),
|
|
||||||
];
|
|
||||||
|
|
||||||
const namespaceChainId = `${selectedNetwork?.namespace}:${selectedNetwork?.chainId}`;
|
const nameSpaces = await getNamespaces(
|
||||||
|
optionalNamespaces,
|
||||||
|
requiredNamespaces,
|
||||||
|
networksData,
|
||||||
|
selectedNetwork,
|
||||||
|
accounts,
|
||||||
|
currentIndex,
|
||||||
|
);
|
||||||
|
|
||||||
const { optionalNamespaces, requiredNamespaces } = currentProposal.params;
|
setSupportedNamespaces(nameSpaces);
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Check with other dApps
|
getSupportedNamespaces();
|
||||||
switch (selectedNetwork?.namespace) {
|
}, [currentProposal, networksData, selectedNetwork, accounts, currentIndex]);
|
||||||
case EIP155:
|
|
||||||
return {
|
|
||||||
eip155: {
|
|
||||||
chains: [namespaceChainId],
|
|
||||||
// TODO: Debug optional namespace methods and events being required for approval
|
|
||||||
methods: [
|
|
||||||
...Object.values(EIP155_SIGNING_METHODS),
|
|
||||||
...Object.values(NETWORK_METHODS),
|
|
||||||
...(optionalNamespaces.eip155?.methods ?? []),
|
|
||||||
...(requiredNamespaces.eip155?.methods ?? []),
|
|
||||||
],
|
|
||||||
events: [
|
|
||||||
...(optionalNamespaces.eip155?.events ?? []),
|
|
||||||
...(requiredNamespaces.eip155?.events ?? []),
|
|
||||||
],
|
|
||||||
accounts: sortedAccounts.map(ethAccount => {
|
|
||||||
return `${namespaceChainId}:${ethAccount.address}`;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
cosmos: {
|
|
||||||
chains: [],
|
|
||||||
methods: [],
|
|
||||||
events: [],
|
|
||||||
accounts: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
case COSMOS:
|
|
||||||
return {
|
|
||||||
cosmos: {
|
|
||||||
chains: [namespaceChainId],
|
|
||||||
methods: [
|
|
||||||
...Object.values(COSMOS_METHODS),
|
|
||||||
...Object.values(NETWORK_METHODS),
|
|
||||||
...(optionalNamespaces.cosmos?.methods ?? []),
|
|
||||||
...(requiredNamespaces.cosmos?.methods ?? []),
|
|
||||||
],
|
|
||||||
events: [
|
|
||||||
...(optionalNamespaces.cosmos?.events ?? []),
|
|
||||||
...(requiredNamespaces.cosmos?.events ?? []),
|
|
||||||
],
|
|
||||||
accounts: sortedAccounts.map(cosmosAccount => {
|
|
||||||
return `${namespaceChainId}:${cosmosAccount.address}`;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
eip155: {
|
|
||||||
chains: [],
|
|
||||||
methods: [],
|
|
||||||
events: [],
|
|
||||||
accounts: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}, [accounts, currentProposal, currentIndex, selectedNetwork]);
|
|
||||||
|
|
||||||
const namespaces = useMemo(() => {
|
const namespaces = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
@ -180,6 +139,7 @@ const PairingModal = ({
|
|||||||
setModalVisible(false);
|
setModalVisible(false);
|
||||||
setToastVisible(true);
|
setToastVisible(true);
|
||||||
setCurrentProposal(undefined);
|
setCurrentProposal(undefined);
|
||||||
|
setSupportedNamespaces(undefined);
|
||||||
setWalletConnectData({
|
setWalletConnectData({
|
||||||
walletConnectMethods: [],
|
walletConnectMethods: [],
|
||||||
walletConnectEvents: [],
|
walletConnectEvents: [],
|
||||||
|
@ -42,7 +42,6 @@ const ApproveTransaction = ({ route }: SignRequestProps) => {
|
|||||||
const requestName = requestSession.peer.metadata.name;
|
const requestName = requestSession.peer.metadata.name;
|
||||||
const requestIcon = requestSession.peer.metadata.icons[0];
|
const requestIcon = requestSession.peer.metadata.icons[0];
|
||||||
const requestURL = requestSession.peer.metadata.url;
|
const requestURL = requestSession.peer.metadata.url;
|
||||||
// TODO: Remove and access namespace from requestEvent
|
|
||||||
const transaction = route.params.transaction;
|
const transaction = route.params.transaction;
|
||||||
const requestEvent = route.params.requestEvent;
|
const requestEvent = route.params.requestEvent;
|
||||||
const chainId = requestEvent.params.chainId;
|
const chainId = requestEvent.params.chainId;
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
// Taken from https://medium.com/walletconnect/how-to-build-a-wallet-in-react-native-with-the-web3wallet-sdk-b6f57bf02f9a
|
|
||||||
|
|
||||||
import { providers, Wallet } from 'ethers';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Types
|
|
||||||
*/
|
|
||||||
interface IInitArgs {
|
|
||||||
mnemonic?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Library
|
|
||||||
*/
|
|
||||||
export default class EIP155Lib {
|
|
||||||
wallet: Wallet;
|
|
||||||
|
|
||||||
constructor(wallet: Wallet) {
|
|
||||||
this.wallet = wallet;
|
|
||||||
}
|
|
||||||
|
|
||||||
static init({ mnemonic }: IInitArgs) {
|
|
||||||
const wallet = mnemonic
|
|
||||||
? Wallet.fromMnemonic(mnemonic)
|
|
||||||
: Wallet.createRandom();
|
|
||||||
|
|
||||||
return new EIP155Lib(wallet);
|
|
||||||
}
|
|
||||||
|
|
||||||
getMnemonic() {
|
|
||||||
return this.wallet.mnemonic.phrase;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAddress() {
|
|
||||||
return this.wallet.address;
|
|
||||||
}
|
|
||||||
|
|
||||||
signMessage(message: string) {
|
|
||||||
return this.wallet.signMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
_signTypedData(domain: any, types: any, data: any) {
|
|
||||||
return this.wallet._signTypedData(domain, types, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(provider: providers.JsonRpcProvider) {
|
|
||||||
return this.wallet.connect(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
signTransaction(transaction: providers.TransactionRequest) {
|
|
||||||
return this.wallet.signTransaction(transaction);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
// Taken from https://medium.com/walletconnect/how-to-build-a-wallet-in-react-native-with-the-web3wallet-sdk-b6f57bf02f9a
|
|
||||||
|
|
||||||
import { utils } from 'ethers';
|
|
||||||
|
|
||||||
import { Account } from '../../types';
|
|
||||||
import { EIP155_CHAINS, TEIP155Chain } from './EIP155Data';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Truncates string (in the middle) via given lenght value
|
|
||||||
*/
|
|
||||||
export function truncate(value: string, length: number) {
|
|
||||||
if (value?.length <= length) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const separator = '...';
|
|
||||||
const stringLength = length - separator.length;
|
|
||||||
const frontLength = Math.ceil(stringLength / 2);
|
|
||||||
const backLength = Math.floor(stringLength / 2);
|
|
||||||
|
|
||||||
return (
|
|
||||||
value.substring(0, frontLength) +
|
|
||||||
separator +
|
|
||||||
value.substring(value.length - backLength)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts hex to utf8 string if it is valid bytes
|
|
||||||
*/
|
|
||||||
export function convertHexToUtf8(value: string) {
|
|
||||||
if (utils.isHexString(value)) {
|
|
||||||
return utils.toUtf8String(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets message from various signing request methods by filtering out
|
|
||||||
* a value that is not an address (thus is a message).
|
|
||||||
* If it is a hex string, it gets converted to utf8 string
|
|
||||||
*/
|
|
||||||
export function getSignParamsMessage(params: string[]) {
|
|
||||||
const message = params.filter(p => !utils.isAddress(p))[0];
|
|
||||||
|
|
||||||
return convertHexToUtf8(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets data from various signTypedData request methods by filtering out
|
|
||||||
* a value that is not an address (thus is data).
|
|
||||||
* If data is a string convert it to object
|
|
||||||
*/
|
|
||||||
export function getSignTypedDataParamsData(params: string[]) {
|
|
||||||
const data = params.filter(p => !utils.isAddress(p))[0];
|
|
||||||
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
return JSON.parse(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get our address from params checking if params string contains one
|
|
||||||
* of our wallet addresses
|
|
||||||
*/
|
|
||||||
export async function getAccountNumberFromParams(
|
|
||||||
addresses: string[],
|
|
||||||
ethAccounts: Account[],
|
|
||||||
params: any,
|
|
||||||
) {
|
|
||||||
const paramsString = JSON.stringify(params);
|
|
||||||
let address = '';
|
|
||||||
|
|
||||||
addresses.forEach(addr => {
|
|
||||||
if (paramsString.includes(addr)) {
|
|
||||||
address = addr;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentAccount = ethAccounts!.find(
|
|
||||||
account => account.address === address,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!currentAccount) {
|
|
||||||
throw new Error('Account with given adress not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentAccount.counterId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if chain is part of EIP155 standard
|
|
||||||
*/
|
|
||||||
export function isEIP155Chain(chain: string) {
|
|
||||||
return chain.includes('eip155');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if chain is part of COSMOS standard
|
|
||||||
*/
|
|
||||||
export function isCosmosChain(chain: string) {
|
|
||||||
return chain.includes('cosmos');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if chain is part of SOLANA standard
|
|
||||||
*/
|
|
||||||
export function isSolanaChain(chain: string) {
|
|
||||||
return chain.includes('solana');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats chainId to its name
|
|
||||||
*/
|
|
||||||
export function formatChainName(chainId: string) {
|
|
||||||
return EIP155_CHAINS[chainId as TEIP155Chain]?.name ?? chainId;
|
|
||||||
}
|
|
208
src/utils/wallet-connect/helpers.ts
Normal file
208
src/utils/wallet-connect/helpers.ts
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
// Taken from https://medium.com/walletconnect/how-to-build-a-wallet-in-react-native-with-the-web3wallet-sdk-b6f57bf02f9a
|
||||||
|
|
||||||
|
import { utils } from 'ethers';
|
||||||
|
|
||||||
|
import { ProposalTypes } from '@walletconnect/types';
|
||||||
|
|
||||||
|
import { Account, NetworksDataState } from '../../types';
|
||||||
|
import { EIP155_SIGNING_METHODS } from './EIP155Data';
|
||||||
|
import { mergeWith } from 'lodash';
|
||||||
|
import { retrieveAccounts } from '../accounts';
|
||||||
|
import { COSMOS, EIP155 } from '../constants';
|
||||||
|
import { NETWORK_METHODS } from './common-data';
|
||||||
|
import { COSMOS_METHODS } from './COSMOSData';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts hex to utf8 string if it is valid bytes
|
||||||
|
*/
|
||||||
|
export function convertHexToUtf8(value: string) {
|
||||||
|
if (utils.isHexString(value)) {
|
||||||
|
return utils.toUtf8String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets message from various signing request methods by filtering out
|
||||||
|
* a value that is not an address (thus is a message).
|
||||||
|
* If it is a hex string, it gets converted to utf8 string
|
||||||
|
*/
|
||||||
|
export function getSignParamsMessage(params: string[]) {
|
||||||
|
const message = params.filter(p => !utils.isAddress(p))[0];
|
||||||
|
|
||||||
|
return convertHexToUtf8(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getNamespaces = async (
|
||||||
|
optionalNamespaces: ProposalTypes.OptionalNamespaces,
|
||||||
|
requiredNamespaces: ProposalTypes.RequiredNamespaces,
|
||||||
|
networksData: NetworksDataState[],
|
||||||
|
selectedNetwork: NetworksDataState,
|
||||||
|
accounts: Account[],
|
||||||
|
currentIndex: number,
|
||||||
|
) => {
|
||||||
|
const namespaceChainId = `${selectedNetwork.namespace}:${selectedNetwork.chainId}`;
|
||||||
|
|
||||||
|
const combinedNamespaces = mergeWith(
|
||||||
|
requiredNamespaces,
|
||||||
|
optionalNamespaces,
|
||||||
|
(obj, src) =>
|
||||||
|
Array.isArray(obj) && Array.isArray(src) ? [...src, ...obj] : undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
const walletConnectChains: string[] = [];
|
||||||
|
|
||||||
|
Object.keys(combinedNamespaces).forEach(key => {
|
||||||
|
const { chains } = combinedNamespaces[key];
|
||||||
|
|
||||||
|
chains && walletConnectChains.push(...chains);
|
||||||
|
});
|
||||||
|
|
||||||
|
// If combinedNamespaces is not empty, send back namespaces object based on requested chains
|
||||||
|
// Else send back namespaces object using currently selected network
|
||||||
|
if (Object.keys(combinedNamespaces).length > 0) {
|
||||||
|
if (!(walletConnectChains.length > 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get required networks
|
||||||
|
const requiredNetworks = networksData.filter(network =>
|
||||||
|
walletConnectChains.includes(`${network.namespace}:${network.chainId}`),
|
||||||
|
);
|
||||||
|
// Get accounts for required networks
|
||||||
|
const requiredAddressesPromise = requiredNetworks.map(
|
||||||
|
async requiredNetwork => {
|
||||||
|
const retrievedAccounts = await retrieveAccounts(requiredNetwork);
|
||||||
|
|
||||||
|
if (!retrievedAccounts) {
|
||||||
|
throw new Error('Accounts for given network not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const addresses = retrievedAccounts.map(
|
||||||
|
retrieveAccount =>
|
||||||
|
`${requiredNetwork.namespace}:${requiredNetwork.chainId}:${retrieveAccount.address}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return addresses;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const requiredAddressesArray = await Promise.all(requiredAddressesPromise);
|
||||||
|
const requiredAddresses = requiredAddressesArray.flat();
|
||||||
|
|
||||||
|
let sortedAccounts = requiredAddresses;
|
||||||
|
|
||||||
|
// If selected network is included in chains requested from dApp,
|
||||||
|
// Put selected account as first account
|
||||||
|
if (walletConnectChains.includes(namespaceChainId)) {
|
||||||
|
const currentAddresses = requiredAddresses.filter(address =>
|
||||||
|
address.includes(namespaceChainId),
|
||||||
|
);
|
||||||
|
sortedAccounts = [
|
||||||
|
currentAddresses[currentIndex],
|
||||||
|
...currentAddresses.filter((address, index) => index !== currentIndex),
|
||||||
|
...requiredAddresses.filter(
|
||||||
|
address => !currentAddresses.includes(address),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct namespace object
|
||||||
|
const newNamespaces = {
|
||||||
|
eip155: {
|
||||||
|
chains: walletConnectChains.filter(chain => chain.includes(EIP155)),
|
||||||
|
// TODO: Debug optional namespace methods and events being required for approval
|
||||||
|
methods: [
|
||||||
|
...Object.values(EIP155_SIGNING_METHODS),
|
||||||
|
...Object.values(NETWORK_METHODS),
|
||||||
|
...(optionalNamespaces.eip155?.methods ?? []),
|
||||||
|
...(requiredNamespaces.eip155?.methods ?? []),
|
||||||
|
],
|
||||||
|
events: [
|
||||||
|
...(optionalNamespaces.eip155?.events ?? []),
|
||||||
|
...(requiredNamespaces.eip155?.events ?? []),
|
||||||
|
],
|
||||||
|
accounts: sortedAccounts.filter(account => account.includes(EIP155)),
|
||||||
|
},
|
||||||
|
cosmos: {
|
||||||
|
chains: walletConnectChains.filter(chain => chain.includes(COSMOS)),
|
||||||
|
methods: [
|
||||||
|
...Object.values(COSMOS_METHODS),
|
||||||
|
...Object.values(NETWORK_METHODS),
|
||||||
|
...(optionalNamespaces.cosmos?.methods ?? []),
|
||||||
|
...(requiredNamespaces.cosmos?.methods ?? []),
|
||||||
|
],
|
||||||
|
events: [
|
||||||
|
...(optionalNamespaces.cosmos?.events ?? []),
|
||||||
|
...(requiredNamespaces.cosmos?.events ?? []),
|
||||||
|
],
|
||||||
|
accounts: sortedAccounts.filter(account => account.includes(COSMOS)),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return newNamespaces;
|
||||||
|
} else {
|
||||||
|
// Set selected account as the first account in supported namespaces
|
||||||
|
const sortedAccounts = [
|
||||||
|
accounts[currentIndex],
|
||||||
|
...accounts.filter((account, index) => index !== currentIndex),
|
||||||
|
];
|
||||||
|
|
||||||
|
switch (selectedNetwork.namespace) {
|
||||||
|
case EIP155:
|
||||||
|
return {
|
||||||
|
eip155: {
|
||||||
|
chains: [namespaceChainId],
|
||||||
|
// TODO: Debug optional namespace methods and events being required for approval
|
||||||
|
methods: [
|
||||||
|
...Object.values(EIP155_SIGNING_METHODS),
|
||||||
|
...Object.values(NETWORK_METHODS),
|
||||||
|
...(optionalNamespaces.eip155?.methods ?? []),
|
||||||
|
...(requiredNamespaces.eip155?.methods ?? []),
|
||||||
|
],
|
||||||
|
events: [
|
||||||
|
...(optionalNamespaces.eip155?.events ?? []),
|
||||||
|
...(requiredNamespaces.eip155?.events ?? []),
|
||||||
|
],
|
||||||
|
accounts: sortedAccounts.map(ethAccount => {
|
||||||
|
return `${namespaceChainId}:${ethAccount.address}`;
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
cosmos: {
|
||||||
|
chains: [],
|
||||||
|
methods: [],
|
||||||
|
events: [],
|
||||||
|
accounts: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case COSMOS:
|
||||||
|
return {
|
||||||
|
cosmos: {
|
||||||
|
chains: [namespaceChainId],
|
||||||
|
methods: [
|
||||||
|
...Object.values(COSMOS_METHODS),
|
||||||
|
...Object.values(NETWORK_METHODS),
|
||||||
|
...(optionalNamespaces.cosmos?.methods ?? []),
|
||||||
|
...(requiredNamespaces.cosmos?.methods ?? []),
|
||||||
|
],
|
||||||
|
events: [
|
||||||
|
...(optionalNamespaces.cosmos?.events ?? []),
|
||||||
|
...(requiredNamespaces.cosmos?.events ?? []),
|
||||||
|
],
|
||||||
|
accounts: sortedAccounts.map(cosmosAccount => {
|
||||||
|
return `${namespaceChainId}:${cosmosAccount.address}`;
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
eip155: {
|
||||||
|
chains: [],
|
||||||
|
methods: [],
|
||||||
|
events: [],
|
||||||
|
accounts: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user