Simulation

This commit is contained in:
Georges KABBOUCHI 2021-08-18 23:20:45 +03:00
parent ea3d16b276
commit ae6a4a7a81
9 changed files with 191 additions and 44 deletions

View File

@ -1,2 +1,4 @@
INFURA_ID= INFURA_ID=
PORTIS_ID= PORTIS_ID=
TENDERLY_FORK_PATH=
TENDERLY_KEY=

View File

@ -2,7 +2,8 @@ import {
computed, computed,
reactive, reactive,
onMounted, onMounted,
useContext useContext,
watch
} from "@nuxtjs/composition-api"; } from "@nuxtjs/composition-api";
import BigNumber from "bignumber.js"; import BigNumber from "bignumber.js";
import abis from "~/constant/abis"; import abis from "~/constant/abis";
@ -14,7 +15,6 @@ import { Network } from "./useNetwork";
import { useWeb3 } from "./useWeb3"; import { useWeb3 } from "./useWeb3";
import Web3 from "web3"; import Web3 from "web3";
import { AbiItem } from "web3-utils"; import { AbiItem } from "web3-utils";
import { mainnetWeb3, polygonWeb3 } from "~/utils/web3";
import { useToken } from "./useToken"; import { useToken } from "./useToken";
import { useBigNumber } from "./useBigNumber"; import { useBigNumber } from "./useBigNumber";
import { useSorting } from "./useSorting"; import { useSorting } from "./useSorting";
@ -32,7 +32,7 @@ const prices = reactive({
export function useBalances() { export function useBalances() {
const { $axios } = useContext(); const { $axios } = useContext();
const { times, plus, ensureValue } = useBigNumber(); const { times, plus, ensureValue } = useBigNumber();
const { account, networkName } = useWeb3(); const { account, networkName, web3 } = useWeb3();
const { activeAccount } = useDSA(); const { activeAccount } = useDSA();
const { getTokenByKey } = useToken(); const { getTokenByKey } = useToken();
const { by } = useSorting(); const { by } = useSorting();
@ -46,23 +46,35 @@ export function useBalances() {
const fetchBalances = async (refresh = false) => { const fetchBalances = async (refresh = false) => {
if (!balances.user || refresh) { if (!balances.user || refresh) {
balances.user = { balances.user = {
mainnet: await getBalances(account.value, Network.Mainnet, mainnetWeb3), mainnet:
polygon: await getBalances(account.value, Network.Polygon, polygonWeb3) 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) { if (!balances.dsa || refresh) {
balances.dsa = { balances.dsa = {
mainnet: await getBalances( mainnet:
activeAccount.value.address, networkName.value === Network.Mainnet
Network.Mainnet, ? await getBalances(
mainnetWeb3 activeAccount.value.address,
), Network.Mainnet,
polygon: await getBalances( web3.value
activeAccount.value.address, )
Network.Polygon, : {},
polygonWeb3 polygon:
) networkName.value === Network.Polygon
? await getBalances(
activeAccount.value.address,
Network.Polygon,
web3.value
)
: {}
}; };
} }
}; };
@ -110,6 +122,11 @@ export function useBalances() {
.sort(by("-netWorth")); .sort(by("-netWorth"));
}; };
watch(web3, () => {
console.log("Fetch balances");
fetchBalances(true);
});
return { return {
balances, balances,
fetchBalances, fetchBalances,
@ -127,6 +144,8 @@ async function getBalances(
web3: Web3, web3: Web3,
additionalTokens = [] additionalTokens = []
) { ) {
console.log("getBalances", owner, network, web3);
try { try {
const tokenResolverABI = abis.resolver.balance; const tokenResolverABI = abis.resolver.balance;
const tokenResolverAddr = addresses[network].resolver.balance; const tokenResolverAddr = addresses[network].resolver.balance;

View File

@ -38,6 +38,8 @@ export function useDSA() {
activeAccount.value = accounts.value[0]; activeAccount.value = accounts.value[0];
} }
} }
//@ts-ignore
window.dsa = dsa.value
} }
); );

View File

@ -14,7 +14,7 @@ export enum Network {
export const networks = [ export const networks = [
{ id: "mainnet", chainId: 1, name: "Mainnet", icon: MainnetSVG }, { 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<Network>(); export const activeNetworkId = ref<Network>();
@ -23,7 +23,6 @@ export const activeNetwork = computed(
); );
export function useNetwork() { export function useNetwork() {
const { showWarning } = useNotification(); const { showWarning } = useNotification();
const { account, networkName, refreshWeb3 } = useWeb3(); const { account, networkName, refreshWeb3 } = useWeb3();
const { showNetworksMismatchDialog } = useModal(); const { showNetworksMismatchDialog } = useModal();
@ -108,15 +107,18 @@ export function useNetwork() {
} }
watch(activeNetworkId, () => { watch(activeNetworkId, () => {
localStorage.setItem('network', activeNetworkId.value) localStorage.setItem("network", activeNetworkId.value);
}) });
onMounted( () => { onMounted(() => {
if (activeNetworkId.value) {
return;
}
//@ts-ignore //@ts-ignore
activeNetworkId.value = localStorage.getItem('network') || "mainnet"; activeNetworkId.value = localStorage.getItem("network") || "mainnet";
refreshWeb3() refreshWeb3();
}) });
return { return {
networkMismatch, networkMismatch,

104
composables/useTenderly.ts Normal file
View File

@ -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
};
}

View File

@ -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 Web3 from "web3";
import Web3Modal from "web3modal"; import Web3Modal from "web3modal";
import { Network } from "./useNetwork"; import { Network } from "./useNetwork";
@ -122,6 +122,14 @@ export function useWeb3() {
web3.value = newWeb3; web3.value = newWeb3;
}; };
const setWeb3 = (newWeb3: Web3) => {
web3.value = newWeb3;
}
watch(web3, () => {
window.web3 = web3.value;
})
return { return {
account, account,
chainId, chainId,
@ -130,6 +138,7 @@ export function useWeb3() {
activate, activate,
deactivate, deactivate,
networkName, networkName,
refreshWeb3 refreshWeb3,
setWeb3,
}; };
} }

View File

@ -79,11 +79,28 @@
Balance Balance
</button> </button>
</div> </div>
<div v-if="canSimulate" class="fixed bottom-0 left-0 ml-10 mb-16">
<button
v-if="forkId"
@click="stopSimulation"
class="px-9 h-[56px] bg-primary-blue-dark hover:bg-primary-blue-hover text-white rounded-[28px] text-lg font-semibold shadow flex items-center"
>
Stop Simulation
</button>
<button
v-else
@click="startSimulation"
class="px-9 h-[56px] bg-primary-blue-dark hover:bg-primary-blue-hover text-white rounded-[28px] text-lg font-semibold shadow flex items-center"
>
Start Simulation
</button>
</div>
</div> </div>
</template> </template>
<script> <script>
import { defineComponent, nextTick, onErrorCaptured, useContext, useRoute, watch } from "@nuxtjs/composition-api"; import { defineComponent, nextTick, onErrorCaptured, onMounted, useContext, useRoute, watch } from "@nuxtjs/composition-api";
import MakerDAOIcon from '~/assets/icons/makerdao.svg?inline' import MakerDAOIcon from '~/assets/icons/makerdao.svg?inline'
import CompoundIcon from '~/assets/icons/compound.svg?inline' import CompoundIcon from '~/assets/icons/compound.svg?inline'
import AaveIcon from '~/assets/icons/aave.svg?inline' import AaveIcon from '~/assets/icons/aave.svg?inline'
@ -91,6 +108,7 @@ import { useWeb3 } from '~/composables/useWeb3'
import { init as initSidebars, useSidebar } from '~/composables/useSidebar' import { init as initSidebars, useSidebar } from '~/composables/useSidebar'
import { useBackdrop } from '@/composables/useBackdrop' import { useBackdrop } from '@/composables/useBackdrop'
import { useNetwork } from "~/composables/useNetwork"; import { useNetwork } from "~/composables/useNetwork";
import { useTenderly } from "~/composables/useTenderly";
export default defineComponent({ export default defineComponent({
components: { components: {
@ -104,6 +122,7 @@ export default defineComponent({
const { isShown: isBackdropShown, close: closeBackdrop } = useBackdrop() const { isShown: isBackdropShown, close: closeBackdrop } = useBackdrop()
const { redirect } = useContext() const { redirect } = useContext()
const { showSidebarBalances } = useSidebar() const { showSidebarBalances } = useSidebar()
const { canSimulate, startSimulation, stopSimulation, forkId } = useTenderly()
const route = useRoute() const route = useRoute()
watch(isBackdropShown, () => { watch(isBackdropShown, () => {
@ -149,6 +168,10 @@ export default defineComponent({
closeBackdrop, closeBackdrop,
showSidebarBalances, showSidebarBalances,
activeNetworkId, activeNetworkId,
startSimulation,
forkId,
stopSimulation,
canSimulate,
} }
} }

View File

@ -43,6 +43,8 @@ export default {
publicRuntimeConfig: { publicRuntimeConfig: {
INFURA_ID: process.env.INFURA_ID, INFURA_ID: process.env.INFURA_ID,
PORTIS_ID: process.env.PORTIS_ID, PORTIS_ID: process.env.PORTIS_ID,
TENDERLY_FORK_PATH: process.env.TENDERLY_FORK_PATH,
TENDERLY_KEY: process.env.TENDERLY_KEY,
}, },
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins

View File

@ -1,16 +0,0 @@
import Web3 from "web3";
const mainnetInfura = "https://mainnet.infura.io/v3/";
const polygonInfura = "https://polygon-mainnet.infura.io/v3/";
export const polygonWeb3 = new Web3(
new Web3.providers.HttpProvider(
polygonInfura + "19c4b8b779a343e6ac5a91f4eaf55b81"
)
);
export const mainnetWeb3 = new Web3(
new Web3.providers.HttpProvider(
mainnetInfura + "19c4b8b779a343e6ac5a91f4eaf55b81"
)
);