Skip to content

Commit

Permalink
Fix outdated account id issue on testnet (#69)
Browse files Browse the repository at this point in the history
Signed-off-by: Kipkap <[email protected]>
  • Loading branch information
himalayan-dev authored Feb 1, 2024
1 parent 05a0726 commit 17863dd
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 114 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/hedera-metamask-snaps",
"version": "0.2.1",
"version": "0.2.2",
"description": "A collection of Hedera related Metamask snaps that expose and utilize Hedera functionality inside Metamask",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
Expand Down
2 changes: 1 addition & 1 deletion packages/hedera-wallet-snap/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/hedera-wallet-snap-monorepo",
"version": "0.2.1",
"version": "0.2.2",
"private": true,
"description": "Hedera Wallet Snap unlocks wallet functionality via Metamask that any other apps can interact with, thereby turning Metamask into a native Hedera wallet without relying on Hedera JSON-RPC Relay.",
"homepage": "https://github.com/hashgraph/hedera-metamask-snaps#readme",
Expand Down
2 changes: 1 addition & 1 deletion packages/hedera-wallet-snap/packages/site/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/hedera-wallet-snap-site",
"version": "0.2.1",
"version": "0.2.2",
"private": true,
"license": "Apache-2.0",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/hedera-wallet-snap/packages/snap/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/hedera-wallet-snap",
"version": "0.2.1",
"version": "0.2.2",
"description": "Hedera Wallet Snap unlocks wallet functionality via Metamask that any other apps can interact with, thereby turning Metamask into a native Hedera wallet without relying on Hedera JSON-RPC Relay.",
"keywords": [
"MetaMask",
Expand Down
4 changes: 2 additions & 2 deletions packages/hedera-wallet-snap/packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"version": "0.2.1",
"version": "0.2.2",
"description": "Hedera Wallet unlocks wallet functionality via Metamask that any other apps can interact with, thereby turning Metamask into a native Hedera wallet without relying on Hedera JSON-RPC Relay.",
"proposedName": "Hedera Wallet",
"repository": {
"type": "git",
"url": "git+https://github.com/hashgraph/hedera-metamask-snaps.git"
},
"source": {
"shasum": "ngYUkJdkHCbtJJ8B++HifOOgwX/eurIXyWrCCR5mknE=",
"shasum": "Qe/82uvBrHxaFLrIEnPSDC2C8L8GmiEi/O/SnM+pWTM=",
"location": {
"npm": {
"filePath": "dist/snap.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
} from '@hashgraph/sdk';
import _ from 'lodash';

import { StakingInfoJson } from '@hashgraph/sdk/lib/account/AccountInfo';
import { StakingInfoJson } from '@hashgraph/sdk/lib/StakingInfo';
import { providerErrors } from '@metamask/rpc-errors';
import { AccountInfo } from 'src/types/account';
import { Wallet } from '../../../domain/wallet/abstract';
Expand Down Expand Up @@ -141,23 +141,27 @@ export class HederaServiceImpl implements HederaService {

const response: FetchResponse = await fetchDataFromUrl(url);
if (!response.success) {
return [] as MirrorStakingInfo[];
return result;
}

for (const node of response.data.nodes) {
result.push(node);
}
try {
for (const node of response.data.nodes) {
result.push(node);
}

if (response.data.links.next) {
const secondUrl = `${this.mirrorNodeUrl}${
response.data.links.next as string
}`;
const secondResponse: FetchResponse = await fetchDataFromUrl(secondUrl);
if (secondResponse.success) {
for (const node of secondResponse.data.nodes) {
result.push(node);
if (response.data.links.next) {
const secondUrl = `${this.mirrorNodeUrl}${
response.data.links.next as string
}`;
const secondResponse: FetchResponse = await fetchDataFromUrl(secondUrl);
if (secondResponse.success) {
for (const node of secondResponse.data.nodes) {
result.push(node);
}
}
}
} catch (error: any) {
console.error('Error in getNodeStakingInfo:', String(error));
}

return result;
Expand All @@ -166,71 +170,80 @@ export class HederaServiceImpl implements HederaService {
async getMirrorAccountInfo(
idOrAliasOrEvmAddress: string,
): Promise<AccountInfo> {
let result = {} as MirrorAccountInfo;
const result = {} as AccountInfo;
const url = `${this.mirrorNodeUrl}/api/v1/accounts/${idOrAliasOrEvmAddress}`;
const response: FetchResponse = await fetchDataFromUrl(url);
if (!response.success) {
return {} as AccountInfo;
return result;
}

result = response.data as MirrorAccountInfo;

const hbars = result.balance.balance / 1e8;
const tokens: Record<string, TokenBalance> = {};
// Use map to create an array of promises
const tokenPromises = result.balance.tokens.map(async (token: Token) => {
const tokenId = token.token_id;
const tokenInfo: MirrorTokenInfo = await this.getTokenById(tokenId);
tokens[tokenId] = {
balance: token.balance / Math.pow(10, Number(tokenInfo.decimals)),
decimals: Number(tokenInfo.decimals),
tokenId,
name: tokenInfo.name,
symbol: tokenInfo.symbol,
tokenType: tokenInfo.type,
supplyType: tokenInfo.supply_type,
totalSupply: (
Number(tokenInfo.total_supply) /
Math.pow(10, Number(tokenInfo.decimals))
).toString(),
maxSupply: (
Number(tokenInfo.max_supply) /
Math.pow(10, Number(tokenInfo.decimals))
).toString(),
} as TokenBalance;
});

// Wait for all promises to resolve
await Promise.all(tokenPromises);

return {
accountId: result.account,
alias: result.alias,
createdTime: timestampToString(result.created_timestamp),
expirationTime: timestampToString(result.expiry_timestamp),
memo: result.memo,
evmAddress: result.evm_address,
key: {
type: result.key._type,
key: result.key.key,
},
balance: {
const mirrorNodeData = response.data as MirrorAccountInfo;

try {
result.accountId = mirrorNodeData.account;
result.alias = mirrorNodeData.alias;
result.createdTime = timestampToString(mirrorNodeData.created_timestamp);
result.expirationTime = timestampToString(
mirrorNodeData.expiry_timestamp,
);
result.memo = mirrorNodeData.memo;
result.evmAddress = mirrorNodeData.evm_address;
result.key = {
type: mirrorNodeData.key._type,
key: mirrorNodeData.key.key,
};
result.autoRenewPeriod = String(mirrorNodeData.auto_renew_period);
result.ethereumNonce = String(mirrorNodeData.ethereum_nonce);
result.isDeleted = mirrorNodeData.deleted;
result.stakingInfo = {
declineStakingReward: mirrorNodeData.decline_reward,
stakePeriodStart: timestampToString(mirrorNodeData.stake_period_start),
pendingReward: String(mirrorNodeData.pending_reward),
stakedToMe: '0', // TODO
stakedAccountId: mirrorNodeData.staked_account_id ?? '',
stakedNodeId: mirrorNodeData.staked_node_id ?? '',
} as StakingInfoJson;

const hbars = mirrorNodeData.balance.balance / 1e8;
const tokens: Record<string, TokenBalance> = {};
// Use map to create an array of promises
const tokenPromises = mirrorNodeData.balance.tokens.map(
async (token: Token) => {
const tokenId = token.token_id;
const tokenInfo: MirrorTokenInfo = await this.getTokenById(tokenId);
tokens[tokenId] = {
balance: token.balance / Math.pow(10, Number(tokenInfo.decimals)),
decimals: Number(tokenInfo.decimals),
tokenId,
name: tokenInfo.name,
symbol: tokenInfo.symbol,
tokenType: tokenInfo.type,
supplyType: tokenInfo.supply_type,
totalSupply: (
Number(tokenInfo.total_supply) /
Math.pow(10, Number(tokenInfo.decimals))
).toString(),
maxSupply: (
Number(tokenInfo.max_supply) /
Math.pow(10, Number(tokenInfo.decimals))
).toString(),
} as TokenBalance;
},
);

// Wait for all promises to resolve
await Promise.all(tokenPromises);

result.balance = {
hbars,
timestamp: timestampToString(result.balance.timestamp),
tokens,
} as AccountBalance,
autoRenewPeriod: String(result.auto_renew_period),
ethereumNonce: String(result.ethereum_nonce),
isDeleted: result.deleted,
stakingInfo: {
declineStakingReward: result.decline_reward,
stakePeriodStart: timestampToString(result.stake_period_start),
pendingReward: String(result.pending_reward),
stakedToMe: '0', // TODO
stakedAccountId: result.staked_account_id ?? '',
stakedNodeId: result.staked_node_id ?? '',
} as StakingInfoJson,
} as AccountInfo;
} as AccountBalance;
} catch (error: any) {
console.error('Error in getMirrorAccountInfo:', String(error));
}

return result;
}

async getTokenById(tokenId: string): Promise<MirrorTokenInfo> {
Expand Down Expand Up @@ -260,19 +273,23 @@ export class HederaServiceImpl implements HederaService {
return result;
}

result = response.data.transactions as MirrorTransactionInfo[];

result.forEach((transaction) => {
transaction.consensus_timestamp = timestampToString(
transaction.consensus_timestamp,
);
transaction.parent_consensus_timestamp = timestampToString(
transaction.parent_consensus_timestamp,
);
transaction.valid_start_timestamp = timestampToString(
transaction.valid_start_timestamp,
);
});
try {
result = response.data.transactions as MirrorTransactionInfo[];

result.forEach((transaction) => {
transaction.consensus_timestamp = timestampToString(
transaction.consensus_timestamp,
);
transaction.parent_consensus_timestamp = timestampToString(
transaction.parent_consensus_timestamp,
);
transaction.valid_start_timestamp = timestampToString(
transaction.valid_start_timestamp,
);
});
} catch (error: any) {
console.error('Error in getMirrorTransactions:', String(error));
}

return result;
}
Expand Down
45 changes: 22 additions & 23 deletions packages/hedera-wallet-snap/packages/snap/src/snap/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,31 +453,13 @@ export async function importMetaMaskAccount(
console.log('Retrieving account info from Hedera Mirror node');
const hederaService = new HederaServiceImpl(network, mirrorNodeUrl);
mirrorNodeUrl = hederaService.mirrorNodeUrl;
const accountInfo: AccountInfo = await hederaService.getMirrorAccountInfo(
let accountInfo: AccountInfo = await hederaService.getMirrorAccountInfo(
idOrAliasOrEvmAddress,
);
if (!_.isEmpty(accountInfo)) {
hederaAccountId = accountInfo.accountId;

// Make sure that the EVM address of this accountId matches the one on Hedera
if (accountInfo.evmAddress !== address) {
console.error(
`The Hedera account '${hederaAccountId}' is associated with the EVM address '${accountInfo.evmAddress}' but you tried to associate it with the address '${address}.`,
);
throw providerErrors.custom({
code: 4200,
message: `This Hedera account is associated with the EVM address '${accountInfo.evmAddress}' but you tried to associate it with the address '${address}.`,
data: hederaAccountId,
});
}

balance = accountInfo.balance;

// eslint-disable-next-line require-atomic-updates
state.accountState[connectedAddress][network].accountInfo = accountInfo;
if (_.isEmpty(accountInfo)) {
accountInfo = await hederaService.getMirrorAccountInfo(address);
}

if (_.isEmpty(hederaAccountId)) {
if (_.isEmpty(accountInfo)) {
/* const dialogParamsForHederaAccountId: SnapDialogParams = {
type: 'alert',
content: await generateCommonPanel(origin, [
Expand All @@ -491,7 +473,6 @@ export async function importMetaMaskAccount(
]),
};
await snapDialog(dialogParamsForHederaAccountId); */

console.error(
`This Hedera account is not yet active. Please activate it by sending some HBAR to this account. EVM Address: ${address}`,
);
Expand All @@ -501,6 +482,24 @@ export async function importMetaMaskAccount(
data: address,
});
}
hederaAccountId = accountInfo.accountId;

// Make sure that the EVM address of this accountId matches the one on Hedera
if (accountInfo.evmAddress !== address) {
console.error(
`The Hedera account '${hederaAccountId}' is associated with the EVM address '${accountInfo.evmAddress}' but you tried to associate it with the address '${address}.`,
);
throw providerErrors.custom({
code: 4200,
message: `This Hedera account is associated with the EVM address '${accountInfo.evmAddress}' but you tried to associate it with the address '${address}.`,
data: hederaAccountId,
});
}

balance = accountInfo.balance;

// eslint-disable-next-line require-atomic-updates
state.accountState[connectedAddress][network].accountInfo = accountInfo;
}

// eslint-disable-next-line require-atomic-updates
Expand Down

0 comments on commit 17863dd

Please sign in to comment.