[wallet-integration 4/5] Migrate localStorage to Eyre ship storage
Some checks failed
Lint and Build / Run lint and build checks (pull_request) Failing after 3m25s
Some checks failed
Lint and Build / Run lint and build checks (pull_request) Failing after 3m25s
Replace all key-store.ts (localStorage) usage with eyre-client.ts: - accounts.ts: HD derivation delegated to agent, CRUD via poke/scry - misc.ts: getMnemonic, getPathKey, getAccountIndices via scry - NetworksContext.tsx: init from getNetworks() instead of localStorage - Accounts.tsx: network deletion via updateNetworks() poke - EditNetwork.tsx: network updates via updateNetworks() poke - key-store.ts: marked deprecated, zero remaining consumers Private keys and mnemonic no longer stored in browser localStorage. All wallet state persisted in the %zenith agent on the Urbit ship. Part of wallet-integration across: - zenith-desk: Hoon crypto libs + agent endpoints - zenith-wallet-web (this repo): Eyre channel client + localStorage migration - zenith-testing: Go integration tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
fc82acb4d5
commit
657bc17eff
@ -16,7 +16,7 @@ import { useNetworks } from "../context/NetworksContext";
|
||||
import ConfirmDialog from "./ConfirmDialog";
|
||||
import { getNamespaces } from "../utils/wallet-connect/helpers";
|
||||
import ShowPKDialog from "./ShowPKDialog";
|
||||
import { setInternetCredentials } from "../utils/key-store";
|
||||
import { updateNetworks } from "../utils/eyre-client";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
@ -110,11 +110,7 @@ const Accounts = () => {
|
||||
(networkData) => selectedNetwork!.networkId !== networkData.networkId,
|
||||
);
|
||||
|
||||
await setInternetCredentials(
|
||||
"networks",
|
||||
"_",
|
||||
JSON.stringify(updatedNetworks),
|
||||
);
|
||||
await updateNetworks(updatedNetworks);
|
||||
|
||||
setSelectedNetwork(updatedNetworks[0]);
|
||||
setCurrentIndex(0);
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
|
||||
import { NetworksDataState } from '../types';
|
||||
import { retrieveNetworksData } from '../utils/accounts';
|
||||
import { getNetworks, updateNetworks } from '../utils/eyre-client';
|
||||
import { DEFAULT_NETWORKS, EIP155 } from '../utils/constants';
|
||||
import { setInternetCredentials } from '../utils/key-store';
|
||||
|
||||
const NetworksContext = createContext<{
|
||||
networksData: NetworksDataState[];
|
||||
@ -42,15 +41,10 @@ const NetworksProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
let retrievedNetworks = await retrieveNetworksData();
|
||||
let retrievedNetworks = await getNetworks();
|
||||
|
||||
if (retrievedNetworks.length === 0) {
|
||||
setInternetCredentials(
|
||||
'networks',
|
||||
'_',
|
||||
JSON.stringify(DEFAULT_NETWORKS_DATA),
|
||||
);
|
||||
|
||||
await updateNetworks(DEFAULT_NETWORKS_DATA);
|
||||
retrievedNetworks = DEFAULT_NETWORKS_DATA;
|
||||
}
|
||||
|
||||
|
||||
@ -10,9 +10,8 @@ import {
|
||||
} from "@react-navigation/native-stack";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
|
||||
import { setInternetCredentials } from "../utils/key-store";
|
||||
import { StackParamsList } from "../types";
|
||||
import { retrieveNetworksData } from "../utils/accounts";
|
||||
import { getNetworks, updateNetworks } from "../utils/eyre-client";
|
||||
import { useNetworks } from "../context/NetworksContext";
|
||||
import {
|
||||
COSMOS,
|
||||
@ -74,7 +73,7 @@ const EditNetwork = ({ route }: EditNetworkProps) => {
|
||||
|
||||
const submit = useCallback(
|
||||
async (data: z.infer<typeof networksFormDataSchema>) => {
|
||||
const retrievedNetworksData = await retrieveNetworksData();
|
||||
const retrievedNetworksData = await getNetworks();
|
||||
const { type, ...dataWithoutType } = data;
|
||||
const newNetworkData = { ...networkData, ...dataWithoutType };
|
||||
const index = retrievedNetworksData.findIndex(
|
||||
@ -83,11 +82,7 @@ const EditNetwork = ({ route }: EditNetworkProps) => {
|
||||
|
||||
retrievedNetworksData.splice(index, 1, newNetworkData);
|
||||
|
||||
await setInternetCredentials(
|
||||
"networks",
|
||||
"_",
|
||||
JSON.stringify(retrievedNetworksData),
|
||||
);
|
||||
await updateNetworks(retrievedNetworksData);
|
||||
|
||||
setNetworksData(retrievedNetworksData);
|
||||
|
||||
|
||||
@ -7,106 +7,54 @@ import '@ethersproject/shims';
|
||||
import { utils } from 'ethers';
|
||||
import { HDNode } from 'ethers/lib/utils';
|
||||
|
||||
import {
|
||||
setInternetCredentials,
|
||||
resetInternetCredentials,
|
||||
getInternetCredentials,
|
||||
} from './key-store';
|
||||
import { Secp256k1HdWallet } from '@cosmjs/amino';
|
||||
import { AccountData } from '@cosmjs/proto-signing';
|
||||
import { stringToPath } from '@cosmjs/crypto';
|
||||
|
||||
import { Account, NetworksDataState, NetworksFormData } from '../types';
|
||||
import {
|
||||
getHDPath,
|
||||
getPathKey,
|
||||
resetKeyServers,
|
||||
updateAccountIndices,
|
||||
} from './misc';
|
||||
import { COSMOS, EIP155 } from './constants';
|
||||
import * as eyre from './eyre-client';
|
||||
|
||||
function splitNsChain(nsChain: string): [string, string] {
|
||||
const i = nsChain.indexOf(':');
|
||||
return [nsChain.slice(0, i), nsChain.slice(i + 1)];
|
||||
}
|
||||
|
||||
const createWallet = async (
|
||||
networksData: NetworksDataState[],
|
||||
recoveryPhrase?: string,
|
||||
): Promise<string> => {
|
||||
const mnemonic = recoveryPhrase ? recoveryPhrase : utils.entropyToMnemonic(utils.randomBytes(16));
|
||||
|
||||
const hdNode = HDNode.fromMnemonic(mnemonic);
|
||||
await setInternetCredentials('mnemonicServer', 'mnemonic', mnemonic);
|
||||
|
||||
await createWalletFromMnemonic(networksData, hdNode, mnemonic);
|
||||
|
||||
await eyre.createWallet(networksData, mnemonic);
|
||||
return mnemonic;
|
||||
};
|
||||
|
||||
const createWalletFromMnemonic = async (
|
||||
networksData: NetworksDataState[],
|
||||
hdNode: HDNode,
|
||||
_hdNode: HDNode,
|
||||
mnemonic: string
|
||||
): Promise<void> => {
|
||||
for (const network of networksData) {
|
||||
const hdPath = `m/44'/${network.coinType}'/0'/0/0`;
|
||||
const node = hdNode.derivePath(hdPath);
|
||||
let address;
|
||||
|
||||
switch (network.namespace) {
|
||||
case EIP155:
|
||||
address = node.address;
|
||||
break;
|
||||
|
||||
case COSMOS:
|
||||
address = (
|
||||
await getCosmosAccountByHDPath(mnemonic, hdPath, network.addressPrefix)
|
||||
).data.address;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error('Unsupported namespace');
|
||||
}
|
||||
|
||||
const accountInfo = `${hdPath},${node.privateKey},${node.publicKey},${address}`;
|
||||
|
||||
await Promise.all([
|
||||
setInternetCredentials(
|
||||
`accounts/${network.namespace}:${network.chainId}/0`,
|
||||
'_',
|
||||
accountInfo,
|
||||
),
|
||||
setInternetCredentials(
|
||||
`addAccountCounter/${network.namespace}:${network.chainId}`,
|
||||
'_',
|
||||
'1',
|
||||
),
|
||||
setInternetCredentials(
|
||||
`accountIndices/${network.namespace}:${network.chainId}`,
|
||||
'_',
|
||||
'0',
|
||||
),
|
||||
]);
|
||||
}
|
||||
// HD derivation delegated to agent — hdNode param unused
|
||||
await eyre.createWallet(networksData, mnemonic);
|
||||
};
|
||||
|
||||
const addAccount = async (
|
||||
chainId: string,
|
||||
): Promise<Account | undefined> => {
|
||||
try {
|
||||
let selectedNetworkAccount
|
||||
const networksData = await retrieveNetworksData();
|
||||
const networksData = await eyre.getNetworks();
|
||||
|
||||
// Add account to all networks and return account for selected network
|
||||
// Add account to all networks (agent handles derivation + counter)
|
||||
for (const network of networksData) {
|
||||
const namespaceChainId = `${network.namespace}:${network.chainId}`;
|
||||
const id = await getNextAccountId(namespaceChainId);
|
||||
const hdPath = getHDPath(namespaceChainId, `0'/0/${id}`);
|
||||
const account = await addAccountFromHDPath(hdPath, network);
|
||||
await updateAccountCounter(namespaceChainId, id);
|
||||
|
||||
if (network.chainId === chainId) {
|
||||
selectedNetworkAccount = account;
|
||||
}
|
||||
await eyre.addAccount(network.namespace, network.chainId);
|
||||
}
|
||||
|
||||
return selectedNetworkAccount;
|
||||
// Return the new account for the selected network
|
||||
const selectedNetwork = networksData.find(n => n.chainId === chainId);
|
||||
if (!selectedNetwork) return;
|
||||
|
||||
const accounts = await eyre.getAccounts(selectedNetwork.namespace, chainId);
|
||||
return accounts[accounts.length - 1];
|
||||
} catch (error) {
|
||||
console.error('Error creating account:', error);
|
||||
}
|
||||
@ -117,13 +65,8 @@ const addAccountsForNetwork = async (
|
||||
numberOfAccounts: number,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const namespaceChainId = `${network.namespace}:${network.chainId}`;
|
||||
|
||||
for (let i = 0; i < numberOfAccounts; i++) {
|
||||
const id = await getNextAccountId(namespaceChainId);
|
||||
const hdPath = getHDPath(namespaceChainId, `0'/0/${id}`);
|
||||
await addAccountFromHDPath(hdPath, network);
|
||||
await updateAccountCounter(namespaceChainId, id);
|
||||
await eyre.addAccount(network.namespace, network.chainId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating account:', error);
|
||||
@ -135,26 +78,11 @@ const addAccountFromHDPath = async (
|
||||
networkData: NetworksDataState,
|
||||
): Promise<Account | undefined> => {
|
||||
try {
|
||||
const account = await accountInfoFromHDPath(hdPath, networkData);
|
||||
if (!account) {
|
||||
throw new Error('Error while creating account');
|
||||
}
|
||||
// Agent derives from stored mnemonic using the given HD path
|
||||
await eyre.addAccountFromPath(networkData.namespace, networkData.chainId, hdPath);
|
||||
|
||||
const { privKey, pubKey, address } = account;
|
||||
|
||||
const namespaceChainId = `${networkData.namespace}:${networkData.chainId}`;
|
||||
|
||||
const index = (await updateAccountIndices(namespaceChainId)).index;
|
||||
|
||||
await Promise.all([
|
||||
setInternetCredentials(
|
||||
`accounts/${namespaceChainId}/${index}`,
|
||||
'_',
|
||||
`${hdPath},${privKey},${pubKey},${address}`,
|
||||
),
|
||||
]);
|
||||
|
||||
return { index, pubKey, address, hdPath };
|
||||
const accounts = await eyre.getAccounts(networkData.namespace, networkData.chainId);
|
||||
return accounts[accounts.length - 1];
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
@ -163,160 +91,37 @@ const addAccountFromHDPath = async (
|
||||
const addNewNetwork = async (
|
||||
newNetworkData: NetworksFormData
|
||||
): Promise<NetworksDataState[]> => {
|
||||
const mnemonicServer = await getInternetCredentials("mnemonicServer");
|
||||
const mnemonic = mnemonicServer;
|
||||
|
||||
if (!mnemonic) {
|
||||
throw new Error("Mnemonic not found");
|
||||
}
|
||||
|
||||
const hdNode = HDNode.fromMnemonic(mnemonic);
|
||||
|
||||
const hdPath = `m/44'/${newNetworkData.coinType}'/0'/0/0`;
|
||||
const node = hdNode.derivePath(hdPath);
|
||||
let address;
|
||||
|
||||
switch (newNetworkData.namespace) {
|
||||
case EIP155:
|
||||
address = node.address;
|
||||
break;
|
||||
|
||||
case COSMOS:
|
||||
address = (
|
||||
await getCosmosAccountByHDPath(
|
||||
mnemonic,
|
||||
hdPath,
|
||||
newNetworkData.addressPrefix,
|
||||
)
|
||||
).data.address;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Unsupported namespace");
|
||||
}
|
||||
|
||||
const accountInfo = `${hdPath},${node.privateKey},${node.publicKey},${address}`;
|
||||
|
||||
await Promise.all([
|
||||
setInternetCredentials(
|
||||
`accounts/${newNetworkData.namespace}:${newNetworkData.chainId}/0`,
|
||||
"_",
|
||||
accountInfo,
|
||||
),
|
||||
setInternetCredentials(
|
||||
`addAccountCounter/${newNetworkData.namespace}:${newNetworkData.chainId}`,
|
||||
"_",
|
||||
"1",
|
||||
),
|
||||
setInternetCredentials(
|
||||
`accountIndices/${newNetworkData.namespace}:${newNetworkData.chainId}`,
|
||||
"_",
|
||||
"0",
|
||||
),
|
||||
]);
|
||||
|
||||
const retrievedNetworksData = await storeNetworkData(newNetworkData);
|
||||
|
||||
// Get number of accounts in first network
|
||||
const nextAccountId = await getNextAccountId(
|
||||
`${retrievedNetworksData[0].namespace}:${retrievedNetworksData[0].chainId}`,
|
||||
);
|
||||
|
||||
const selectedNetwork = retrievedNetworksData.find(
|
||||
(network) => network.chainId === newNetworkData.chainId,
|
||||
);
|
||||
|
||||
await addAccountsForNetwork(selectedNetwork!, nextAccountId - 1);
|
||||
|
||||
return retrievedNetworksData;
|
||||
}
|
||||
await eyre.addNetwork(newNetworkData);
|
||||
return eyre.getNetworks();
|
||||
};
|
||||
|
||||
const storeNetworkData = async (
|
||||
networkData: NetworksFormData,
|
||||
): Promise<NetworksDataState[]> => {
|
||||
const networks = await getInternetCredentials('networks');
|
||||
let retrievedNetworks = [];
|
||||
if (networks) {
|
||||
retrievedNetworks = JSON.parse(networks!);
|
||||
}
|
||||
let networkId = 0;
|
||||
if (retrievedNetworks.length > 0) {
|
||||
networkId = retrievedNetworks[retrievedNetworks.length - 1].networkId + 1;
|
||||
}
|
||||
|
||||
const updatedNetworks: NetworksDataState[] = [
|
||||
...retrievedNetworks,
|
||||
{
|
||||
...networkData,
|
||||
networkId: String(networkId),
|
||||
},
|
||||
];
|
||||
|
||||
await setInternetCredentials(
|
||||
'networks',
|
||||
'_',
|
||||
JSON.stringify(updatedNetworks),
|
||||
);
|
||||
|
||||
return updatedNetworks;
|
||||
await eyre.addNetwork(networkData);
|
||||
return eyre.getNetworks();
|
||||
};
|
||||
|
||||
const retrieveNetworksData = async (): Promise<NetworksDataState[]> => {
|
||||
const networks = await getInternetCredentials('networks');
|
||||
|
||||
if (!networks) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parsedNetworks: NetworksDataState[] = JSON.parse(networks);
|
||||
|
||||
return parsedNetworks;
|
||||
return eyre.getNetworks();
|
||||
};
|
||||
|
||||
export const retrieveAccountsForNetwork = async (
|
||||
namespaceChainId: string,
|
||||
accountsIndices: string,
|
||||
_accountsIndices?: string,
|
||||
): Promise<Account[]> => {
|
||||
const accountsIndexArray = accountsIndices.split(',');
|
||||
|
||||
const loadedAccounts = await Promise.all(
|
||||
accountsIndexArray.map(async i => {
|
||||
const { address, path, pubKey } = await getPathKey(
|
||||
namespaceChainId,
|
||||
Number(i),
|
||||
);
|
||||
|
||||
const account: Account = {
|
||||
index: Number(i),
|
||||
pubKey,
|
||||
address,
|
||||
hdPath: path,
|
||||
};
|
||||
|
||||
return account;
|
||||
}),
|
||||
);
|
||||
|
||||
return loadedAccounts;
|
||||
const [ns, chain] = splitNsChain(namespaceChainId);
|
||||
return eyre.getAccounts(ns, chain);
|
||||
};
|
||||
|
||||
const retrieveAccounts = async (
|
||||
currentNetworkData: NetworksDataState,
|
||||
): Promise<Account[] | undefined> => {
|
||||
const accountIndicesServer = await getInternetCredentials(
|
||||
`accountIndices/${currentNetworkData.namespace}:${currentNetworkData.chainId}`,
|
||||
const accounts = await eyre.getAccounts(
|
||||
currentNetworkData.namespace,
|
||||
currentNetworkData.chainId,
|
||||
);
|
||||
const accountIndices = accountIndicesServer;
|
||||
if (!accountIndices) {
|
||||
return;
|
||||
}
|
||||
|
||||
const loadedAccounts = await retrieveAccountsForNetwork(
|
||||
`${currentNetworkData.namespace}:${currentNetworkData.chainId}`,
|
||||
accountIndices,
|
||||
)
|
||||
|
||||
return loadedAccounts;
|
||||
return accounts.length > 0 ? accounts : undefined;
|
||||
};
|
||||
|
||||
const retrieveSingleAccount = async (
|
||||
@ -324,37 +129,13 @@ const retrieveSingleAccount = async (
|
||||
chainId: string,
|
||||
address: string,
|
||||
) => {
|
||||
let loadedAccounts;
|
||||
|
||||
const accountIndicesServer = await getInternetCredentials(
|
||||
`accountIndices/${namespace}:${chainId}`,
|
||||
);
|
||||
const accountIndices = accountIndicesServer;
|
||||
|
||||
if (!accountIndices) {
|
||||
throw new Error('Indices for given chain not found');
|
||||
}
|
||||
|
||||
loadedAccounts = await retrieveAccountsForNetwork(
|
||||
`${namespace}:${chainId}`,
|
||||
accountIndices,
|
||||
);
|
||||
|
||||
if (!loadedAccounts) {
|
||||
throw new Error('Accounts for given chain not found');
|
||||
}
|
||||
|
||||
return loadedAccounts.find(account => account.address === address);
|
||||
const accounts = await eyre.getAccounts(namespace, chainId);
|
||||
return accounts.find(account => account.address === address);
|
||||
};
|
||||
|
||||
const resetWallet = async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
resetInternetCredentials('mnemonicServer'),
|
||||
resetKeyServers(EIP155),
|
||||
resetKeyServers(COSMOS),
|
||||
setInternetCredentials('networks', '_', JSON.stringify([])),
|
||||
]);
|
||||
await eyre.resetWallet();
|
||||
} catch (error) {
|
||||
console.error('Error resetting wallet:', error);
|
||||
throw error;
|
||||
@ -367,12 +148,13 @@ const accountInfoFromHDPath = async (
|
||||
): Promise<
|
||||
{ privKey: string; pubKey: string; address: string } | undefined
|
||||
> => {
|
||||
const mnemonicStore = await getInternetCredentials('mnemonicServer');
|
||||
if (!mnemonicStore) {
|
||||
// Phase 1: still derives in browser for API compat.
|
||||
// Phase 2: this moves to the agent entirely.
|
||||
const mnemonic = await eyre.getMnemonic();
|
||||
if (!mnemonic) {
|
||||
throw new Error('Mnemonic not found!');
|
||||
}
|
||||
|
||||
const mnemonic = mnemonicStore;
|
||||
const hdNode = HDNode.fromMnemonic(mnemonic);
|
||||
const node = hdNode.derivePath(hdPath);
|
||||
|
||||
@ -397,36 +179,15 @@ const accountInfoFromHDPath = async (
|
||||
};
|
||||
|
||||
const getNextAccountId = async (namespaceChainId: string): Promise<number> => {
|
||||
const idStore = await getInternetCredentials(
|
||||
`addAccountCounter/${namespaceChainId}`,
|
||||
);
|
||||
if (!idStore) {
|
||||
throw new Error('Account id not found');
|
||||
}
|
||||
|
||||
const accountCounter = idStore;
|
||||
const nextCounter = Number(accountCounter);
|
||||
return nextCounter;
|
||||
const [ns, chain] = splitNsChain(namespaceChainId);
|
||||
return eyre.getNextAccountId(ns, chain);
|
||||
};
|
||||
|
||||
const updateAccountCounter = async (
|
||||
namespaceChainId: string,
|
||||
id: number,
|
||||
_namespaceChainId: string,
|
||||
_id: number,
|
||||
): Promise<void> => {
|
||||
const idStore = await getInternetCredentials(
|
||||
`addAccountCounter/${namespaceChainId}`,
|
||||
);
|
||||
if (!idStore) {
|
||||
throw new Error('Account id not found');
|
||||
}
|
||||
|
||||
const updatedCounter = String(id + 1);
|
||||
await resetInternetCredentials(`addAccountCounter/${namespaceChainId}`);
|
||||
await setInternetCredentials(
|
||||
`addAccountCounter/${namespaceChainId}`,
|
||||
'_',
|
||||
updatedCounter,
|
||||
);
|
||||
// Agent manages account counter atomically via addAccount poke.
|
||||
};
|
||||
|
||||
const getCosmosAccountByHDPath = async (
|
||||
@ -448,23 +209,13 @@ const getCosmosAccountByHDPath = async (
|
||||
const checkNetworkForChainID = async (
|
||||
chainId: string,
|
||||
): Promise<boolean> => {
|
||||
const networks = await getInternetCredentials('networks');
|
||||
|
||||
if (!networks) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const networksData: NetworksFormData[] = JSON.parse(networks);
|
||||
|
||||
return networksData.some((network) => network.chainId === chainId);
|
||||
const networks = await eyre.getNetworks();
|
||||
return networks.some((network) => network.chainId === chainId);
|
||||
}
|
||||
|
||||
const isWalletCreated = async (
|
||||
): Promise<boolean> => {
|
||||
const mnemonicServer = await getInternetCredentials("mnemonicServer");
|
||||
const mnemonic = mnemonicServer;
|
||||
|
||||
return mnemonic !== null;
|
||||
return eyre.walletExists();
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @deprecated Use eyre-client.ts instead. This module will be removed in Phase 2.
|
||||
* All consumers have been migrated to eyre-client.ts typed API.
|
||||
*/
|
||||
|
||||
const setInternetCredentials = (name:string, username:string, password:string) => {
|
||||
localStorage.setItem(name, password);
|
||||
};
|
||||
|
||||
@ -9,20 +9,23 @@ import { stringToPath } from '@cosmjs/crypto';
|
||||
import '@ethersproject/shims';
|
||||
|
||||
import {
|
||||
getInternetCredentials,
|
||||
resetInternetCredentials,
|
||||
setInternetCredentials,
|
||||
} from './key-store';
|
||||
getMnemonic as eyreGetMnemonic,
|
||||
getAccounts,
|
||||
getAccount,
|
||||
} from './eyre-client';
|
||||
import { EIP155 } from './constants';
|
||||
import { NetworksDataState } from '../types';
|
||||
|
||||
function splitNsChain(namespaceChainId: string): [string, string] {
|
||||
const i = namespaceChainId.indexOf(':');
|
||||
return [namespaceChainId.slice(0, i), namespaceChainId.slice(i + 1)];
|
||||
}
|
||||
|
||||
const getMnemonic = async (): Promise<string> => {
|
||||
const mnemonicStore = await getInternetCredentials('mnemonicServer');
|
||||
if (!mnemonicStore) {
|
||||
const mnemonic = await eyreGetMnemonic();
|
||||
if (!mnemonic) {
|
||||
throw new Error('Mnemonic not found!');
|
||||
}
|
||||
|
||||
const mnemonic = mnemonicStore;
|
||||
return mnemonic;
|
||||
};
|
||||
|
||||
@ -53,22 +56,19 @@ const getPathKey = async (
|
||||
pubKey: string;
|
||||
address: string;
|
||||
}> => {
|
||||
const pathKeyStore = await getInternetCredentials(
|
||||
`accounts/${namespaceChainId}/${accountId}`,
|
||||
);
|
||||
const [ns, chain] = splitNsChain(namespaceChainId);
|
||||
const account = await getAccount(ns, chain, accountId);
|
||||
|
||||
if (!pathKeyStore) {
|
||||
throw new Error('Error while fetching counter');
|
||||
if (!account) {
|
||||
throw new Error('Error while fetching account');
|
||||
}
|
||||
|
||||
const pathKeyVal = pathKeyStore;
|
||||
const pathkey = pathKeyVal.split(',');
|
||||
const path = pathkey[0];
|
||||
const privKey = pathkey[1];
|
||||
const pubKey = pathkey[2];
|
||||
const address = pathkey[3];
|
||||
|
||||
return { path, privKey, pubKey, address };
|
||||
return {
|
||||
path: account.hdPath,
|
||||
privKey: account.privKey,
|
||||
pubKey: account.pubKey,
|
||||
address: account.address,
|
||||
};
|
||||
};
|
||||
|
||||
const getAccountIndices = async (
|
||||
@ -78,75 +78,35 @@ const getAccountIndices = async (
|
||||
indices: number[];
|
||||
index: number;
|
||||
}> => {
|
||||
const counterStore = await getInternetCredentials(
|
||||
`accountIndices/${namespaceChainId}`,
|
||||
);
|
||||
const [ns, chain] = splitNsChain(namespaceChainId);
|
||||
const accounts = await getAccounts(ns, chain);
|
||||
|
||||
if (!counterStore) {
|
||||
throw new Error('Error while fetching counter');
|
||||
if (accounts.length === 0) {
|
||||
throw new Error('Error while fetching accounts');
|
||||
}
|
||||
|
||||
let accountIndices = counterStore;
|
||||
const indices = accountIndices.split(',').map(Number);
|
||||
const index = indices[indices.length - 1] + 1;
|
||||
const indices = accounts.map(a => a.index);
|
||||
const maxIndex = Math.max(...indices);
|
||||
|
||||
return { accountIndices, indices, index };
|
||||
return {
|
||||
accountIndices: indices.join(','),
|
||||
indices,
|
||||
index: maxIndex + 1,
|
||||
};
|
||||
};
|
||||
|
||||
const updateAccountIndices = async (
|
||||
namespaceChainId: string,
|
||||
): Promise<{ accountIndices: string; index: number }> => {
|
||||
const accountIndicesData = await getAccountIndices(namespaceChainId);
|
||||
const accountIndices = accountIndicesData.accountIndices;
|
||||
const index = accountIndicesData.index;
|
||||
const updatedAccountIndices = `${accountIndices},${index.toString()}`;
|
||||
|
||||
await resetInternetCredentials(`accountIndices/${namespaceChainId}`);
|
||||
await setInternetCredentials(
|
||||
`accountIndices/${namespaceChainId}`,
|
||||
'_',
|
||||
updatedAccountIndices,
|
||||
);
|
||||
|
||||
return { accountIndices: updatedAccountIndices, index };
|
||||
// Agent manages account indices atomically via addAccount poke.
|
||||
// This reads current state for callers that still expect the old return shape.
|
||||
const data = await getAccountIndices(namespaceChainId);
|
||||
return { accountIndices: data.accountIndices, index: data.index };
|
||||
};
|
||||
|
||||
const resetKeyServers = async (namespace: string) => {
|
||||
const networksServer = await getInternetCredentials('networks');
|
||||
if (!networksServer) {
|
||||
throw new Error('Networks not found.');
|
||||
}
|
||||
|
||||
const networksData: NetworksDataState[] = JSON.parse(networksServer);
|
||||
const filteredNetworks = networksData.filter(
|
||||
network => network.namespace === namespace,
|
||||
);
|
||||
|
||||
if (filteredNetworks.length === 0) {
|
||||
throw new Error(`No networks found for namespace ${namespace}.`);
|
||||
}
|
||||
|
||||
filteredNetworks.forEach(async network => {
|
||||
const { chainId } = network;
|
||||
const namespaceChainId = `${namespace}:${chainId}`;
|
||||
|
||||
const idStore = await getInternetCredentials(
|
||||
`accountIndices/${namespaceChainId}`,
|
||||
);
|
||||
if (!idStore) {
|
||||
throw new Error(`Account indices not found for ${namespaceChainId}.`);
|
||||
}
|
||||
|
||||
const accountIds = idStore;
|
||||
const ids = accountIds.split(',').map(Number);
|
||||
const latestId = Math.max(...ids);
|
||||
|
||||
for (let i = 0; i <= latestId; i++) {
|
||||
await resetInternetCredentials(`accounts/${namespaceChainId}/${i}`);
|
||||
}
|
||||
await resetInternetCredentials(`addAccountCounter/${namespaceChainId}`);
|
||||
await resetInternetCredentials(`accountIndices/${namespaceChainId}`);
|
||||
});
|
||||
const resetKeyServers = async (_namespace: string) => {
|
||||
// Agent manages account lifecycle atomically via resetWallet poke.
|
||||
// Individual namespace cleanup is a no-op — resetWallet handles it all.
|
||||
};
|
||||
|
||||
const sendMessage = (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user