diff --git a/assets/icons/currencies/rai.svg b/assets/icons/currencies/rai.svg index 16e95ce..d399f42 100644 --- a/assets/icons/currencies/rai.svg +++ b/assets/icons/currencies/rai.svg @@ -1,5 +1,5 @@ - + @@ -28,7 +28,7 @@ - + diff --git a/assets/icons/reflexer.svg b/assets/icons/reflexer.svg new file mode 100644 index 0000000..426969f --- /dev/null +++ b/assets/icons/reflexer.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/icons/currencies/rai.svg b/assets/img/icons/currencies/rai.svg index 16e95ce..d399f42 100644 --- a/assets/img/icons/currencies/rai.svg +++ b/assets/img/icons/currencies/rai.svg @@ -1,5 +1,5 @@ - + @@ -28,7 +28,7 @@ - + diff --git a/components/protocols/reflexer/CardReflexer.vue b/components/protocols/reflexer/CardReflexer.vue new file mode 100644 index 0000000..394666c --- /dev/null +++ b/components/protocols/reflexer/CardReflexer.vue @@ -0,0 +1,66 @@ +
+
+ +
+
{{ formatUsd(amountUsd) }}
+
+ {{ formatDecimal(amount) }} {{ symbol }} + +
+
+
+ {{ badge }} +
+
+ +
+ +
+ + +
+
+ + + \ No newline at end of file diff --git a/components/protocols/reflexer/DropdownReflexer.vue b/components/protocols/reflexer/DropdownReflexer.vue new file mode 100644 index 0000000..5eebec0 --- /dev/null +++ b/components/protocols/reflexer/DropdownReflexer.vue @@ -0,0 +1,104 @@ + + + diff --git a/components/sidebar/context/makerdao/SidebarMakerdaoSupply.vue b/components/sidebar/context/makerdao/SidebarMakerdaoSupply.vue index a8d543f..182cb3f 100644 --- a/components/sidebar/context/makerdao/SidebarMakerdaoSupply.vue +++ b/components/sidebar/context/makerdao/SidebarMakerdaoSupply.vue @@ -104,7 +104,7 @@ export default defineComponent({ const amount = ref('') const amountParsed = computed(() => parseSafeFloat(amount.value)) - const { tokenKey, token, debt, collateral, liquidation, liquidationMaxPrice, isNewVault, vaultId, vaultType, fetchPosition} = useMakerdaoPosition() + const { tokenKey, token, debt, collateral, liquidation, liquidationMaxPrice, isNewVault, vaultId, vaultType, fetchPosition } = useMakerdaoPosition() const symbol = computed(() => token.value?.symbol) const decimals = computed(() => token.value?.decimals) @@ -163,6 +163,8 @@ export default defineComponent({ from: account.value, onReceipt: async receipt => { showConfirmedTransaction(receipt.transactionHash); + + isNewVault.value = false; await fetchBalances(true); await fetchPosition(); diff --git a/components/sidebar/context/reflexer/SidebarReflexerBorrow.vue b/components/sidebar/context/reflexer/SidebarReflexerBorrow.vue new file mode 100644 index 0000000..9cf4ca2 --- /dev/null +++ b/components/sidebar/context/reflexer/SidebarReflexerBorrow.vue @@ -0,0 +1,196 @@ + + + diff --git a/components/sidebar/context/reflexer/SidebarReflexerCollateral.vue b/components/sidebar/context/reflexer/SidebarReflexerCollateral.vue new file mode 100644 index 0000000..62e05b7 --- /dev/null +++ b/components/sidebar/context/reflexer/SidebarReflexerCollateral.vue @@ -0,0 +1,83 @@ + + + diff --git a/components/sidebar/context/reflexer/SidebarReflexerPayback.vue b/components/sidebar/context/reflexer/SidebarReflexerPayback.vue new file mode 100644 index 0000000..eaa6d63 --- /dev/null +++ b/components/sidebar/context/reflexer/SidebarReflexerPayback.vue @@ -0,0 +1,220 @@ + + + diff --git a/components/sidebar/context/reflexer/SidebarReflexerSupply.vue b/components/sidebar/context/reflexer/SidebarReflexerSupply.vue new file mode 100644 index 0000000..cacffe8 --- /dev/null +++ b/components/sidebar/context/reflexer/SidebarReflexerSupply.vue @@ -0,0 +1,204 @@ + + + diff --git a/components/sidebar/context/reflexer/SidebarReflexerWithdraw.vue b/components/sidebar/context/reflexer/SidebarReflexerWithdraw.vue new file mode 100644 index 0000000..9bc827a --- /dev/null +++ b/components/sidebar/context/reflexer/SidebarReflexerWithdraw.vue @@ -0,0 +1,192 @@ + + + diff --git a/composables/protocols/useReflexerPosition.ts b/composables/protocols/useReflexerPosition.ts new file mode 100644 index 0000000..d4124c0 --- /dev/null +++ b/composables/protocols/useReflexerPosition.ts @@ -0,0 +1,346 @@ +import { computed, Ref, ref, watch } from "@nuxtjs/composition-api"; +import BigNumber from "bignumber.js"; +BigNumber.config({ POW_PRECISION: 200 }); +import abis from "~/constant/abis"; +import addresses from "~/constant/addresses"; +import reflexerSafes from "~/constant/tokens/safes"; +import { useBigNumber } from "~/composables/useBigNumber"; +import { useDSA } from "~/composables/useDSA"; +import { useToken } from "~/composables/useToken"; +import { useWeb3 } from "@instadapp/vue-web3"; +import { AbiItem } from "web3-utils"; +import { useBalances } from "../useBalances"; + +const defaultSafe = { + id: null, + tokenKey: "eth", + token: "ETH", + collateralName: "ETH-A", + collateral: "0", + debt: "0", + liquidatedCollateral: "0", + status: "0", + rate: "0", + liquidation: "0", + price: "0", + netvalue: "0" +}; + +const oracleRelayerAddress = "0x4ed9C0dCa0479bC64d8f4EB3007126D5791f7851"; + +const safeId = ref(null); +const safes = ref([]); +const isNewSafe = ref(false); +const safeTypes = ref([]); +const safeType = ref(""); + +const safe = computed(() => { + const vlt = safes.value.find(v => v.id === safeId.value); + if (!isNewSafe.value && !!vlt) { + return vlt; + } + + const vt = safeTypes.value.find(vt => vt.type === safeType.value); + if (vt) { + return { ...defaultSafe, ...vt }; + } + + const defaultSafeType = safeTypes.value[0]; + if (defaultSafeType) { + return { ...defaultSafe, ...defaultSafeType }; + } + + return defaultSafe; +}); + +export function useReflexerPosition( + collateralAmountRef: Ref = null, + debtAmountRef: Ref = null +) { + const { library } = useWeb3(); + const { activeAccount } = useDSA(); + const { isZero, ensureValue, times, div, max, gt, toBN } = useBigNumber(); + const { getTokenByKey } = useToken(); + const { prices } = useBalances(); + + const raiToken = computed(() => getTokenByKey("rai")); + const raiInUsd = computed(() => + raiToken.value ? prices.mainnet[raiToken.value.address] || "0" : "0" + ); + + const safeTokenType = computed(() => safe.value.safeTokenType); + + const price = computed(() => ensureValue(safe.value.price).toFixed()); + const spotPrice = computed(() => ensureValue(safe.value.spotPrice).toFixed()); + + const collateralUsd = computed(() => + times(collateral.value, price.value).toFixed() + ); + const collateral = computed(() => + ensureValue(safe.value.collateral).toFixed() + ); + + const liquidation = computed(() => + ensureValue(safe.value.liquidation).toFixed() + ); + const tokenKey = computed(() => safe.value.tokenKey); + + const token = computed(() => getTokenByKey(tokenKey.value)); + const symbol = computed(() => token.value.symbol ?? "ETH"); + const rate = computed(() => ensureValue(safe.value.rate).toFixed()); + const netValue = computed(() => ensureValue(safe.value.netValue).toFixed()); + + const status = computed(() => { + if (!collateralAmountRef || !debtAmountRef) + return ensureValue(safe.value.status).toFixed(); + return isZero(collateralAmountRef.value) && !isZero(debtAmountRef.value) + ? "1.1" + : div( + debtAmountRef.value, + times(collateralAmountRef.value, spotPrice.value) + ).toFixed(); + }); + + const liquidationPrice = computed(() => { + if (!collateralAmountRef || !debtAmountRef) + return max( + div(div(debt.value, collateral.value), liquidation.value), + "0" + ).toFixed(); + + return isZero(collateralAmountRef.value) && !isZero(debtAmountRef.value) + ? times(price.value, "1.1").toFixed() + : max( + div( + div(debtAmountRef.value, collateralAmountRef.value), + toBN(liquidation.value) + .multipliedBy(spotPrice.value) + .dividedBy(price.value) + ), + "0" + ).toFixed(); + }); + + const debt = computed(() => ensureValue(safe.value.debt).toFixed()); + const debtUsd = computed(() => + times(debt.value, raiInUsd.value).toFixed() + ); + + const minDebt = computed( + () => safeTypes.value[0]?.totalDebt?.toString() || "699" + ); + const debtCeilingReached = computed(() => + safeTypes.value?.some(v => + gt(v.overallTotalDebt, v.overallTotalDebtCeiling) + ) + ); + + const fetchPosition = async () => { + if (!library.value) { + return; + } + + safeTypes.value = await getSafeTypes(library.value); + + if (!activeAccount.value) { + return; + } + safes.value = await getSafes(activeAccount.value.address, library.value); + if (safes.value.length > 0 && !safeId.value) { + safeId.value = safes.value[0].id; + } + }; + + watch( + library, + async val => { + if (val) { + fetchPosition(); + } + }, + { immediate: true } + ); + + watch( + activeAccount, + async val => { + if (val) { + fetchPosition(); + } + }, + { immediate: true } + ); + + const selectSafe = vid => { + if (vid === safeId.value && !isNewSafe.value) return; + safeId.value = vid; + isNewSafe.value = false; + }; + + return { + fetchPosition, + safeId: computed(() => (isNewSafe.value ? "0" : safeId.value || "0")), + selectSafe, + safeTokenType, + safe, + safes, + safeType, + safeTypes, + isNewSafe, + collateralUsd, + collateral, + price, + raiInUsd, + liquidation, + tokenKey, + token, + symbol, + rate, + netValue, + status, + liquidationPrice, + liquidationMaxPrice: price, + debt, + debtUsd, + minDebt, + debtCeilingReached + }; +} + +async function getSafeTypes(web3) { + const reflexerResolveABI = abis.resolver.reflexer; + const reflexerResolveAddr = addresses.mainnet.resolver.reflexer; + + const reflexerResolverInstance = new web3.eth.Contract( + reflexerResolveABI as AbiItem[], + reflexerResolveAddr + ); + + try { + const rawData: any[] = await reflexerResolverInstance.methods + .getColInfo(reflexerSafes.types) + .call(); + + const rawRedemptionPrice = await web3.eth.getStorageAt( + oracleRelayerAddress, + 4 + ); + return reflexerSafes.allSafes.map( + ({ type, token, key: tokenKey, disabled, safeTokenType }, i) => { + const [rate, price, ratioCbyD, debtCeiling, totalDebt] = rawData[i]; + + return { + type, + token, + tokenKey, + disabled, + safeTokenType, + rate: calRate(rate), + redemptionPrice: new BigNumber(rawRedemptionPrice) + .dividedBy(1e27) + .toFixed(), + spotPrice: new BigNumber(price).dividedBy(1e27).toFixed(), + price: new BigNumber(price) + .times(rawRedemptionPrice) + .dividedBy(1e54) + .toFixed(), + liquidation: new BigNumber(1) + .dividedBy(new BigNumber(ratioCbyD).dividedBy(1e27)) + .toFixed(), + debtCeiling: debtCeiling, + totalDebt: new BigNumber(totalDebt).multipliedBy(1.00002).toFixed() + }; + } + ); + } catch (error) { + console.error(error); + return []; + } +} +async function getSafes(user, web3) { + try { + const reflexerResolveABI = abis.resolver.reflexer; + const reflexerResolveAddr = addresses.mainnet.resolver.reflexer; + + const reflexerResolverInstance = new web3.eth.Contract( + reflexerResolveABI as AbiItem[], + reflexerResolveAddr + ); + + const rawData: any[] = await reflexerResolverInstance.methods + .getSafes(user) + .call(); + + const rawRedemptionPrice = await web3.eth.getStorageAt( + oracleRelayerAddress, + 4 + ); + return rawData.map( + ([ + id, + owner, + type, + collInWei, + , + debtInWei, + liquidatedColInWei, + ratePerBlock, + priceInWei, + liquidationRatioCbyD, + urn + ]) => { + const collateral = new BigNumber(collInWei).dividedBy(1e18); + const debt = new BigNumber(debtInWei).dividedBy(1e18); + const spotPrice = new BigNumber(priceInWei).dividedBy(1e27); + const price = new BigNumber(priceInWei) + .times(rawRedemptionPrice) + .dividedBy(1e54); + + const safe = reflexerSafes.getSafeByType(type); + + return { + id, + owner, + type, + tokenKey: safe.key, + token: safe.token, + safeTokenType: safe.safeTokenType, + collateral: collateral.toFixed(), + debt: debt.toFixed(), + liquidatedCollateral: new BigNumber(liquidatedColInWei) + .dividedBy(1e18) + .toFixed(), + rate: calRate(ratePerBlock), + price: price.toFixed(), + spotPrice, + liquidation: new BigNumber(1) + .dividedBy(new BigNumber(liquidationRatioCbyD).dividedBy(1e27)) + .toFixed(), + urn, + netValue: collateral + .multipliedBy(price) + .minus(debt) + .toFixed(), + status: collateral.isZero() + ? "0" + : debt.dividedBy(collateral.multipliedBy(spotPrice)).toFixed() + }; + } + ); + } catch (error) { + console.error(error); + return []; + } +} + +function calRate(ilkRate) { + try { + return new BigNumber(ilkRate) + .dividedBy(1e27) + .pow(31545000) + .minus(1) + .toFixed(18); + } catch (error) { + console.log("error", error); + } +} diff --git a/composables/useSidebar.ts b/composables/useSidebar.ts index 2986629..d5ec48e 100644 --- a/composables/useSidebar.ts +++ b/composables/useSidebar.ts @@ -35,6 +35,12 @@ import SidebarLiquityTroveWithdraw from '~/components/sidebar/context/liquity/Si import SidebarLiquityTroveBorrow from '~/components/sidebar/context/liquity/SidebarLiquityTroveBorrow.vue' import SidebarLiquityTrovePayback from '~/components/sidebar/context/liquity/SidebarLiquityTrovePayback.vue' +import SidebarReflexerCollateral from '~/components/sidebar/context/reflexer/SidebarReflexerCollateral.vue' +import SidebarReflexerSupply from '~/components/sidebar/context/reflexer/SidebarReflexerSupply.vue' +import SidebarReflexerWithdraw from '~/components/sidebar/context/reflexer/SidebarReflexerWithdraw.vue' +import SidebarReflexerBorrow from '~/components/sidebar/context/reflexer/SidebarReflexerBorrow.vue' +import SidebarReflexerPayback from '~/components/sidebar/context/reflexer/SidebarReflexerPayback.vue' + import SidebarStrategySelection from '~/components/sidebar/context/strategy/SidebarStrategySelection.vue' import SidebarStrategy from '~/components/sidebar/context/strategy/SidebarStrategy.vue' @@ -69,6 +75,13 @@ const sidebars = { '/mainnet/liquity#trove-withdraw': { component: SidebarLiquityTroveWithdraw }, '/mainnet/liquity#trove-borrow': { component: SidebarLiquityTroveBorrow }, '/mainnet/liquity#trove-payback': { component: SidebarLiquityTrovePayback }, + + "/mainnet/reflexer": { component: null }, + '/mainnet/reflexer#collateral': { component: SidebarReflexerCollateral }, + "/mainnet/reflexer#supply": { component: SidebarReflexerSupply }, + "/mainnet/reflexer#withdraw": { component: SidebarReflexerWithdraw }, + "/mainnet/reflexer#borrow": { component: SidebarReflexerBorrow }, + "/mainnet/reflexer#payback": { component: SidebarReflexerPayback }, }; const sidebar = ref(null); diff --git a/composables/useValidators.ts b/composables/useValidators.ts index bd54ee2..77ad963 100644 --- a/composables/useValidators.ts +++ b/composables/useValidators.ts @@ -2,17 +2,19 @@ import { useBigNumber } from "./useBigNumber"; import { useFormatting } from "./useFormatting"; import { useMakerdaoPosition } from "~/composables/protocols/useMakerdaoPosition"; import { useLiquityPosition } from "./protocols/useLiquityPosition"; +import { useReflexerPosition } from "./protocols/useReflexerPosition"; export function useValidators() { const { formatNumber } = useFormatting(); const { isZero, minus, eq, gt, lt, gte, plus } = useBigNumber(); const { minDebt: makerMinDebt, vaultTypes } = useMakerdaoPosition(); + const { minDebt: reflexerMinDebt, safeTypes } = useReflexerPosition(); const { minDebt: liquityMinDebt, liquidationReserve: liquityLiquidationReserve, troveOpened: liquityTroveOpened } = useLiquityPosition(); - + function validateAmount(amountParsed, balance = null, options = null) { const mergedOptions = Object.assign( { msg: "Your amount exceeds your maximum limit." }, @@ -96,6 +98,50 @@ export function useValidators() { return null; } + function validateReflexerDebtCeiling(safeType, debtParsed = 0) { + const safe = safeTypes.value.find(v => v.type === safeType); + const { debtCeiling, totalDebt } = safe || {}; + + if (!isZero(debtCeiling) && !isZero(totalDebt)) { + const total = plus(totalDebt, debtParsed); + return gte(total, debtCeiling) + ? `${safeType} Collateral reached debt ceiling` + : null; + } + return null; + } + + function validateReflexerDebt( + debtParsed, + minDebt = reflexerMinDebt.value, + vaultId, + ) { + if (lt(debtParsed, minDebt) && gt(debtParsed, "0")) { + const vaultText = vaultId + ? vaultId !== "0" + ? `on vault #${vaultId}` + : `on new vault` + : ""; + + return `Minimum debt requirement is ${minDebt} RAI ${vaultText}` ; + } + + return null; + } + + function validateReflexerPaybackDebt( + debtParsed, + minDebt = reflexerMinDebt.value, + vaultId, + ) { + + if (lt(debtParsed, minDebt) && gt(debtParsed, "0")) { + return `Minimum debt requirement is ${minDebt} RAI. Payback additional ${debtParsed} RAI`; + } + + return null; + } + function validateLiquityDebt( debtParsed, minDebt = liquityMinDebt.value, @@ -129,6 +175,9 @@ export function useValidators() { validateMakerDebt, validateMakerDebtCeiling, validateLiquityDebt, - validateLiquityTroveExists + validateLiquityTroveExists, + validateReflexerDebtCeiling, + validateReflexerDebt, + validateReflexerPaybackDebt, }; } diff --git a/constant/abi/read/reflexer.json b/constant/abi/read/reflexer.json new file mode 100644 index 0000000..26891be --- /dev/null +++ b/constant/abi/read/reflexer.json @@ -0,0 +1,271 @@ +[ + { + "inputs": [ + { + "internalType": "string[]", + "name": "name", + "type": "string[]" + } + ], + "name": "getColInfo", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "borrowRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationRatio", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "debtCeiling", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "debtFloor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalDebt", + "type": "uint256" + } + ], + "internalType": "struct Helpers.ColInfo[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "redemptionRate", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getReflexerAddresses", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "manager", + "type": "address" + }, + { + "internalType": "address", + "name": "safeEngine", + "type": "address" + }, + { + "internalType": "address", + "name": "taxCollector", + "type": "address" + }, + { + "internalType": "address", + "name": "oracleRelayer", + "type": "address" + }, + { + "internalType": "address", + "name": "getSafes", + "type": "address" + } + ], + "internalType": "struct Helpers.ReflexerAddresses", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "getSafeById", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "string", + "name": "colType", + "type": "string" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "adjustedDebt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidatedCol", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "colPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationRatio", + "type": "uint256" + }, + { + "internalType": "address", + "name": "safeAddress", + "type": "address" + } + ], + "internalType": "struct Helpers.SafeData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "getSafes", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "string", + "name": "colType", + "type": "string" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "adjustedDebt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidatedCol", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "colPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationRatio", + "type": "uint256" + }, + { + "internalType": "address", + "name": "safeAddress", + "type": "address" + } + ], + "internalType": "struct Helpers.SafeData[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/constant/abis.ts b/constant/abis.ts index f978da4..974c464 100644 --- a/constant/abis.ts +++ b/constant/abis.ts @@ -7,7 +7,7 @@ import makerABI from "./abi/read/maker.json"; import makerProxyRegistryABI from "./abi/makerProxyRegistry.json"; import unipoolABI from "./abi/read/unipool.json"; import liquityABI from "./abi/read/liquity.json"; - +import reflexerABI from './abi/read/reflexer.json' const abis = { makerProxyRegistry: makerProxyRegistryABI, resolver: { @@ -19,6 +19,7 @@ const abis = { maker: makerABI, unipool: unipoolABI, liquity: liquityABI, + reflexer: reflexerABI } }; diff --git a/constant/addresses.ts b/constant/addresses.ts index ffd8594..a1b4ac0 100644 --- a/constant/addresses.ts +++ b/constant/addresses.ts @@ -9,25 +9,26 @@ const addresses = { compound: "0xcCAa4b1b3931749b8b6EF19C6b0B2c496703321b", maker: "0x84addce4fac0b6ee4b0cd132120d6d4b700e35c0", unipool: "0x22bddA39D14eD0aafeee36B6e784602fdDE64723", - liquity: '0xDAf2A39503463B0F41f899EDD82213b3c96b6Cf8', - }, + liquity: "0xDAf2A39503463B0F41f899EDD82213b3c96b6Cf8", + reflexer: "0x016ca8d0993d1a7073b01802a2e22fd0df7e633a" + } }, polygon: { core: { instaIndex: "0xA9B99766E6C676Cf1975c0D3166F96C0848fF5ad", - instaConnectorsV2: "0x2A00684bFAb9717C21271E0751BCcb7d2D763c88", + instaConnectorsV2: "0x2A00684bFAb9717C21271E0751BCcb7d2D763c88" }, resolver: { aave_v2: "0xD6E0803d0eB34af8Ea135835512D7E77960b28F1", accounts: "0xdF19Da523DA64bBE82eE0E4DFf00d676A8386474", balance: "0x04F8a41be023f839E709eeEaA0725FD766139A4d", merkleResolver: { - aave_v2: "0x2a26228e607ffD2aB2bD3aA49cBae0eDC6469Bf8", + aave_v2: "0x2a26228e607ffD2aB2bD3aA49cBae0eDC6469Bf8" }, - weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", - }, - }, + weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + } + } }; export default addresses; diff --git a/constant/tokens/safes.ts b/constant/tokens/safes.ts new file mode 100644 index 0000000..f69c115 --- /dev/null +++ b/constant/tokens/safes.ts @@ -0,0 +1,10 @@ +// prettier-ignore +const safes = [ + { type: 'ETH-A', token: 'ETH', key: 'eth', ratio: 0.6666666666666666, joinAddr: '0x2D3cD7b81c93f188F3CB8aD87c8Acc73d6226e3A', addr: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', stabiltyRate: 0, price: 0, typeBytes: '0x4554482d41000000000000000000000000000000000000000000000000000000', disabled: false, safeTokenType: 'token' }, + ] + +export default { + allSafes: safes, + types: safes.map(safe => safe.type), + getSafeByType: type => safes.find(safe => safe.type === type) +}; diff --git a/pages/index.vue b/pages/index.vue index e0b3ea3..62eb823 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -37,6 +37,7 @@ import CompoundIcon from "~/assets/icons/compound.svg?inline"; 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"; const appsPerNetwork = { mainnet: [ @@ -68,12 +69,19 @@ const appsPerNetwork = { url: "/1inch", description: "DEX Aggregator" }, - { + { id: "liquity", icon: LiquityIcon, name: "Liquity", url: "/mainnet/liquity", description: "Collateralized LUSD Debt" + }, + { + id: "reflexer", + icon: ReflexerIcon, + name: "Reflexer Finance", + url: "/mainnet/reflexer", + description: "Collateralized RAI Debt" } ], polygon: [ diff --git a/pages/mainnet/reflexer.vue b/pages/mainnet/reflexer.vue new file mode 100644 index 0000000..e7cbb4d --- /dev/null +++ b/pages/mainnet/reflexer.vue @@ -0,0 +1,297 @@ + + +