195 lines
6.4 KiB
TypeScript
195 lines
6.4 KiB
TypeScript
// 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[],
|
|
) => {
|
|
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;
|
|
}
|
|
// Check for unsupported chains
|
|
const networkChains = networksData.map(
|
|
network => `${network.namespace}:${network.chainId}`,
|
|
);
|
|
if (!walletConnectChains.every(chain => networkChains.includes(chain))) {
|
|
const unsupportedChains = walletConnectChains.filter(
|
|
chain => !networkChains.includes(chain),
|
|
);
|
|
throw new Error(`Unsupported chains : ${unsupportedChains.join(',')}`);
|
|
}
|
|
|
|
// 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();
|
|
|
|
// 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: requiredAddresses.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: requiredAddresses.filter(account => account.includes(COSMOS)),
|
|
},
|
|
};
|
|
|
|
return newNamespaces;
|
|
} else {
|
|
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: accounts.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: accounts.map(cosmosAccount => {
|
|
return `${namespaceChainId}:${cosmosAccount.address}`;
|
|
}),
|
|
},
|
|
eip155: {
|
|
chains: [],
|
|
methods: [],
|
|
events: [],
|
|
accounts: [],
|
|
},
|
|
};
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
};
|