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

add multichain and more #11

Merged
merged 40 commits into from
Sep 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
5d964ec
[ADD] getPrice ts file
alexandreTimal Aug 22, 2024
0eb29e9
Merge branch 'searchBar_newTokenAdress' of github.com:PoCInnovation/p…
alexandreTimal Aug 22, 2024
413fb31
[ADD] add multichain poc
Aug 23, 2024
39ff548
ok
alexandreTimal Aug 24, 2024
157082b
[ADD] add working multichain btn
Aug 27, 2024
1d55cfa
[ADD] add all function for tokens value, but need a debug
alexandreTimal Sep 1, 2024
eaf7f4a
push(multichain): sync changes to remote repo
Sep 4, 2024
1ad1cef
fix(multichain): fix undefined useStore() in Switchchain func
Sep 7, 2024
de9caf6
[ADD] new feature, get the value of the balance for a user
alexandreTimal Sep 9, 2024
5adf1cd
[ADD] getPrice ts file
alexandreTimal Aug 22, 2024
8d3577b
ok
alexandreTimal Aug 24, 2024
04a237f
[ADD] add all function for tokens value, but need a debug
alexandreTimal Sep 1, 2024
7e4d0d5
[ADD] new feature, get the value of the balance for a user
alexandreTimal Sep 9, 2024
ee7b1b5
Merge branch 'searchBar_newTokenAdress' of github.com:PoCInnovation/p…
alexandreTimal Sep 9, 2024
f0edc93
fix(multichain): add pubClient in store (switchChain not working yet)
Sep 10, 2024
8674ed9
feat(multichain): add multichain on transaction component
Sep 13, 2024
d15ea11
refactor(multichain): remove test lines
Sep 13, 2024
222b5ae
[ADD] get the eth value
alexandreTimal Sep 15, 2024
af03a4e
[FIX] css from passwordPage.vue
alexandreTimal Sep 15, 2024
8e686df
feat: adding the base of the component for the import pop up
Sep 15, 2024
39d14f8
feat: adding new mutations and getters to manage password
Sep 15, 2024
c1ae3ff
feat: store the password to the store
Sep 15, 2024
aa0e40f
fix: remove the storage of the mnemonic
Sep 15, 2024
60d55f7
feat: return the private key
Sep 15, 2024
bbbf4ed
feat: set the encrypted private key to the local storage
Sep 15, 2024
14fa580
[ADD] new css for the login page
alexandreTimal Sep 16, 2024
7b854c9
[ADD] sort tokens by balance value
alexandreTimal Sep 16, 2024
0ecda31
feat: adding importation feature
Sep 16, 2024
7800146
fix: bug who multiply acc when they was imported
Sep 16, 2024
659b466
style: remove useless console.loog
Sep 16, 2024
026706f
fix: remove password from store when document is hidden
Sep 16, 2024
83c8395
feat: adding a new component for the import cards
Sep 16, 2024
d947bd0
feat: adding the importation feature
Sep 16, 2024
b819513
style: remove unused function
Sep 18, 2024
c5fa061
Merge pull request #9 from PoCInnovation/import-acc
gregorsternat Sep 18, 2024
4473c3e
Merge pull request #8 from PoCInnovation/searchBar_newTokenAdress
Intermarch3 Sep 19, 2024
9e1f872
[MERGE] merge new components
Sep 19, 2024
0179bf3
[FIX] change all component for multichain
Sep 19, 2024
8be40cb
feat(multichain): add multichain on token component
Sep 22, 2024
8cde26f
Merge pull request #10 from PoCInnovation/multichain_dev
Intermarch3 Sep 22, 2024
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
502 changes: 502 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@scure/bip39": "^1.3.0",
"alchemy-sdk": "^3.3.1",
"axios": "^1.7.2",
"bignumber.js": "^9.1.2",
"crypto-js": "^4.2.0",
"crypto-ts": "^1.0.2",
"viem": "^2.14.2",
Expand All @@ -43,6 +44,7 @@
"postcss": "^8.4.38",
"prettier": "^3.2.5",
"tailwindcss": "^3.4.4",
"tsx": "^4.17.0",
"typescript": "~5.4.0",
"vite": "^5.2.8",
"vue-tsc": "^2.0.11"
Expand Down
Binary file added public/img/PrettyMetaMask.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/eth_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,28 @@
import ERC from "./components/main/ERC/ERC.vue";
import { onMounted, ref, onUnmounted } from "vue";
import passwordPage from "./components/passwordPage.vue";
import chainSwitcher from "./components/chainSwitcher.vue";
import { SwitchChain } from "./multichain";
import { useStore } from "vuex";

const open = ref(false)
const store = useStore()

