diff --git a/.env.example b/.env.example index 56d4917..afbe374 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,4 @@ INFURA_ID= -PORTIS_ID= \ No newline at end of file +PORTIS_ID= +TENDERLY_FORK_PATH= +TENDERLY_KEY= \ No newline at end of file diff --git a/composables/useBalances.ts b/composables/useBalances.ts index 1ee630f..ed6ff63 100644 --- a/composables/useBalances.ts +++ b/composables/useBalances.ts @@ -2,7 +2,8 @@ import { computed, reactive, onMounted, - useContext + useContext, + watch } from "@nuxtjs/composition-api"; import BigNumber from "bignumber.js"; import abis from "~/constant/abis"; @@ -14,7 +15,6 @@ import { Network } from "./useNetwork"; import { useWeb3 } from "./useWeb3"; import Web3 from "web3"; import { AbiItem } from "web3-utils"; -import { mainnetWeb3, polygonWeb3 } from "~/utils/web3"; import { useToken } from "./useToken"; import { useBigNumber } from "./useBigNumber"; import { useSorting } from "./useSorting"; @@ -32,7 +32,7 @@ const prices = reactive({ export function useBalances() { const { $axios } = useContext(); const { times, plus, ensureValue } = useBigNumber(); - const { account, networkName } = useWeb3(); + const { account, networkName, web3 } = useWeb3(); const { activeAccount } = useDSA(); const { getTokenByKey } = useToken(); const { by } = useSorting(); @@ -46,23 +46,35 @@ export function useBalances() { const fetchBalances = async (refresh = false) => { if (!balances.user || refresh) { balances.user = { - mainnet: await getBalances(account.value, Network.Mainnet, mainnetWeb3), - polygon: await getBalances(account.value, Network.Polygon, polygonWeb3) + mainnet: + networkName.value === Network.Mainnet + ? await getBalances(account.value, Network.Mainnet, web3.value) + : {}, + polygon: + networkName.value === Network.Polygon + ? await getBalances(account.value, Network.Polygon, web3.value) + : {} }; } if (!balances.dsa || refresh) { balances.dsa = { - mainnet: await getBalances( - activeAccount.value.address, - Network.Mainnet, - mainnetWeb3 - ), - polygon: await getBalances( - activeAccount.value.address, - Network.Polygon, - polygonWeb3 - ) + mainnet: + networkName.value === Network.Mainnet + ? await getBalances( + activeAccount.value.address, + Network.Mainnet, + web3.value + ) + : {}, + polygon: + networkName.value === Network.Polygon + ? await getBalances( + activeAccount.value.address, + Network.Polygon, + web3.value + ) + : {} }; } }; @@ -110,6 +122,11 @@ export function useBalances() { .sort(by("-netWorth")); }; + watch(web3, () => { + console.log("Fetch balances"); + + fetchBalances(true); + }); return { balances, fetchBalances, @@ -127,6 +144,8 @@ async function getBalances( web3: Web3, additionalTokens = [] ) { + console.log("getBalances", owner, network, web3); + try { const tokenResolverABI = abis.resolver.balance; const tokenResolverAddr = addresses[network].resolver.balance; diff --git a/composables/useDSA.ts b/composables/useDSA.ts index c04c2a5..8f05331 100644 --- a/composables/useDSA.ts +++ b/composables/useDSA.ts @@ -12,7 +12,7 @@ export function useDSA() { watch( web3, - () => { + () => { if (web3.value) { dsa.value = new DSA(web3.value, chainId.value); } @@ -38,6 +38,8 @@ export function useDSA() { activeAccount.value = accounts.value[0]; } } + //@ts-ignore + window.dsa = dsa.value } ); diff --git a/composables/useNetwork.ts b/composables/useNetwork.ts index 3196065..e99d356 100644 --- a/composables/useNetwork.ts +++ b/composables/useNetwork.ts @@ -14,7 +14,7 @@ export enum Network { export const networks = [ { id: "mainnet", chainId: 1, name: "Mainnet", icon: MainnetSVG }, - { id: "polygon", chainId: 136, name: "Polygon", icon: PolygonSVG } + { id: "polygon", chainId: 137, name: "Polygon", icon: PolygonSVG } ]; export const activeNetworkId = ref(); @@ -23,7 +23,6 @@ export const activeNetwork = computed( ); export function useNetwork() { - const { showWarning } = useNotification(); const { account, networkName, refreshWeb3 } = useWeb3(); const { showNetworksMismatchDialog } = useModal(); @@ -108,15 +107,18 @@ export function useNetwork() { } watch(activeNetworkId, () => { - localStorage.setItem('network', activeNetworkId.value) - }) + localStorage.setItem("network", activeNetworkId.value); + }); - onMounted( () => { + onMounted(() => { + if (activeNetworkId.value) { + return; + } //@ts-ignore - activeNetworkId.value = localStorage.getItem('network') || "mainnet"; + activeNetworkId.value = localStorage.getItem("network") || "mainnet"; - refreshWeb3() - }) + refreshWeb3(); + }); return { networkMismatch, diff --git a/composables/useTenderly.ts b/composables/useTenderly.ts new file mode 100644 index 0000000..40ec67d --- /dev/null +++ b/composables/useTenderly.ts @@ -0,0 +1,104 @@ +import { useContext, ref, onMounted, computed } from "@nuxtjs/composition-api"; +import axios from "axios"; +import { activeNetwork, useNetwork } from "./useNetwork"; +import { useWeb3 } from "./useWeb3"; +import Web3 from "web3"; +import { useDSA } from "./useDSA"; + +const forkId = ref(null); +export function useTenderly() { + const { $config } = useContext(); + const { setWeb3, refreshWeb3 } = useWeb3(); + const { accounts } = useDSA(); + const canSimulate = computed( + () => $config.TENDERLY_FORK_PATH && $config.TENDERLY_KEY + ); + + onMounted(() => { + if (!canSimulate.value) { + return; + } + + setTimeout(() => { + setForkId(window.localStorage.getItem("forkId")); + }, 1000); + }); + + const startSimulation = async () => { + try { + const { data } = await axios({ + method: "post", + url: `https://api.tenderly.co/api/v1/account/${$config.TENDERLY_FORK_PATH}/fork`, + headers: { + "X-Access-key": $config.TENDERLY_KEY, + "Content-Type": "application/json" + }, + data: JSON.stringify({ + network_id: activeNetwork.value.chainId.toString() + }) + }); + + setForkId(data?.simulation_fork?.id); + if (data?.simulation_fork?.id) { + addBalance(); + } + } catch (error) { + stopSimulation(); + } + }; + + const stopSimulation = async () => { + try { + await axios({ + method: "delete", + url: `https://api.tenderly.co/api/v1/account/${$config.TENDERLY_FORK_PATH}/fork/${forkId.value}`, + headers: { + "X-Access-key": $config.TENDERLY_KEY, + "Content-Type": "application/json" + } + }); + } catch (error) {} + + forkId.value = null; + window.localStorage.removeItem("forkId"); + refreshWeb3(); + }; + + const setForkId = fork => { + if (!fork) { + stopSimulation(); + return; + } + + forkId.value = fork; + setWeb3( + new Web3( + new Web3.providers.HttpProvider( + `https://rpc.tenderly.co/fork/${forkId.value}` + ) + ) + ); + window.localStorage.setItem("forkId", forkId.value); + }; + + const addBalance = async () => { + await axios({ + method: "post", + url: `https://api.tenderly.co/api/v1/account/${$config.TENDERLY_FORK_PATH}/fork/${forkId.value}/balance`, + headers: { + "X-Access-key": $config.TENDERLY_KEY, + "Content-Type": "application/json" + }, + data: JSON.stringify({ + accounts: accounts.value.map(a => a.address) + }) + }); + }; + + return { + forkId, + canSimulate, + startSimulation, + stopSimulation + }; +} diff --git a/composables/useWeb3.ts b/composables/useWeb3.ts index 83a5af7..813671d 100644 --- a/composables/useWeb3.ts +++ b/composables/useWeb3.ts @@ -1,4 +1,4 @@ -import { computed, onMounted, ref } from "@nuxtjs/composition-api"; +import { computed, onMounted, ref, watch } from "@nuxtjs/composition-api"; import Web3 from "web3"; import Web3Modal from "web3modal"; import { Network } from "./useNetwork"; @@ -122,6 +122,14 @@ export function useWeb3() { web3.value = newWeb3; }; + const setWeb3 = (newWeb3: Web3) => { + web3.value = newWeb3; + } + + watch(web3, () => { + window.web3 = web3.value; + }) + return { account, chainId, @@ -130,6 +138,7 @@ export function useWeb3() { activate, deactivate, networkName, - refreshWeb3 + refreshWeb3, + setWeb3, }; } diff --git a/layouts/default.vue b/layouts/default.vue index 8c6e214..5d59d7e 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -79,11 +79,28 @@ Balance + +
+ + +