From 0926447767fa957d54904859e0067082a7922b67 Mon Sep 17 00:00:00 2001 From: Georges KABBOUCHI Date: Tue, 21 Sep 2021 23:11:08 +0300 Subject: [PATCH 01/10] yearn --- abis/read/yearnV2.json | 400 ++++++++++++++++++ components/protocols/yearn-v2/CardYearn.vue | 100 +++++ .../context/yearn-v2/SidebarYearnV2Supply.vue | 183 ++++++++ .../yearn-v2/SidebarYearnV2Withdraw.vue | 179 ++++++++ composables/protocols/useYearnV2Position.ts | 131 ++++++ composables/useSidebar.ts | 8 + constant/addresses.ts | 3 +- package.json | 2 +- pages/mainnet/yearn-v2.vue | 100 +++++ yarn.lock | 8 +- 10 files changed, 1108 insertions(+), 6 deletions(-) create mode 100644 abis/read/yearnV2.json create mode 100644 components/protocols/yearn-v2/CardYearn.vue create mode 100644 components/sidebar/context/yearn-v2/SidebarYearnV2Supply.vue create mode 100644 components/sidebar/context/yearn-v2/SidebarYearnV2Withdraw.vue create mode 100644 composables/protocols/useYearnV2Position.ts create mode 100644 pages/mainnet/yearn-v2.vue diff --git a/abis/read/yearnV2.json b/abis/read/yearnV2.json new file mode 100644 index 0000000..9c61417 --- /dev/null +++ b/abis/read/yearnV2.json @@ -0,0 +1,400 @@ +[ + { + "inputs": [ + { + "internalType": "contract YearnV2Interface", + "name": "vault", + "type": "address" + } + ], + "name": "getAvailableDepositLimit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "contract YearnV2Interface", + "name": "vault", + "type": "address" + } + ], + "name": "getBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "contract YearnV2Interface", + "name": "vault", + "type": "address" + } + ], + "name": "getExpectedShareValue", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address[]", + "name": "wantAddresses", + "type": "address[]" + } + ], + "name": "getPositions", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "vaultLatestVersion", + "type": "address" + }, + { + "internalType": "address", + "name": "vault", + "type": "address" + }, + { + "internalType": "address", + "name": "want", + "type": "address" + }, + { + "internalType": "uint256", + "name": "pricePerShare", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availableDepositLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalAssets", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "balanceOf", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "wantBalanceOf", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expectedShareValue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isDeprecated", + "type": "bool" + }, + { + "internalType": "bool", + "name": "emergencyShutdown", + "type": "bool" + } + ], + "internalType": "struct Helpers.VaultData[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address[]", + "name": "wantAddresses", + "type": "address[]" + } + ], + "name": "getPositionsForLatest", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "vaultLatestVersion", + "type": "address" + }, + { + "internalType": "address", + "name": "vault", + "type": "address" + }, + { + "internalType": "address", + "name": "want", + "type": "address" + }, + { + "internalType": "uint256", + "name": "pricePerShare", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availableDepositLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalAssets", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "balanceOf", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "wantBalanceOf", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expectedShareValue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isDeprecated", + "type": "bool" + }, + { + "internalType": "bool", + "name": "emergencyShutdown", + "type": "bool" + } + ], + "internalType": "struct Helpers.VaultData[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract YearnV2Interface", + "name": "vault", + "type": "address" + } + ], + "name": "getPricePerShare", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRegistry", + "outputs": [ + { + "internalType": "contract YearnRegistryInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract YearnV2Interface", + "name": "vault", + "type": "address" + } + ], + "name": "getTotalAssets", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract YearnV2Interface", + "name": "vault", + "type": "address" + } + ], + "name": "isEmergencyShutdown", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "want", + "type": "address" + } + ], + "name": "isWantSupported", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "want", + "type": "address" + } + ], + "name": "latestForWant", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "want", + "type": "address" + } + ], + "name": "listVaultsForWant", + "outputs": [ + { + "internalType": "address[]", + "name": "vaultAddresses", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "want", + "type": "address" + } + ], + "name": "numVaultsForWant", + "outputs": [ + { + "internalType": "uint256", + "name": "numVaults", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/components/protocols/yearn-v2/CardYearn.vue b/components/protocols/yearn-v2/CardYearn.vue new file mode 100644 index 0000000..4c19488 --- /dev/null +++ b/components/protocols/yearn-v2/CardYearn.vue @@ -0,0 +1,100 @@ + + + + diff --git a/components/sidebar/context/yearn-v2/SidebarYearnV2Supply.vue b/components/sidebar/context/yearn-v2/SidebarYearnV2Supply.vue new file mode 100644 index 0000000..21b5e17 --- /dev/null +++ b/components/sidebar/context/yearn-v2/SidebarYearnV2Supply.vue @@ -0,0 +1,183 @@ + + + diff --git a/components/sidebar/context/yearn-v2/SidebarYearnV2Withdraw.vue b/components/sidebar/context/yearn-v2/SidebarYearnV2Withdraw.vue new file mode 100644 index 0000000..dec1bca --- /dev/null +++ b/components/sidebar/context/yearn-v2/SidebarYearnV2Withdraw.vue @@ -0,0 +1,179 @@ + + + diff --git a/composables/protocols/useYearnV2Position.ts b/composables/protocols/useYearnV2Position.ts new file mode 100644 index 0000000..a5c8686 --- /dev/null +++ b/composables/protocols/useYearnV2Position.ts @@ -0,0 +1,131 @@ +import { useWeb3 } from "@instadapp/vue-web3"; +import { ref, useContext, watch } from "@nuxtjs/composition-api"; +import addresses from "~/constant/addresses"; +import tokens from "~/constant/tokens"; +import { useDSA } from "../useDSA"; +import yearnV2ABI from "~/abis/read/yearnV2.json"; +import useEventBus from "../useEventBus"; +import BigNumber from "bignumber.js"; +import { useBigNumber } from "../useBigNumber"; + +const resolver = addresses.mainnet.resolver.yearnV2; + +const wantAddresses = [ + tokens.mainnet.getTokenByKey("weth").address, + tokens.mainnet.getTokenByKey("dai").address +]; + +const vaults = ref([]); + +export function useYearnV2Position() { + const { $axios } = useContext(); + const { times } = useBigNumber(); + const { library } = useWeb3(); + const { activeAccount } = useDSA(); + const { onEvent } = useEventBus(); + + const fetchPosition = async () => { + vaults.value = []; + const availableVaults = await $axios + .$get("https://api.yearn.finance/v1/chains/1/vaults/all") + .then(vs => vs.filter(v => v.type === "v2")); + + if (!library.value) { + return; + } + + if (!activeAccount.value) { + return; + } + + const resolverInstance = new library.value.eth.Contract( + yearnV2ABI as any, + resolver + ); + + const tokensArr = wantAddresses; // tokens.mainnet.allTokens.map(a => a.address); + + const rawData = await resolverInstance.methods + .getPositionsForLatest(activeAccount.value.address, tokensArr) + .call(); + + const newVaults = []; + + rawData.forEach( + ([ + vaultLatestVersion, + vault, + want, + pricePerShare, + availableDepositLimit, + totalAssets, + balanceOf, + wantBalanceOf, + expectedShareValue, + decimals, + isDeprecated, + emergencyShutdown + ]) => { + const v = availableVaults.find(v => v.address === vault); + if (v) { + const supply = new BigNumber(balanceOf) + .dividedBy(10 ** decimals) + .toFixed(); + + newVaults.push({ + ...v, + priceInUsd: v.tvl.price.toString(), + position: { + vaultLatestVersion, + vault, + want, + pricePerShare, + availableDepositLimit, + totalAssets, + balanceOf, + wantBalanceOf, + expectedShareValue, + decimals, + isDeprecated, + emergencyShutdown, + supply, + supplyUsd: times(supply, v.tvl.price).toFixed(), + } + }); + } + } + ); + vaults.value = newVaults; + }; + + const refreshPosition = async () => { + await fetchPosition(); + }; + + onEvent("protocol::compound::refresh", refreshPosition); + + watch( + library, + async val => { + if (val) { + refreshPosition(); + } + }, + { immediate: true } + ); + + watch( + activeAccount, + async val => { + if (val) { + refreshPosition(); + } + }, + { immediate: true } + ); + + return { + vaults, + refreshPosition + }; +} diff --git a/composables/useSidebar.ts b/composables/useSidebar.ts index d5ec48e..89e109a 100644 --- a/composables/useSidebar.ts +++ b/composables/useSidebar.ts @@ -41,6 +41,9 @@ import SidebarReflexerWithdraw from '~/components/sidebar/context/reflexer/Sideb import SidebarReflexerBorrow from '~/components/sidebar/context/reflexer/SidebarReflexerBorrow.vue' import SidebarReflexerPayback from '~/components/sidebar/context/reflexer/SidebarReflexerPayback.vue' +import SidebarYearnV2Supply from "~/components/sidebar/context/yearn-v2/SidebarYearnV2Supply.vue"; +import SidebarYearnV2Withdraw from '~/components/sidebar/context/yearn-v2/SidebarYearnV2Withdraw.vue' + import SidebarStrategySelection from '~/components/sidebar/context/strategy/SidebarStrategySelection.vue' import SidebarStrategy from '~/components/sidebar/context/strategy/SidebarStrategy.vue' @@ -82,6 +85,11 @@ const sidebars = { "/mainnet/reflexer#withdraw": { component: SidebarReflexerWithdraw }, "/mainnet/reflexer#borrow": { component: SidebarReflexerBorrow }, "/mainnet/reflexer#payback": { component: SidebarReflexerPayback }, + + + "/mainnet/yearn-v2": { component: null }, + "/mainnet/yearn-v2#supply": { component: SidebarYearnV2Supply }, + "/mainnet/yearn-v2#withdraw": { component: SidebarYearnV2Withdraw }, }; const sidebar = ref(null); diff --git a/constant/addresses.ts b/constant/addresses.ts index a1b4ac0..4268b2c 100644 --- a/constant/addresses.ts +++ b/constant/addresses.ts @@ -10,7 +10,8 @@ const addresses = { maker: "0x84addce4fac0b6ee4b0cd132120d6d4b700e35c0", unipool: "0x22bddA39D14eD0aafeee36B6e784602fdDE64723", liquity: "0xDAf2A39503463B0F41f899EDD82213b3c96b6Cf8", - reflexer: "0x016ca8d0993d1a7073b01802a2e22fd0df7e633a" + reflexer: "0x016ca8d0993d1a7073b01802a2e22fd0df7e633a", + yearnV2: "0x3f6DCA8a0b7d04737BC3B2aEAbeB1C09431581f0" } }, diff --git a/package.json b/package.json index 5709b8d..6015364 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "bignumber.js": "^9.0.1", "core-js": "^3.15.1", "css-color-function": "^1.3.3", - "dsa-connect": "^0.4.4", + "dsa-connect": "^0.4.7-beta.0", "nuxt": "^2.15.7", "qrcode": "^1.4.4", "slugify": "^1.6.0", diff --git a/pages/mainnet/yearn-v2.vue b/pages/mainnet/yearn-v2.vue new file mode 100644 index 0000000..8992323 --- /dev/null +++ b/pages/mainnet/yearn-v2.vue @@ -0,0 +1,100 @@ + + + diff --git a/yarn.lock b/yarn.lock index d343ecf..cedd00f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5919,10 +5919,10 @@ drbg.js@^1.0.1: create-hash "^1.1.2" create-hmac "^1.1.4" -dsa-connect@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/dsa-connect/-/dsa-connect-0.4.4.tgz#c47ded36b23d089c85f61bff3a781b5d577d4fe7" - integrity sha512-QSR8uiDXRwbInh2muGJfJPEK5KkMRX1Rc5wrcOL3Ov1bKkpZxQ0iSAoO3R/5OD5MV23n6vKiIa9ZX/BVId/exg== +dsa-connect@^0.4.7-beta.0: + version "0.4.7-beta.0" + resolved "https://registry.yarnpkg.com/dsa-connect/-/dsa-connect-0.4.7-beta.0.tgz#40b73e2fdec353c175d2bb3f813a426865940ebb" + integrity sha512-pODE4W5KxIx07wmGoV/w1S4hNw6g3GnoNcrDG3ExDRKogIISpqvVfxK+HWkcospmKf9eYoAW1QY0/x32tOxJww== duplexer3@^0.1.4: version "0.1.4" From e322f604c711e6de849086863d91bb22e7e257f4 Mon Sep 17 00:00:00 2001 From: Georges KABBOUCHI Date: Fri, 24 Sep 2021 00:18:24 +0300 Subject: [PATCH 02/10] update dsa-connect --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6015364..db9578d 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "bignumber.js": "^9.0.1", "core-js": "^3.15.1", "css-color-function": "^1.3.3", - "dsa-connect": "^0.4.7-beta.0", + "dsa-connect": "^0.4.8-beta.1", "nuxt": "^2.15.7", "qrcode": "^1.4.4", "slugify": "^1.6.0", diff --git a/yarn.lock b/yarn.lock index cedd00f..0191098 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5919,10 +5919,10 @@ drbg.js@^1.0.1: create-hash "^1.1.2" create-hmac "^1.1.4" -dsa-connect@^0.4.7-beta.0: - version "0.4.7-beta.0" - resolved "https://registry.yarnpkg.com/dsa-connect/-/dsa-connect-0.4.7-beta.0.tgz#40b73e2fdec353c175d2bb3f813a426865940ebb" - integrity sha512-pODE4W5KxIx07wmGoV/w1S4hNw6g3GnoNcrDG3ExDRKogIISpqvVfxK+HWkcospmKf9eYoAW1QY0/x32tOxJww== +dsa-connect@^0.4.8-beta.1: + version "0.4.8-beta.1" + resolved "https://registry.yarnpkg.com/dsa-connect/-/dsa-connect-0.4.8-beta.1.tgz#6dc36eb2b2d5ee16050277b32947b416e401f6fd" + integrity sha512-q39XBUfYXvXlf/WygLCVQVxaIv3o+2mYiMnPuFhwkxkEL5v5YiTB1QYucTOn+CVrjr5yjTfA1zrlx2XGsP2F8Q== duplexer3@^0.1.4: version "0.1.4" From 9eb75d93faccb5bdb4f4f1e93b5b06e6fd5883c9 Mon Sep 17 00:00:00 2001 From: Georges KABBOUCHI Date: Fri, 24 Sep 2021 00:23:10 +0300 Subject: [PATCH 03/10] Update useYearnV2Position.ts --- composables/protocols/useYearnV2Position.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/composables/protocols/useYearnV2Position.ts b/composables/protocols/useYearnV2Position.ts index a5c8686..07e4da4 100644 --- a/composables/protocols/useYearnV2Position.ts +++ b/composables/protocols/useYearnV2Position.ts @@ -10,10 +10,7 @@ import { useBigNumber } from "../useBigNumber"; const resolver = addresses.mainnet.resolver.yearnV2; -const wantAddresses = [ - tokens.mainnet.getTokenByKey("weth").address, - tokens.mainnet.getTokenByKey("dai").address -]; +const wantAddresses = tokens.mainnet.allTokens.map((token) => token.address); const vaults = ref([]); From 56fddcb4bfa6499da333fe89b238fa99af7bb84c Mon Sep 17 00:00:00 2001 From: Georges KABBOUCHI Date: Fri, 24 Sep 2021 00:31:17 +0300 Subject: [PATCH 04/10] fixes --- assets/icons/yearn.svg | 7 +++++++ components/protocols/yearn-v2/CardYearn.vue | 9 +++++---- pages/index.vue | 8 ++++++++ pages/mainnet/yearn-v2.vue | 8 ++++---- 4 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 assets/icons/yearn.svg diff --git a/assets/icons/yearn.svg b/assets/icons/yearn.svg new file mode 100644 index 0000000..1524ede --- /dev/null +++ b/assets/icons/yearn.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/components/protocols/yearn-v2/CardYearn.vue b/components/protocols/yearn-v2/CardYearn.vue index 4c19488..a6a3012 100644 --- a/components/protocols/yearn-v2/CardYearn.vue +++ b/components/protocols/yearn-v2/CardYearn.vue @@ -1,6 +1,6 @@