mirror of
https://github.com/Instadapp/assembly.git
synced 2024-07-29 22:37:06 +00:00
Merge branch 'master' into liquity-stability-pool
This commit is contained in:
commit
b83b41ebd6
400
abis/read/yearnV2.json
Normal file
400
abis/read/yearnV2.json
Normal file
|
@ -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"
|
||||
}
|
||||
]
|
7
assets/icons/yearn.svg
Normal file
7
assets/icons/yearn.svg
Normal file
|
@ -0,0 +1,7 @@
|
|||
<svg viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.375 11.375C11.375 10.4788 12.1038 9.75 13 9.75C13.8962 9.75 14.625 10.4788 14.625 11.375C14.625 12.2712 13.8962 13 13 13C12.1038 13 11.375 12.2712 11.375 11.375Z" fill="white"/>
|
||||
<path d="M7.3125 16.25H18.6875V6.5H7.3125V16.25ZM13 8.125C14.5096 8.125 15.7714 9.165 16.1346 10.5625H17.0625C17.511 10.5625 17.875 10.9265 17.875 11.375C17.875 11.8235 17.511 12.1875 17.0625 12.1875H16.1346C15.7714 13.585 14.5096 14.625 13 14.625C11.2076 14.625 9.75 13.1674 9.75 11.375C9.75 9.58262 11.2076 8.125 13 8.125Z" fill="white"/>
|
||||
<path d="M21.125 1.625H4.875C3.53112 1.625 2.4375 2.71862 2.4375 4.0625V18.6875C2.4375 20.0314 3.53112 21.125 4.875 21.125H21.125C22.4689 21.125 23.5625 20.0314 23.5625 18.6875V4.0625C23.5625 2.71862 22.4689 1.625 21.125 1.625ZM20.3125 17.0625C20.3125 17.511 19.9485 17.875 19.5 17.875H6.5C6.0515 17.875 5.6875 17.511 5.6875 17.0625V5.6875C5.6875 5.239 6.0515 4.875 6.5 4.875H19.5C19.9485 4.875 20.3125 5.239 20.3125 5.6875V17.0625Z" fill="white"/>
|
||||
<path d="M17.0625 22.75H21.125V23.5625C21.125 24.011 20.761 24.375 20.3125 24.375H17.875C17.4265 24.375 17.0625 24.011 17.0625 23.5625V22.75Z" fill="white"/>
|
||||
<path d="M4.875 22.75H8.9375V23.5625C8.9375 24.011 8.5735 24.375 8.125 24.375H5.6875C5.239 24.375 4.875 24.011 4.875 23.5625V22.75Z" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
108
components/protocols/yearn-v2/CardYearn.vue
Normal file
108
components/protocols/yearn-v2/CardYearn.vue
Normal file
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<div
|
||||
class="flex-shrink-0 bg-white rounded-lg relative flex flex-col flex-1 px-6 pt-4 pb-6 dark:bg-dark-500"
|
||||
style="box-shadow: -1px -3px 10px rgba(12, 25, 91, 0.03), 2px 4px 12px rgba(12, 25, 91, 0.05)"
|
||||
>
|
||||
<div class="flex items-center h-14">
|
||||
<div class="flex mr-4 -space-x-3 overflow-hidden">
|
||||
<div
|
||||
v-if="tokenIcon"
|
||||
class="inline-flex items-center justify-center dark:opacity-90 w-12 h-12"
|
||||
>
|
||||
<img class="w-full h-full object-cover" :src="tokenIcon" />
|
||||
</div>
|
||||
<IconCurrency v-else :currency="tokenKey" class="w-12 h-12" no-height />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col flex-grow">
|
||||
<div class="mb-1 font-medium leading-none whitespace-no-wrap text-19">
|
||||
{{ formatUsd(supplyUsd) }}
|
||||
</div>
|
||||
<div class="flex leading-none whitespace-no-wrap">
|
||||
<span class="text-grey-pure text-14"
|
||||
>{{ formatDecimal(supply) }} {{ symbol }}</span
|
||||
>
|
||||
<Info
|
||||
:text="`${formatUsd(priceInUsd, 2)}/${symbol}`"
|
||||
icon="price"
|
||||
class="ml-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto text-right">
|
||||
<p class="text-lg font-medium">{{ formatPercent(netAPY) }}</p>
|
||||
<p class="text-sm font-medium text-[#9FB0C9]">net APY</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="mt-4" />
|
||||
|
||||
<div class="flex items-center justify-around mt-6">
|
||||
<button
|
||||
class="mr-4 h-10 w-full bg-primary-blue-dark shadow text-white rounded-[4px] hover:bg-primary-blue-hover"
|
||||
@click="showSupply"
|
||||
>
|
||||
Supply
|
||||
</button>
|
||||
<button
|
||||
class="h-10 w-full text-primary-blue-dark shadow border border-primary-blue-dark hover:border-primary-blue-hover rounded-[4px] hover:text-primary-blue-hover"
|
||||
@click="showWithdraw"
|
||||
>
|
||||
Withdraw
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed, defineComponent, useContext } from "@nuxtjs/composition-api";
|
||||
import { useFormatting } from "~/composables/useFormatting";
|
||||
import { useToken } from "~/composables/useToken";
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
tokenKey: { type: String, required: true },
|
||||
tokenIcon: { type: String, required: false },
|
||||
vault: { type: String, default: null },
|
||||
supply: { type: String, required: true },
|
||||
supplyUsd: { type: String, required: true },
|
||||
priceInUsd: { type: String, default: "0" },
|
||||
netAPY: { type: String, default: "0" }
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const { app } = useContext();
|
||||
const { formatPercent, formatUsd, formatDecimal } = useFormatting();
|
||||
const { getTokenByKey } = useToken();
|
||||
|
||||
const symbol = computed(
|
||||
() => getTokenByKey(props.tokenKey)?.symbol || props.tokenKey
|
||||
);
|
||||
|
||||
function showSupply() {
|
||||
app.router.push({ hash: `supply?vault=${props.vault}` });
|
||||
}
|
||||
|
||||
function showWithdraw() {
|
||||
app.router.push({ hash: `withdraw?vault=${props.vault}` });
|
||||
}
|
||||
|
||||
return {
|
||||
showSupply,
|
||||
showWithdraw,
|
||||
formatPercent,
|
||||
formatUsd,
|
||||
formatDecimal,
|
||||
symbol
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.position-button {
|
||||
@apply flex-1;
|
||||
@apply h-8;
|
||||
@apply h-8;
|
||||
}
|
||||
</style>
|
|
@ -2,9 +2,9 @@
|
|||
<SidebarContextContainer class="flex-1 h-full overflow-hidden">
|
||||
<SidebarContextHeader><slot name="title" /></SidebarContextHeader>
|
||||
|
||||
<div class="overflow-y-scroll scrollbar-hover">
|
||||
<div class="mx-auto w-full">
|
||||
<div class="py-2 sm:py-4">
|
||||
<div class="overflow-y-scroll scrollbar-hover h-full">
|
||||
<div class="mx-auto w-full h-full">
|
||||
<div class="py-2 sm:py-4 h-full">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
<SidebarSectionStatus
|
||||
class="mt-8"
|
||||
:liquidation="maxLiquidation"
|
||||
:liquidation="liquidation"
|
||||
:status="status"
|
||||
/>
|
||||
|
||||
|
@ -212,6 +212,7 @@ export default defineComponent({
|
|||
formatUsdMax,
|
||||
formatUsd,
|
||||
maxLiquidation,
|
||||
liquidation,
|
||||
liquidationPrice,
|
||||
liquidationMaxPrice,
|
||||
errorMessages,
|
||||
|
|
183
components/sidebar/context/yearn-v2/SidebarYearnV2Supply.vue
Normal file
183
components/sidebar/context/yearn-v2/SidebarYearnV2Supply.vue
Normal file
|
@ -0,0 +1,183 @@
|
|||
<template>
|
||||
<SidebarContextRootContainer>
|
||||
<template #title>Supply {{ symbol }}</template>
|
||||
|
||||
<SidebarSectionValueWithIcon label="Token Balance" center>
|
||||
<template #icon
|
||||
><IconCurrency :currency="token.key" class="w-20 h-20" noHeight
|
||||
/></template>
|
||||
<template #value>{{ formatNumber(balance) }} {{ symbol }}</template>
|
||||
</SidebarSectionValueWithIcon>
|
||||
|
||||
<div class="bg-[#C5CCE1] bg-opacity-[0.15] mt-10 p-8 h-full">
|
||||
<h3 class="text-primary-gray text-xs font-semibold mb-2.5">
|
||||
Amount to supply
|
||||
</h3>
|
||||
|
||||
<input-numeric
|
||||
v-model="amount"
|
||||
placeholder="Amount to supply"
|
||||
:error="errors.amount.message"
|
||||
>
|
||||
<template v-if="!isMaxAmount" #suffix>
|
||||
<div class="absolute mt-2 top-0 right-0 mr-4">
|
||||
<button
|
||||
type="button"
|
||||
class="text-primary-blue-dark font-semibold text-sm hover:text-primary-blue-hover"
|
||||
@click="toggle"
|
||||
>
|
||||
Max
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</input-numeric>
|
||||
|
||||
<div class="flex flex-shrink-0 mt-10">
|
||||
<ButtonCTA
|
||||
class="w-full"
|
||||
:disabled="!isValid || pending"
|
||||
:loading="pending"
|
||||
@click="cast"
|
||||
>
|
||||
Supply
|
||||
</ButtonCTA>
|
||||
</div>
|
||||
|
||||
<ValidationErrors :error-messages="errorMessages" class="mt-6" />
|
||||
</div>
|
||||
</SidebarContextRootContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref } from "@nuxtjs/composition-api";
|
||||
import InputNumeric from "~/components/common/input/InputNumeric.vue";
|
||||
import { useBalances } from "~/composables/useBalances";
|
||||
import { useNotification } from "~/composables/useNotification";
|
||||
import { useBigNumber } from "~/composables/useBigNumber";
|
||||
import { useFormatting } from "~/composables/useFormatting";
|
||||
import { useValidators } from "~/composables/useValidators";
|
||||
import { useValidation } from "~/composables/useValidation";
|
||||
import { useToken } from "~/composables/useToken";
|
||||
import { useParsing } from "~/composables/useParsing";
|
||||
import { useMaxAmountActive } from "~/composables/useMaxAmountActive";
|
||||
import { useWeb3 } from "@instadapp/vue-web3";
|
||||
import ToggleButton from "~/components/common/input/ToggleButton.vue";
|
||||
import { useDSA } from "~/composables/useDSA";
|
||||
import ButtonCTA from "~/components/common/input/ButtonCTA.vue";
|
||||
import Button from "~/components/Button.vue";
|
||||
import { useSidebar } from "~/composables/useSidebar";
|
||||
import DSA from "dsa-connect";
|
||||
import { useYearnV2Position } from "~/composables/protocols/useYearnV2Position";
|
||||
export default defineComponent({
|
||||
components: { InputNumeric, ToggleButton, ButtonCTA, Button },
|
||||
props: {
|
||||
vault: { type: String, required: true }
|
||||
},
|
||||
setup(props) {
|
||||
const { close } = useSidebar();
|
||||
const { account } = useWeb3();
|
||||
const { dsa } = useDSA();
|
||||
const { getTokenByKey, valInt } = useToken();
|
||||
const { getBalanceByKey, fetchBalances } = useBalances();
|
||||
const { formatNumber, formatUsdMax, formatUsd } = useFormatting();
|
||||
const { isZero, gt, plus } = useBigNumber();
|
||||
const { parseSafeFloat } = useParsing();
|
||||
const {
|
||||
showPendingTransaction,
|
||||
showWarning,
|
||||
showConfirmedTransaction
|
||||
} = useNotification();
|
||||
|
||||
const { vaults, refreshPosition } = useYearnV2Position();
|
||||
const selectedVault = computed(() =>
|
||||
vaults.value.find(v => v.address === props.vault)
|
||||
);
|
||||
|
||||
const amount = ref("");
|
||||
const amountParsed = computed(() => parseSafeFloat(amount.value));
|
||||
|
||||
const token = computed(() =>
|
||||
selectedVault.value
|
||||
? getTokenByKey(selectedVault.value.token.display_name.toLowerCase())
|
||||
: null
|
||||
);
|
||||
const symbol = computed(() => token.value?.symbol);
|
||||
const decimals = computed(() => token.value?.decimals);
|
||||
const balance = computed(() => getBalanceByKey(token.value?.key));
|
||||
|
||||
const { toggle, isMaxAmount } = useMaxAmountActive(amount, balance);
|
||||
|
||||
const { validateAmount, validateIsLoggedIn } = useValidators();
|
||||
const errors = computed(() => {
|
||||
const hasAmountValue = !isZero(amount.value);
|
||||
|
||||
return {
|
||||
amount: {
|
||||
message: validateAmount(amountParsed.value, balance.value),
|
||||
show: hasAmountValue
|
||||
},
|
||||
auth: { message: validateIsLoggedIn(!!account.value), show: true }
|
||||
};
|
||||
});
|
||||
const { errorMessages, isValid } = useValidation(errors);
|
||||
|
||||
const pending = ref(false);
|
||||
|
||||
async function cast() {
|
||||
pending.value = true;
|
||||
|
||||
const amount = isMaxAmount.value
|
||||
? dsa.value.maxValue
|
||||
: valInt(amountParsed.value, decimals.value);
|
||||
|
||||
const spells = dsa.value.Spell();
|
||||
|
||||
spells.add({
|
||||
//@ts-ignore
|
||||
connector: "YEARN-VAULT-A",
|
||||
method: "deposit",
|
||||
args: [props.vault, amount, 0, 0]
|
||||
});
|
||||
|
||||
try {
|
||||
const txHash = await (dsa.value as DSA).cast({
|
||||
spells,
|
||||
from: account.value,
|
||||
onReceipt: async receipt => {
|
||||
showConfirmedTransaction(receipt.transactionHash);
|
||||
|
||||
await fetchBalances(true);
|
||||
await refreshPosition();
|
||||
}
|
||||
});
|
||||
|
||||
showPendingTransaction(txHash);
|
||||
} catch (error) {
|
||||
showWarning(error.message);
|
||||
}
|
||||
|
||||
pending.value = false;
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
return {
|
||||
selectedVault,
|
||||
pending,
|
||||
cast,
|
||||
errors,
|
||||
amount,
|
||||
token,
|
||||
symbol,
|
||||
balance,
|
||||
formatNumber,
|
||||
formatUsdMax,
|
||||
formatUsd,
|
||||
toggle,
|
||||
isMaxAmount,
|
||||
errorMessages,
|
||||
isValid
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
179
components/sidebar/context/yearn-v2/SidebarYearnV2Withdraw.vue
Normal file
179
components/sidebar/context/yearn-v2/SidebarYearnV2Withdraw.vue
Normal file
|
@ -0,0 +1,179 @@
|
|||
<template>
|
||||
<SidebarContextRootContainer>
|
||||
<template #title>Withdraw {{ symbol }}</template>
|
||||
|
||||
<SidebarSectionValueWithIcon label="Token Balance" center>
|
||||
<template #icon
|
||||
><IconCurrency :currency="token.key" class="w-20 h-20" noHeight
|
||||
/></template>
|
||||
<template #value>{{ formatNumber(balance) }} {{ symbol }}</template>
|
||||
</SidebarSectionValueWithIcon>
|
||||
|
||||
<div class="bg-[#C5CCE1] bg-opacity-[0.15] mt-10 p-8 h-full">
|
||||
<h3 class="text-primary-gray text-xs font-semibold mb-2.5">
|
||||
Amount to withdraw
|
||||
</h3>
|
||||
|
||||
<input-numeric
|
||||
v-model="amount"
|
||||
placeholder="Amount to withdraw"
|
||||
:error="errors.amount.message"
|
||||
>
|
||||
<template v-if="!isMaxAmount" #suffix>
|
||||
<div class="absolute mt-2 top-0 right-0 mr-4">
|
||||
<button
|
||||
type="button"
|
||||
class="text-primary-blue-dark font-semibold text-sm hover:text-primary-blue-hover"
|
||||
@click="toggle"
|
||||
>
|
||||
Max
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</input-numeric>
|
||||
|
||||
<div class="flex flex-shrink-0 mt-10">
|
||||
<ButtonCTA
|
||||
class="w-full"
|
||||
:disabled="!isValid || pending"
|
||||
:loading="pending"
|
||||
@click="cast"
|
||||
>
|
||||
Withdraw
|
||||
</ButtonCTA>
|
||||
</div>
|
||||
|
||||
<ValidationErrors :error-messages="errorMessages" class="mt-6" />
|
||||
</div>
|
||||
</SidebarContextRootContainer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed, defineComponent, onMounted, ref } from '@nuxtjs/composition-api'
|
||||
import InputNumeric from '~/components/common/input/InputNumeric.vue'
|
||||
import { useBalances } from '~/composables/useBalances'
|
||||
import { useBigNumber } from '~/composables/useBigNumber'
|
||||
import { useFormatting } from '~/composables/useFormatting'
|
||||
import { useValidators } from '~/composables/useValidators'
|
||||
import { useValidation } from '~/composables/useValidation'
|
||||
import { useToken } from '~/composables/useToken'
|
||||
import { useParsing } from '~/composables/useParsing'
|
||||
import { useMaxAmountActive } from '~/composables/useMaxAmountActive'
|
||||
import { useWeb3 } from '@instadapp/vue-web3'
|
||||
import ToggleButton from '~/components/common/input/ToggleButton.vue'
|
||||
import { useDSA } from '~/composables/useDSA'
|
||||
import ButtonCTA from '~/components/common/input/ButtonCTA.vue'
|
||||
import { useNotification } from '~/composables/useNotification'
|
||||
import Button from '~/components/Button.vue'
|
||||
import { useSidebar } from '~/composables/useSidebar'
|
||||
import { useYearnV2Position } from '~/composables/protocols/useYearnV2Position'
|
||||
|
||||
export default defineComponent({
|
||||
components: { InputNumeric, ToggleButton, ButtonCTA, Button },
|
||||
props: {
|
||||
vault: { type: String, required: true }
|
||||
},
|
||||
setup(props) {
|
||||
const { close } = useSidebar()
|
||||
const { account } = useWeb3()
|
||||
const { dsa } = useDSA()
|
||||
const { getTokenByKey, valInt } = useToken()
|
||||
const { formatNumber, formatUsdMax, formatUsd } = useFormatting()
|
||||
const { isZero, gt, plus, max, minus } = useBigNumber()
|
||||
const { parseSafeFloat } = useParsing()
|
||||
const { showPendingTransaction, showConfirmedTransaction, showWarning } = useNotification()
|
||||
const { fetchBalances } = useBalances();
|
||||
|
||||
const { vaults, refreshPosition } = useYearnV2Position();
|
||||
const selectedVault = computed(() =>
|
||||
vaults.value.find(v => v.address === props.vault)
|
||||
);
|
||||
|
||||
const balance = computed(
|
||||
() => selectedVault.value ? selectedVault.value.position.supply : '0'
|
||||
)
|
||||
|
||||
const amount = ref('')
|
||||
const amountParsed = computed(() => parseSafeFloat(amount.value))
|
||||
|
||||
|
||||
const token = computed(() =>
|
||||
selectedVault.value
|
||||
? getTokenByKey(selectedVault.value.token.display_name.toLowerCase())
|
||||
: null
|
||||
);
|
||||
const symbol = computed(() => token.value?.symbol)
|
||||
const decimals = computed(() => token.value?.decimals)
|
||||
|
||||
|
||||
const { toggle, isMaxAmount } = useMaxAmountActive(amount, balance)
|
||||
|
||||
const { validateAmount, validateIsLoggedIn } = useValidators()
|
||||
|
||||
const errors = computed(() => {
|
||||
const hasAmountValue = !isZero(amount.value)
|
||||
|
||||
return {
|
||||
amount: { message: validateAmount(amountParsed.value, balance.value), show: hasAmountValue },
|
||||
auth: { message: validateIsLoggedIn(!!account.value), show: true },
|
||||
}
|
||||
})
|
||||
const { errorMessages, isValid } = useValidation(errors)
|
||||
|
||||
const pending = ref(false)
|
||||
|
||||
async function cast() {
|
||||
pending.value = true
|
||||
|
||||
const amount = isMaxAmount.value ? dsa.value.maxValue : valInt(amountParsed.value, decimals.value)
|
||||
|
||||
const spells = dsa.value.Spell()
|
||||
|
||||
spells.add({
|
||||
//@ts-ignore
|
||||
connector: "YEARN-VAULT-A",
|
||||
method: 'withdraw',
|
||||
args: [props.vault, amount, 0, 0],
|
||||
})
|
||||
|
||||
try {
|
||||
const txHash = await dsa.value.cast({
|
||||
spells,
|
||||
from: account.value,
|
||||
onReceipt: async receipt => {
|
||||
showConfirmedTransaction(receipt.transactionHash);
|
||||
|
||||
await fetchBalances(true);
|
||||
await refreshPosition();
|
||||
}
|
||||
})
|
||||
|
||||
showPendingTransaction(txHash)
|
||||
} catch (error) {
|
||||
showWarning(error.message)
|
||||
}
|
||||
|
||||
pending.value = false
|
||||
|
||||
close()
|
||||
}
|
||||
|
||||
return {
|
||||
pending,
|
||||
cast,
|
||||
errors,
|
||||
amount,
|
||||
token,
|
||||
symbol,
|
||||
balance,
|
||||
formatNumber,
|
||||
formatUsdMax,
|
||||
formatUsd,
|
||||
toggle,
|
||||
isMaxAmount,
|
||||
errorMessages,
|
||||
isValid
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
138
composables/protocols/useYearnV2Position.ts
Normal file
138
composables/protocols/useYearnV2Position.ts
Normal file
|
@ -0,0 +1,138 @@
|
|||
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 allTokens = tokens.mainnet.allTokens.map(token => token.address);
|
||||
|
||||
const wantAddresses = allTokens;
|
||||
|
||||
const vaults = ref([]);
|
||||
|
||||
export function useYearnV2Position() {
|
||||
const { $axios } = useContext();
|
||||
const { times } = useBigNumber();
|
||||
const { library } = useWeb3();
|
||||
const { activeAccount } = useDSA();
|
||||
const { onEvent } = useEventBus();
|
||||
|
||||
const fetchPosition = async () => {
|
||||
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;
|
||||
|
||||
// allow user to add custom tokens
|
||||
const tokensArr = [
|
||||
...new Set(
|
||||
availableVaults.filter(v => v.type === "v2").map(v => v.token.address)
|
||||
.filter(a => allTokens.includes(a))
|
||||
)
|
||||
];
|
||||
|
||||
|
||||
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
|
||||
};
|
||||
}
|
|
@ -43,6 +43,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'
|
||||
|
||||
|
@ -86,6 +89,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);
|
||||
|
|
|
@ -10,7 +10,8 @@ const addresses = {
|
|||
maker: "0x84addce4fac0b6ee4b0cd132120d6d4b700e35c0",
|
||||
unipool: "0x22bddA39D14eD0aafeee36B6e784602fdDE64723",
|
||||
liquity: "0xDAf2A39503463B0F41f899EDD82213b3c96b6Cf8",
|
||||
reflexer: "0x016ca8d0993d1a7073b01802a2e22fd0df7e633a"
|
||||
reflexer: "0x016ca8d0993d1a7073b01802a2e22fd0df7e633a",
|
||||
yearnV2: "0x3f6DCA8a0b7d04737BC3B2aEAbeB1C09431581f0"
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -9,7 +9,17 @@
|
|||
class="px-8 md:px-4 max-w-6xl mx-auto"
|
||||
:class="{ 'text-center': !active, 'py-12': active }"
|
||||
>
|
||||
<Nuxt v-if="active" />
|
||||
<div v-if="active && activeAccount && activeAccount.version === '1'" class="text-center w-full my-16">
|
||||
<h3 class="font-semibold text-2xl">
|
||||
Assembly doesn't support DSA v1
|
||||
</h3>
|
||||
<p
|
||||
class="mt-4 font-medium leading-normal text-grey-pure text-base"
|
||||
>
|
||||
Please create or switch to DSA v2.
|
||||
</p>
|
||||
</div>
|
||||
<Nuxt v-else-if="active" />
|
||||
|
||||
<web-3-modal slim v-else />
|
||||
</div>
|
||||
|
@ -95,6 +105,7 @@ import { useNetwork } from "~/composables/useNetwork";
|
|||
import { useModal } from "~/composables/useModal";
|
||||
import { useEagerConnect } from "~/composables/useEagerConnect";
|
||||
import Web3Modal from "~/components/modal/web3/Web3Modal.vue";
|
||||
import { useDSA } from "~/composables/useDSA";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
|
@ -105,6 +116,7 @@ export default defineComponent({
|
|||
},
|
||||
setup() {
|
||||
const { active, activate, deactivate, chainId } = useWeb3();
|
||||
const { activeAccount } = useDSA();
|
||||
const { activeNetworkId, activeNetwork, checkForNetworkMismatch } = useNetwork();
|
||||
const { isShown: isBackdropShown, close: closeBackdrop } = useBackdrop()
|
||||
const { redirect } = useContext()
|
||||
|
@ -154,6 +166,7 @@ export default defineComponent({
|
|||
})
|
||||
|
||||
return {
|
||||
activeAccount,
|
||||
active,
|
||||
activate,
|
||||
deactivate,
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
"bignumber.js": "^9.0.1",
|
||||
"core-js": "^3.15.1",
|
||||
"css-color-function": "^1.3.3",
|
||||
"dsa-connect": "^0.4.9",
|
||||
"dsa-connect": "^0.5.0",
|
||||
"nuxt": "^2.15.7",
|
||||
"qrcode": "^1.4.4",
|
||||
"slugify": "^1.6.0",
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
|
||||
<div class="ml-2"><Info text="Debt/Collateral ratio" /></div>
|
||||
</div>
|
||||
<span>Max - {{ formatPercent(position.maxLiquidation) }}</span>
|
||||
<span>Max - {{ formatPercent(maxLiquidation) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -207,7 +207,8 @@ export default defineComponent({
|
|||
totalSupply,
|
||||
totalBorrow,
|
||||
status,
|
||||
liquidation
|
||||
liquidation,
|
||||
maxLiquidation,
|
||||
} = useAaveV2Position();
|
||||
|
||||
const { div } = useBigNumber();
|
||||
|
@ -236,7 +237,8 @@ export default defineComponent({
|
|||
formatUsd,
|
||||
formatPercent,
|
||||
color,
|
||||
text
|
||||
text,
|
||||
maxLiquidation,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
@ -38,6 +38,7 @@ import MakerIcon from "~/assets/icons/makerdao.svg?inline";
|
|||
import OneInchIcon from "~/assets/icons/1inch.svg?inline";
|
||||
import LiquityIcon from "~/assets/icons/liquity.svg?inline";
|
||||
import ReflexerIcon from "~/assets/icons/reflexer.svg?inline";
|
||||
import YearnIcon from "~/assets/icons/yearn.svg?inline";
|
||||
|
||||
const appsPerNetwork = {
|
||||
mainnet: [
|
||||
|
@ -82,6 +83,13 @@ const appsPerNetwork = {
|
|||
name: "Reflexer Finance",
|
||||
url: "/mainnet/reflexer",
|
||||
description: "Collateralized RAI Debt"
|
||||
},
|
||||
{
|
||||
id: "yearn-v2",
|
||||
icon: YearnIcon,
|
||||
name: "Yearn",
|
||||
url: "/mainnet/yearn-v2",
|
||||
description: "Automated Yield Strategies"
|
||||
}
|
||||
],
|
||||
polygon: [
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
|
||||
<div class="ml-2"><Info text="Debt/Collateral ratio" /></div>
|
||||
</div>
|
||||
<span>Max - {{ formatPercent(position.maxLiquidation) }}</span>
|
||||
<span>Max - {{ formatPercent(liquidation) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -205,7 +205,7 @@ export default defineComponent({
|
|||
totalSupply,
|
||||
totalBorrow,
|
||||
status,
|
||||
liquidation
|
||||
liquidation,
|
||||
} = useCompoundPosition();
|
||||
|
||||
const { div } = useBigNumber();
|
||||
|
@ -234,7 +234,8 @@ export default defineComponent({
|
|||
formatUsd,
|
||||
formatPercent,
|
||||
color,
|
||||
text
|
||||
text,
|
||||
liquidation,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
100
pages/mainnet/yearn-v2.vue
Normal file
100
pages/mainnet/yearn-v2.vue
Normal file
|
@ -0,0 +1,100 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<nuxt-link
|
||||
to="/"
|
||||
class="text-[#C0C5D7] text-lg font-semibold flex items-center"
|
||||
>
|
||||
<BackIcon class="w-4 h-4 mr-3" />
|
||||
Apps
|
||||
</nuxt-link>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<div
|
||||
style="background: radial-gradient(42.15% 42.15% at 48.94% 48.94%, #D6DAE0 75.67%, #F0F3F9 100%), #C4C4C4;"
|
||||
class="w-16 h-16 rounded-full flex items-center justify-center border border-[#CCDCF3]"
|
||||
>
|
||||
<div
|
||||
class="w-12 h-12 rounded-full flex items-center justify-center bg-[#1874FF]"
|
||||
>
|
||||
<YearnIcon class="w-8 h-8 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="ml-4 text-primary-black text-2xl font-semibold">Yearn</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-[60px]">
|
||||
<div
|
||||
class="w-full flex flex-col mt-6 sm:flex-row sm:items-center sm:justify-between xl:mt-4"
|
||||
>
|
||||
<h2 class="text-primary-gray text-lg font-semibold">Your Positions</h2>
|
||||
|
||||
<div class="mt-4 sm:mt-0 sm:mr-1">
|
||||
<SearchInput
|
||||
v-model.trim="search"
|
||||
dense
|
||||
class="w-[200px]"
|
||||
placeholder="Search positions"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-3 grid w-full grid-cols-1 gap-4 sm:grid-cols-2 xxl:gap-6 min-w-max-content px-1"
|
||||
>
|
||||
<div v-for="item in filteredVaults" :key="item.symbol">
|
||||
<card-yearn
|
||||
:vault="item.address"
|
||||
:token-key="item.token.display_name.toLowerCase()"
|
||||
:supply="item.position.supply"
|
||||
:supply-usd="item.position.supplyUsd"
|
||||
:type="item.type"
|
||||
:price-in-usd="item.priceInUsd"
|
||||
:netAPY="item.apy.net_apy"
|
||||
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from "@nuxtjs/composition-api";
|
||||
import BackIcon from "~/assets/icons/back.svg?inline";
|
||||
import { useYearnV2Position } from "~/composables/protocols/useYearnV2Position";
|
||||
import { useFormatting } from "~/composables/useFormatting";
|
||||
import { useSearchFilter } from "~/composables/useSearchFilter";
|
||||
import CardYearn from "~/components/protocols/yearn-v2/CardYearn.vue";
|
||||
import YearnIcon from "~/assets/icons/yearn.svg?inline";
|
||||
import ButtonCTAOutlined from "~/components/common/input/ButtonCTAOutlined.vue";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
BackIcon,
|
||||
CardYearn,
|
||||
YearnIcon,
|
||||
ButtonCTAOutlined,
|
||||
},
|
||||
setup() {
|
||||
const { vaults } = useYearnV2Position();
|
||||
|
||||
const { formatUsd, formatPercent } = useFormatting();
|
||||
|
||||
const { filtered: filteredVaults, search } = useSearchFilter(
|
||||
vaults,
|
||||
"key",
|
||||
"display_name"
|
||||
);
|
||||
|
||||
return {
|
||||
filteredVaults,
|
||||
search,
|
||||
formatUsd,
|
||||
formatPercent
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user