onMounted(() => {
const isOpen = localStorage.getItem('open-wallet')
if (isOpen === 'true') {
open.value = true
}
// const store = useStore()
// SwitchChain(store)

setInterval(checkOpen, 5000);

const handleVisibilityChange = () => {
if (document.hidden) {
open.value = false;
localStorage.setItem('open-wallet', 'false');
store.dispatch('clearPassword')
}
};

Expand All @@ -42,6 +49,8 @@
<template>
<div v-if="open" id="container">
<header>
<div class="logo"><h1>✨Pretty-Metamask✨</h1></div>
<chainSwitcher />
</header>
<main>
<VerticalNavbar />
Expand Down Expand Up @@ -71,6 +80,13 @@
color: white;
width: 100vw;
border-bottom: 1px solid rgb(3, 3, 3);
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 5vw;
}
.logo {
font-size: 2.4rem;
}
main {
display: flex;
Expand Down
252 changes: 231 additions & 21 deletions src/alchemy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { AlchemyConfig } from "alchemy-sdk";
import { Network, Alchemy } from "alchemy-sdk";
import { Network, Alchemy, Utils } from "alchemy-sdk";
import { BigNumber } from 'bignumber.js';
import { getBalance } from './getBalance'

interface Config {
apiKey: string;
Expand All @@ -8,45 +10,253 @@ interface Config {

const config: Config = {
apiKey: 'aKVhzlNCwLMUs1hm_m7G3g00_vcuBkKh',
network: Network.ETH_SEPOLIA,
network: Network.ETH_MAINNET,
};

const alchemy = new Alchemy(config as AlchemyConfig);
interface CoinGeckoToken {
id: string;
symbol: string;
name: string;
image: string;
current_price: number;
market_cap: number;
market_cap_rank: number;
fully_diluted_valuation: number;
total_volume: number;
high_24h: number;
low_24h: number;
price_change_24h: number;
price_change_percentage_24h: number;
market_cap_change_24h: number;
market_cap_change_percentage_24h: number;
circulating_supply: number;
total_supply: number;
max_supply: number;
ath: number;
ath_change_percentage: number;
ath_date: string;
atl: number;
atl_change_percentage: number;
atl_date: string;
roi?: string;
last_updated: string;
price_change_percentage_1h?: number;
sparkline_in_7d?: {
price: number[];
};
}

type Token = {
id: string;
symbol: string;
name: string;
};

type BalanceToken = {
name: string;
logo: string;
balance: string;
symbol: string;
decimals: number;
balanceValue: string | null;
}

const options = {
method: 'GET',
headers: { accept: 'application/json' }
};


export const processAll = async (address_: `0x${string}`, network_: Network) => {

const balanceTokens: BalanceToken[] = await getBalances2(address_, network_);

await updateCoinGeckoTokensValue();
const map = new Map<string, string>();

balanceTokens.forEach(result => {
const symbol = result.symbol.toLowerCase();
const value = localStorage.getItem(symbol);
console.log(`symbol is ${symbol}, value ${value}`);
if (value !== null) {
map.set(symbol, value);
}
});
await setEth(address_, map, balanceTokens);
await getTokensValue(map, balanceTokens);
return balanceTokens.sort((a, b) => {
const aValue = a.balanceValue ? parseFloat(a.balanceValue) : 0;
const bValue = b.balanceValue ? parseFloat(b.balanceValue) : 0;
return bValue - aValue;
});
}

async function setEth(address_: `0x${string}`, map: Map<string, string>, balanceTokens: BalanceToken[]) {
const weiValue = await getBalance(address_ as string)

map.set('eth', 'ethereum');

export const getBalances = async (address: string) => {
const balanceEth: string = Utils.formatEther(weiValue);

balanceTokens.push({
name: 'Etherum',
logo: '/img/eth_logo.png',
balance: balanceEth,
symbol: 'eth',
decimals: 18,
balanceValue: null
});
}

async function getBalances2(address_: `0x${string}`, network: Network): Promise<BalanceToken[]> {
try {
const balances = await alchemy.core.getTokenBalances(address);
config.network = network;
const alchemy = new Alchemy(config as AlchemyConfig);
const balances = await alchemy.core.getTokenBalances(address_);
const nonZeroBalances = balances.tokenBalances.filter((token) => {
return token.tokenBalance !== "0x0000000000000000000000000000000000000000000000000000000000000000";
});

let i = 1;
const balanceResults = [];
const balanceResults: BalanceToken[] = [];

for (const token of nonZeroBalances) {
let balance: number = 0;
if (token.tokenBalance != null)
balance = parseInt(token.tokenBalance, 16);
let balance: BigNumber = new BigNumber(0);
if (token.tokenBalance != null) {
balance = new BigNumber(token.tokenBalance);
}

const metadata = await alchemy.core.getTokenMetadata(token.contractAddress);
console.log(`The logo is ${metadata.logo}`);
balance = balance / Math.pow(10, metadata.decimals ?? 1);
const balanceStr: string = balance.toFixed(2);
if (metadata.name == null || metadata.symbol == null) continue;

const decimals = metadata.decimals ?? 18;

const factor = new BigNumber(10).pow(decimals);
const formattedBalance = balance.div(factor).toFixed(2);

balanceResults.push({
name: metadata.name,
logo: metadata.logo,
balance: balanceStr,
logo: metadata.logo ? metadata.logo : 'img/question.png',
balance: formattedBalance,
symbol: metadata.symbol,
decimals: metadata.decimals
decimals: decimals,
balanceValue: null
});
console.log(`${i++}. ${metadata.name}: ${balanceStr} ${metadata.symbol} decimals is ${metadata.decimals}`);
}

return balanceResults;
return balanceResults

} catch (error) {
console.log(`${address}`)
console.log(`${address_}`)
console.error(`Failed to fetch token balances:`, error);
return [];
}
};
};

/**
* Set all CoinGecko tokens in localStorage with the format <symbol, id>.
* Also updates the 'Time' variable in localStorage to reflect the last update time.
*
* This function fetches the latest token data from CoinGecko and stores it
* in localStorage as a map of token symbols to their corresponding IDs.
*/
async function updateCoinGeckoTokensValue() {
try {
const apiUrl = 'https://api.coingecko.com/api/v3/coins/list';
const response = await fetch(apiUrl, options);
const tokens = await response.json();
if (localStorage.getItem("btc") || isMoreThanWeek())
return;

if (!Array.isArray(tokens)) {
throw new Error('Expected an array but received: ' + typeof tokens);
}
const tokenMap: Record<string, string> = tokens.reduce((map: Record<string, string>, token: Token) => {
map[token.symbol] = token.id;
console.log(`token symbol : ${token.symbol}, token id : ${token.id}`)
return map;
}, {} as Record<string, string>);
// console.log(tokenMap);
for (const [symbol, id] of Object.entries(tokenMap)) {
localStorage.setItem(symbol, id);
}
localStorage.setItem("TimeOfLastUpdate", Date.now().toString());
return;
} catch (err) {
console.error('Error fetching tokens:', err);
return {};
}
}

/**
* Get a string array of all wallets tokens symbol.
* fetch all data from the coingecko api and return a Map with sym.
*/
async function getTokensValue(id: Map<string, string> , balanceTokens: BalanceToken[]) {
try {
if (id == null) {
return;
}

const valueString = Array.from(id.values()).join(",");
console.log(`valueString is ${valueString}`);

const apiUrl = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=${valueString}&x_cg_demo_api_key=CG-X2ove9UTHLYyzyJYeYiQgY9T`;

const response = await fetch(apiUrl, options);

if (!response.ok) {
throw new Error(`Failed to fetch data: ${response.status} ${response.statusText}`);
}

const tokens: CoinGeckoToken[] = await response.json();

if (!Array.isArray(tokens)) {
throw new Error(`Expected an array but received: ${typeof tokens}`);
}

console.log("Data from coingecko is ready")
balanceTokens.forEach(token => {
const tokenId = id.get(token.symbol.toLowerCase());
if (tokenId) {
const matchingToken = tokens.find(t => t.id === tokenId);
if (matchingToken) {
if (typeof matchingToken.current_price === 'number') {
console.log(`Token ID: ${tokenId}, Current Price: ${matchingToken.current_price}`);
token.balanceValue = formatBalanceValue(matchingToken.current_price, parseInt(token.balance));
console.log(`The user have: ${token.balanceValue}$`);
} else {
console.warn(`Current price is invalid for token ID: ${tokenId}`);
token.balanceValue = null;
}
} else {
console.log(`There is not correspondence for ${tokenId}`);
}
}
});

} catch (err) {
console.error('Error fetching tokens:', err);
return;
}
}

function formatBalanceValue(price: number, quantity: number): string {
const result: number = price * quantity;

if (result > 10000)
return result.toExponential(3);
else
return result.toPrecision(2);
}

function isMoreThanWeek(): boolean {
const storedTime = localStorage.getItem('TimeOfLastUpdate');

if (!storedTime)
return false;

const storedTimestamp = parseInt(storedTime, 10);
const oneWeekInMilliseconds = 7 * 24 * 60 * 60 * 1000;
const currentTime = Date.now();

return currentTime < (storedTimestamp + oneWeekInMilliseconds);
}
Binary file removed src/assets/eth_logo.png
Binary file not shown.
7 changes: 0 additions & 7 deletions src/client.ts

This file was deleted.

Loading
Loading