From 5515b729f0751478f06595bafdbab59249ee12d3 Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Mon, 18 Nov 2024 08:17:06 -0300
Subject: [PATCH 01/21] =?UTF-8?q?=E2=9C=A8Implemented=20change=20fee=20rec?=
=?UTF-8?q?iever=20in=20edit=20modal?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/dapp/app/layout.tsx | 2 +-
apps/dapp/app/page.tsx | 10 +-
.../components/DeployVault/VaultPreview.tsx | 46 ++--
.../InteractWithVault/EditVault.tsx | 240 ++++++++++++++++++
.../components/ManageVaults/InspectVault.tsx | 13 +-
.../components/ManageVaults/ManageVaults.tsx | 18 +-
apps/dapp/src/components/ui/button.tsx | 40 +++
apps/dapp/src/contexts/index.ts | 7 +-
apps/dapp/src/hooks/useVault.ts | 1 +
apps/dapp/src/providers/modal-provider.tsx | 5 +
.../src/store/lib/features/walletStore.ts | 12 +-
11 files changed, 356 insertions(+), 38 deletions(-)
create mode 100644 apps/dapp/src/components/InteractWithVault/EditVault.tsx
create mode 100644 apps/dapp/src/components/ui/button.tsx
diff --git a/apps/dapp/app/layout.tsx b/apps/dapp/app/layout.tsx
index 7ef5162d..81704878 100644
--- a/apps/dapp/app/layout.tsx
+++ b/apps/dapp/app/layout.tsx
@@ -6,7 +6,7 @@ export default function RootLayout({
children: ReactNode,
}) {
return (
-
+
{children}
diff --git a/apps/dapp/app/page.tsx b/apps/dapp/app/page.tsx
index 5e0585e9..e011fb93 100644
--- a/apps/dapp/app/page.tsx
+++ b/apps/dapp/app/page.tsx
@@ -1,5 +1,5 @@
"use client";
-import { Container } from '@chakra-ui/react'
+import { Container, HStack } from '@chakra-ui/react'
import { useSorobanReact } from '@soroban-react/core'
import ManageVaults from '@/components/ManageVaults/ManageVaults';
import {
@@ -13,10 +13,8 @@ ChartJS.register(ArcElement);
export default function Home() {
const { address } = useSorobanReact()
return (
-
-
-
-
-
+
+
+
);
}
diff --git a/apps/dapp/src/components/DeployVault/VaultPreview.tsx b/apps/dapp/src/components/DeployVault/VaultPreview.tsx
index c0cbea33..d1927875 100644
--- a/apps/dapp/src/components/DeployVault/VaultPreview.tsx
+++ b/apps/dapp/src/components/DeployVault/VaultPreview.tsx
@@ -155,6 +155,29 @@ interface VaultPreviewProps {
setFormControl: (args: FormControlInterface) => any;
}
+
+export const dropdownData = {
+ strategies: {
+ title: 'Strategies',
+ description: 'A strategy is a set of steps to be followed to execute an investment in one or several protocols.',
+ href: 'https://docs.defindex.io/whitepaper/10-whitepaper/01-introduction#core-concepts'
+ },
+ manager: {
+ title: 'Manager',
+ description: 'The Manager can rebalance the Vault, emergency withdraw and invest IDLE funds in strategies.',
+ href: 'https://docs.defindex.io/whitepaper/10-whitepaper/03-the-defindex-approach/02-contracts/01-vault-contract#management'
+ },
+ emergencyManager: {
+ title: 'Emergency manager',
+ description: 'The Emergency Manager has the authority to withdraw assets from the DeFindex in case of an emergency.',
+ href: 'https://docs.defindex.io/whitepaper/10-whitepaper/03-the-defindex-approach/02-contracts/01-vault-contract#emergency-management'
+ },
+ feeReceiver: {
+ title: 'Fee receiver',
+ description: ' Fee Receiver could be the manager using the same address, or it could be a different entity such as a streaming contract, a DAO, or another party.',
+ href: 'https://docs.defindex.io/whitepaper/10-whitepaper/03-the-defindex-approach/02-contracts/01-vault-contract#fee-collection'
+ }
+}
export const VaultPreview: React.FC = ({ data, accordionValue, setAccordionValue, formControl, setFormControl }) => {
const dispatch = useAppDispatch()
@@ -248,28 +271,7 @@ export const VaultPreview: React.FC = ({ data, accordionValue
dispatch(setVaultShare(input * 100))
}
- const dropdownData = {
- strategies: {
- title: 'Strategies',
- description: 'A strategy is a set of steps to be followed to execute an investment in one or several protocols.',
- href: 'https://docs.defindex.io/whitepaper/10-whitepaper/01-introduction#core-concepts'
- },
- manager: {
- title: 'Manager',
- description: 'The Manager can rebalance the Vault, emergency withdraw and invest IDLE funds in strategies.',
- href: 'https://docs.defindex.io/whitepaper/10-whitepaper/03-the-defindex-approach/02-contracts/01-vault-contract#management'
- },
- emergencyManager: {
- title: 'Emergency manager',
- description: 'The Emergency Manager has the authority to withdraw assets from the DeFindex in case of an emergency.',
- href: 'https://docs.defindex.io/whitepaper/10-whitepaper/03-the-defindex-approach/02-contracts/01-vault-contract#emergency-management'
- },
- feeReceiver: {
- title: 'Fee receiver',
- description: ' Fee Receiver could be the manager using the same address, or it could be a different entity such as a streaming contract, a DAO, or another party.',
- href: 'https://docs.defindex.io/whitepaper/10-whitepaper/03-the-defindex-approach/02-contracts/01-vault-contract#fee-collection'
- }
- }
+
return (
<>
setAccordionValue(e.value)}>
diff --git a/apps/dapp/src/components/InteractWithVault/EditVault.tsx b/apps/dapp/src/components/InteractWithVault/EditVault.tsx
new file mode 100644
index 00000000..2be0c278
--- /dev/null
+++ b/apps/dapp/src/components/InteractWithVault/EditVault.tsx
@@ -0,0 +1,240 @@
+import React, { useContext, useEffect, useState } from 'react'
+import { Address, xdr } from '@stellar/stellar-sdk'
+import { useSorobanReact } from '@soroban-react/core'
+
+import { useAppDispatch, useAppSelector } from '@/store/lib/storeHooks'
+import { setVaultFeeReceiver } from '@/store/lib/features/walletStore'
+import { setFeeReceiver } from '@/store/lib/features/vaultStore'
+
+import { ModalContext } from '@/contexts'
+import { VaultMethod, useVaultCallback, useVault } from '@/hooks/useVault'
+import { isValidAddress } from '@/helpers/address'
+
+import { DialogBody, DialogContent, DialogHeader } from '../ui/dialog'
+import { InputGroup } from '../ui/input-group'
+import {
+ Input,
+ Text,
+ Stack,
+ HStack,
+ Fieldset,
+ Link,
+ IconButton,
+} from '@chakra-ui/react'
+import { InfoTip } from '../ui/toggle-tip'
+import { Tooltip } from '../ui/tooltip'
+import { FaRegPaste } from 'react-icons/fa6'
+import { dropdownData } from '../DeployVault/VaultPreview'
+import { Button } from '../ui/button'
+
+const CustomInputField = ({
+ label,
+ value,
+ onChange,
+ handleClick,
+ placeholder,
+ invalid,
+ description,
+ href,
+}: {
+ label: string,
+ value: string,
+ onChange: (e: any) => void,
+ handleClick: (address: string) => void,
+ placeholder: string,
+ invalid: boolean,
+ description?: string,
+ href?: string,
+}) => {
+ const { address } = useSorobanReact()
+ return (
+
+ {label}
+
+ {description}
+
+ Learn more.
+
+
+ >
+ } />
+
+
+
+ handleClick(address!)}
+ >
+
+
+
+ }
+ >
+
+
+
+ A valid Stellar / Soroban address is required.
+
+ )
+}
+
+export const EditVaultModal = () => {
+ const selectedVault = useAppSelector(state => state.wallet.vaults.selectedVault)
+ const vaultMethod = selectedVault?.method
+
+ const { address } = useSorobanReact();
+ const vaultCB = useVaultCallback()
+ const vault = useVault()
+ const dispatch = useAppDispatch()
+ const { transactionStatusModal: statusModal, interactWithVaultModal: interactModal, inspectVaultModal: inspectModal } = useContext(ModalContext)
+ const [formControl, setFormControl] = useState({
+ feeReceiver: {
+ value: selectedVault?.feeReceiver ?? '',
+ isValid: false,
+ needsUpdate: false,
+ isLoading: false,
+ }
+ })
+
+
+
+
+ const handleFeeReceiverChange = (input: string) => {
+ const isValid = isValidAddress(input)
+ while (!isValid) {
+ setFormControl({
+ ...formControl,
+ feeReceiver: {
+ ...formControl.feeReceiver,
+ value: input,
+ isValid: false,
+ }
+ })
+ dispatch(setFeeReceiver(''))
+ return
+ }
+ setFormControl({
+ ...formControl,
+ feeReceiver: {
+ ...formControl.feeReceiver,
+ value: input,
+ isValid: true,
+ }
+ })
+ };
+
+ useEffect(() => {
+ setFormControl({
+ ...formControl,
+ feeReceiver: {
+ isValid: isValidAddress(selectedVault?.feeReceiver ?? ''),
+ value: selectedVault?.feeReceiver ?? '',
+ needsUpdate: false,
+ isLoading: false,
+ }
+ })
+ }, [selectedVault])
+ enum Values {
+ FEERECIEVER = 'feeReceiver',
+ MANAGER = 'manager',
+ EMERGENCYMANAGER = 'emergencyManager'
+ }
+
+ const updateValue = async (value: Values) => {
+ if (!address || !selectedVault) return;
+ let result: any;
+ if (value === Values.FEERECIEVER) {
+ setFormControl({ feeReceiver: { ...formControl.feeReceiver, isLoading: true } })
+ statusModal.initModal()
+ console.log('Updating fee receiver')
+ const caller = new Address(address);
+ const feeReceiver = new Address(formControl.feeReceiver.value);
+ const createDefindexParams: xdr.ScVal[] = [
+ caller.toScVal(),
+ feeReceiver.toScVal(),
+ ];
+ try {
+ result = await vaultCB(VaultMethod.SETFEERECIEVER, selectedVault.address, createDefindexParams, true).then((res) => {
+ console.log(res)
+ statusModal.handleSuccess(res.txHash)
+ dispatch(setVaultFeeReceiver(formControl.feeReceiver.value))
+ })
+ } catch (error: any) {
+ console.error('Error:', error)
+ statusModal.handleError(error.toString())
+ } finally {
+ setFormControl({ feeReceiver: { ...formControl.feeReceiver, isLoading: false } })
+ }
+
+ };
+ }
+
+ useEffect(() => {
+ if (!selectedVault?.feeReceiver) return
+ if (formControl.feeReceiver.value !== selectedVault.feeReceiver && formControl.feeReceiver.isValid) {
+ setFormControl({
+ ...formControl,
+ feeReceiver: {
+ ...formControl.feeReceiver,
+ needsUpdate: true,
+ }
+ })
+ } else if (formControl.feeReceiver.value === selectedVault.feeReceiver && formControl.feeReceiver.isValid) {
+ setFormControl({
+ ...formControl,
+ feeReceiver: {
+ ...formControl.feeReceiver,
+ needsUpdate: false,
+ }
+ })
+ }
+ }, [formControl.feeReceiver.value, formControl.feeReceiver.isValid])
+
+ if (!selectedVault) return null
+ return (
+ <>
+
+
+ Manage {selectedVault.name}
+
+
+
+ handleFeeReceiverChange(e.target.value)}
+ handleClick={(address) => setFormControl({ feeReceiver: { ...formControl.feeReceiver, isValid: true, value: address } })}
+ placeholder='GAFS3TLVM...'
+ invalid={!formControl.feeReceiver.isValid}
+ description={dropdownData.feeReceiver.description}
+ />
+
+
+ {formControl.feeReceiver.needsUpdate &&
+
+ }
+
+
+
+ >
+ )
+}
diff --git a/apps/dapp/src/components/ManageVaults/InspectVault.tsx b/apps/dapp/src/components/ManageVaults/InspectVault.tsx
index 2678d439..d61e2f48 100644
--- a/apps/dapp/src/components/ManageVaults/InspectVault.tsx
+++ b/apps/dapp/src/components/ManageVaults/InspectVault.tsx
@@ -11,6 +11,8 @@ import { Button, Grid, GridItem, HStack, Icon, Stack, Text } from "@chakra-ui/re
import { DialogBody, DialogContent, DialogFooter, DialogHeader } from "../ui/dialog"
import { FaRegEdit } from "react-icons/fa"
import { IoClose } from "react-icons/io5"
+import { ModalContext } from "@/contexts"
+import { useContext } from "react"
export const InspectVault = ({
@@ -24,6 +26,7 @@ export const InspectVault = ({
}) => {
const selectedVault: VaultData | undefined = useAppSelector(state => state.wallet.vaults.selectedVault)
const { address } = useSorobanReact()
+ const { editVaultModal: editModal } = useContext(ModalContext)
if (!selectedVault) return null
return (
@@ -34,11 +37,11 @@ export const InspectVault = ({
Inspect {selectedVault?.name ? selectedVault.name : shortenAddress(selectedVault.address)}
{address === selectedVault.manager &&
-
- { handleOpenDeployVault('edit_vault', true, selectedVault) }} css={{ cursor: "pointer" }}>
-
-
-
+
+ { editModal.setIsOpen(true) }} css={{ cursor: "pointer" }}>
+
+
+
}
diff --git a/apps/dapp/src/components/ManageVaults/ManageVaults.tsx b/apps/dapp/src/components/ManageVaults/ManageVaults.tsx
index 9fbe7223..aee2fc75 100644
--- a/apps/dapp/src/components/ManageVaults/ManageVaults.tsx
+++ b/apps/dapp/src/components/ManageVaults/ManageVaults.tsx
@@ -26,10 +26,17 @@ import {
Input,
Stack,
} from "@chakra-ui/react"
+import { EditVaultModal } from "../InteractWithVault/EditVault"
export const ManageVaults = () => {
const { address, activeChain } = useSorobanReact()
- const { inspectVaultModal: inspectModal, deployVaultModal: deployModal, interactWithVaultModal: interactModal, transactionStatusModal: txModal } = useContext(ModalContext)
+ const {
+ inspectVaultModal: inspectModal,
+ deployVaultModal: deployModal,
+ interactWithVaultModal: interactModal,
+ transactionStatusModal: txModal,
+ editVaultModal: editModal
+ } = useContext(ModalContext)
const dispatch = useAppDispatch()
const modalContext = useContext(ModalContext)
const vaults: VaultData[] = useAppSelector(state => state.wallet.vaults.createdVaults)
@@ -155,6 +162,15 @@ export const ManageVaults = () => {
onClose={() => { inspectModal.setIsOpen(false) }}
/>
+ { editModal.setIsOpen(e.open) }}
+ size={'lg'}
+ placement={'center'}
+ >
+
+
+
{ txModal.setIsOpen(e.open) }}
diff --git a/apps/dapp/src/components/ui/button.tsx b/apps/dapp/src/components/ui/button.tsx
new file mode 100644
index 00000000..21d5f4b5
--- /dev/null
+++ b/apps/dapp/src/components/ui/button.tsx
@@ -0,0 +1,40 @@
+import type { ButtonProps as ChakraButtonProps } from "@chakra-ui/react"
+import {
+ AbsoluteCenter,
+ Button as ChakraButton,
+ Span,
+ Spinner,
+} from "@chakra-ui/react"
+import * as React from "react"
+
+interface ButtonLoadingProps {
+ loading?: boolean
+ loadingText?: React.ReactNode
+}
+
+export interface ButtonProps extends ChakraButtonProps, ButtonLoadingProps {}
+
+export const Button = React.forwardRef(
+ function Button(props, ref) {
+ const { loading, disabled, loadingText, children, ...rest } = props
+ return (
+
+ {loading && !loadingText ? (
+ <>
+
+
+
+ {children}
+ >
+ ) : loading && loadingText ? (
+ <>
+
+ {loadingText}
+ >
+ ) : (
+ children
+ )}
+
+ )
+ },
+)
diff --git a/apps/dapp/src/contexts/index.ts b/apps/dapp/src/contexts/index.ts
index 8a96de99..b4d4e28d 100644
--- a/apps/dapp/src/contexts/index.ts
+++ b/apps/dapp/src/contexts/index.ts
@@ -40,6 +40,7 @@ export type ModalContextType = {
deployVaultModal: ToggleModalProps,
inspectVaultModal: ToggleModalProps,
interactWithVaultModal: ToggleModalProps,
+ editVaultModal: ToggleModalProps,
};
export const ModalContext = React.createContext({
@@ -72,5 +73,9 @@ export const ModalContext = React.createContext({
interactWithVaultModal: {
isOpen: false,
setIsOpen: () => {},
- }
+ },
+ editVaultModal: {
+ isOpen: false,
+ setIsOpen: () => {},
+ },
});
\ No newline at end of file
diff --git a/apps/dapp/src/hooks/useVault.ts b/apps/dapp/src/hooks/useVault.ts
index c5d6a1d6..d9062f72 100644
--- a/apps/dapp/src/hooks/useVault.ts
+++ b/apps/dapp/src/hooks/useVault.ts
@@ -23,6 +23,7 @@ export enum VaultMethod {
GETASSETAMMOUNT = "get_asset_amounts_for_dftokens",
GETIDLEFUNDS = "fetch_current_idle_funds",
GETINVESTEDFUNDS = "fetch_current_invested_funds",
+ SETFEERECIEVER = "set_fee_receiver",
}
const isObject = (val: unknown) => typeof val === 'object' && val !== null && !Array.isArray(val);
diff --git a/apps/dapp/src/providers/modal-provider.tsx b/apps/dapp/src/providers/modal-provider.tsx
index 8564ab67..669ffa29 100644
--- a/apps/dapp/src/providers/modal-provider.tsx
+++ b/apps/dapp/src/providers/modal-provider.tsx
@@ -17,6 +17,7 @@ export const ModalProvider = ({
const [isDeployVaultModalOpen, setIsDeployVaultModalOpen] = React.useState(false)
const [isInspectVaultModalOpen, setIsInspectVaultModalOpen] = React.useState(false)
const [isInteractWithVaultModalOpen, setIsInteractWithVaultModalOpen] = React.useState(false)
+ const [isEditVaultModalOpen, setIsEditVaultModalOpen] = React.useState(false)
const [isTransactionStatusModalOpen, setIsTransactionStatusModalOpen] = React.useState(false)
const [transactionStatusModalStep, setTransactionStatusModalStep] = React.useState(0)
@@ -101,6 +102,10 @@ export const ModalProvider = ({
isOpen: isInteractWithVaultModalOpen,
setIsOpen: setIsInteractWithVaultModalOpen,
},
+ editVaultModal: {
+ isOpen: isEditVaultModalOpen,
+ setIsOpen: setIsEditVaultModalOpen,
+ },
}
return (
diff --git a/apps/dapp/src/store/lib/features/walletStore.ts b/apps/dapp/src/store/lib/features/walletStore.ts
index f03bd9be..7c9be113 100644
--- a/apps/dapp/src/store/lib/features/walletStore.ts
+++ b/apps/dapp/src/store/lib/features/walletStore.ts
@@ -104,7 +104,14 @@ export const walletSlice = createSlice({
vault.userBalance = action.payload.vaule
}
})
- }
+ },
+ setVaultFeeReceiver: (state, action: PayloadAction) => {
+ state.vaults.createdVaults.forEach(vault => {
+ if (vault.address === state.vaults.selectedVault?.address) {
+ vault.feeReceiver = action.payload
+ }
+ })
+ },
},
extraReducers(builder) {
builder.addCase(fetchDefaultAddresses.pending, (state) => {
@@ -131,7 +138,8 @@ export const {
setVaults,
setVaultTVL,
resetSelectedVault,
- setVaultUserBalance
+ setVaultUserBalance,
+ setVaultFeeReceiver
} = walletSlice.actions
// Other code such as selectors can use the imported `RootState` type
From 88a68f758c9c9ba0c589c2baa341f7ee148f80ac Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Mon, 18 Nov 2024 10:05:55 -0300
Subject: [PATCH 02/21] =?UTF-8?q?=F0=9F=93=9DAdd=20env.example=20&=20updat?=
=?UTF-8?q?e=20readme.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/dapp/README.md | 17 ++++++++++++++++-
apps/dapp/env.example | 1 +
2 files changed, 17 insertions(+), 1 deletion(-)
create mode 100644 apps/dapp/env.example
diff --git a/apps/dapp/README.md b/apps/dapp/README.md
index a98bfa81..fd343629 100644
--- a/apps/dapp/README.md
+++ b/apps/dapp/README.md
@@ -2,7 +2,17 @@ This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-
## Getting Started
-First, run the development server:
+### Create a .env file
+
+Copy the .env.example file to .env and fill in the values.
+
+```bash
+cp env.example .env
+```
+
+
+## Running the app
+Run the development server:
```bash
npm run dev
@@ -14,6 +24,11 @@ pnpm dev
bun dev
```
+## Install dependencies
+```bash
+yarn install
+```
+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
diff --git a/apps/dapp/env.example b/apps/dapp/env.example
new file mode 100644
index 00000000..06c166d9
--- /dev/null
+++ b/apps/dapp/env.example
@@ -0,0 +1 @@
+NEXT_PUBLIC_TEST_TOKENS_ADMIN= # Test tokens admin address
\ No newline at end of file
From 853d0c020292fd47362a702920a0093d51ce4eff Mon Sep 17 00:00:00 2001
From: coderipper
Date: Mon, 18 Nov 2024 10:18:56 -0300
Subject: [PATCH 03/21] added get_fees to the vault it retruns (u32, u32)
---
apps/contracts/vault/src/fee.rs | 2 +-
apps/contracts/vault/src/interface.rs | 2 ++
apps/contracts/vault/src/lib.rs | 12 +++++++++---
3 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/apps/contracts/vault/src/fee.rs b/apps/contracts/vault/src/fee.rs
index 8a4dd847..5d5445c0 100644
--- a/apps/contracts/vault/src/fee.rs
+++ b/apps/contracts/vault/src/fee.rs
@@ -14,7 +14,7 @@ use crate::{
/// Fetches the current fee rate from the factory contract.
/// The fee rate is expressed in basis points (BPS).
-fn fetch_defindex_fee(e: &Env) -> u32 {
+pub fn fetch_defindex_fee(e: &Env) -> u32 {
let factory_address = get_factory(e);
// Interacts with the factory contract to get the fee rate.
e.invoke_contract(
diff --git a/apps/contracts/vault/src/interface.rs b/apps/contracts/vault/src/interface.rs
index 7dd40f1f..1beeef94 100644
--- a/apps/contracts/vault/src/interface.rs
+++ b/apps/contracts/vault/src/interface.rs
@@ -198,6 +198,8 @@ pub trait VaultTrait {
// TODO: DELETE THIS, USED FOR TESTING
/// Temporary method for testing purposes.
fn get_asset_amounts_for_dftokens(e: Env, df_token: i128) -> Map;
+
+ fn get_fees(e: Env) -> (u32, u32);
}
pub trait AdminInterfaceTrait {
diff --git a/apps/contracts/vault/src/lib.rs b/apps/contracts/vault/src/lib.rs
index ece2aec1..6dc5701c 100755
--- a/apps/contracts/vault/src/lib.rs
+++ b/apps/contracts/vault/src/lib.rs
@@ -24,7 +24,7 @@ mod utils;
use access::{AccessControl, AccessControlTrait, RolesDataKey};
use aggregator::{internal_swap_exact_tokens_for_tokens, internal_swap_tokens_for_exact_tokens};
-use fee::collect_fees;
+use fee::{collect_fees, fetch_defindex_fee};
use funds::{fetch_current_idle_funds, fetch_current_invested_funds, fetch_total_managed_funds}; //, fetch_idle_funds_for_asset};
use interface::{AdminInterfaceTrait, VaultManagementTrait, VaultTrait};
use investment::{check_and_execute_investments};
@@ -33,8 +33,7 @@ use models::{
OptionalSwapDetailsExactOut,
};
use storage::{
- get_assets, set_asset, set_defindex_protocol_fee_receiver, set_factory,
- set_total_assets, set_vault_fee, extend_instance_ttl
+ extend_instance_ttl, get_assets, get_vault_fee, set_asset, set_defindex_protocol_fee_receiver, set_factory, set_total_assets, set_vault_fee
};
use strategies::{
get_asset_allocation_from_address, get_strategy_asset, get_strategy_client,
@@ -568,6 +567,13 @@ impl VaultTrait for DeFindexVault {
extend_instance_ttl(&e);
calculate_asset_amounts_for_dftokens(&e, df_tokens)
}
+
+ fn get_fees(e: Env) -> (u32, u32) {
+ extend_instance_ttl(&e);
+ let defindex_protocol_fee = fetch_defindex_fee(&e);
+ let vault_fee = get_vault_fee(&e);
+ (defindex_protocol_fee, vault_fee)
+ }
}
#[contractimpl]
From 96e45faf4a7ffb89c891cb8dba55b40ae1b180e4 Mon Sep 17 00:00:00 2001
From: coderipper
Date: Mon, 18 Nov 2024 10:24:06 -0300
Subject: [PATCH 04/21] published addresses, new factory deployed
---
public/testnet.contracts.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/public/testnet.contracts.json b/public/testnet.contracts.json
index c00c6f35..a184b171 100644
--- a/public/testnet.contracts.json
+++ b/public/testnet.contracts.json
@@ -1,11 +1,11 @@
{
"ids": {
"hodl_strategy": "CAEYFO6TY5MMPHSX6CMUKSDHPFVLJKV4TFPHE4ZXAEER2NEIB5GSVBVG",
- "defindex_factory": "CBHW3ETUDAZ4FKKEEASONLALSZAYR6IMBA2THXKRPGRAVRG7UQLZFEKP"
+ "defindex_factory": "CARG5QZELODA44D3NB4LIEIJSEMWLJSKA6CNOT4FFGPRYUKC7JLDDZ6L"
},
"hashes": {
"hodl_strategy": "fcdb4a3c11525a1f32611951741bca5bc4196f58fd1633af37d5b35d30fdf5b0",
- "defindex_vault": "861b1b2734e65edb70cc632889d00ce0f07946110e3f957a76714ce9674c73ce",
+ "defindex_vault": "468b456399610600ae2718188e16052aabb7488493f7260d16b21c8f7dbf1001",
"defindex_factory": "d6522e73d98e7826782e0b8df6c15410d1b1be95cca985b3e6f1c88a27a11a92"
}
}
\ No newline at end of file
From 8f66b084642e4a7a2f5951a4df423ac5b9c9f9e3 Mon Sep 17 00:00:00 2001
From: coderipper
Date: Mon, 18 Nov 2024 15:30:04 -0300
Subject: [PATCH 05/21] fixed version and added core toml
---
apps/contracts/Cargo.lock | 16 ++---
apps/contracts/Cargo.toml | 3 +-
apps/contracts/strategies/core/Cargo.toml | 3 +
apps/contracts/strategies/core/README.md | 77 +++++++++++++++++++++++
4 files changed, 90 insertions(+), 9 deletions(-)
create mode 100644 apps/contracts/strategies/core/README.md
diff --git a/apps/contracts/Cargo.lock b/apps/contracts/Cargo.lock
index 64415e34..234d602b 100644
--- a/apps/contracts/Cargo.lock
+++ b/apps/contracts/Cargo.lock
@@ -94,7 +94,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "blend_strategy"
-version = "1.0.0"
+version = "0.1.0"
dependencies = [
"defindex-strategy-core",
"soroban-sdk",
@@ -281,21 +281,21 @@ dependencies = [
[[package]]
name = "defindex-factory"
-version = "1.0.0"
+version = "0.1.0"
dependencies = [
"soroban-sdk",
]
[[package]]
name = "defindex-strategy-core"
-version = "1.0.0"
+version = "0.1.0"
dependencies = [
"soroban-sdk",
]
[[package]]
name = "defindex-vault"
-version = "1.0.0"
+version = "0.1.0"
dependencies = [
"defindex-strategy-core",
"soroban-sdk",
@@ -449,7 +449,7 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
[[package]]
name = "fixed_apr_strategy"
-version = "1.0.0"
+version = "0.1.0"
dependencies = [
"defindex-strategy-core",
"soroban-sdk",
@@ -540,7 +540,7 @@ dependencies = [
[[package]]
name = "hodl_strategy"
-version = "1.0.0"
+version = "0.1.0"
dependencies = [
"defindex-strategy-core",
"soroban-sdk",
@@ -1200,7 +1200,7 @@ dependencies = [
[[package]]
name = "soroswap_strategy"
-version = "1.0.0"
+version = "0.1.0"
dependencies = [
"defindex-strategy-core",
"soroban-sdk",
@@ -1519,7 +1519,7 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "xycloans_adapter"
-version = "1.0.0"
+version = "0.1.0"
dependencies = [
"defindex-strategy-core",
"soroban-sdk",
diff --git a/apps/contracts/Cargo.toml b/apps/contracts/Cargo.toml
index 9dee20c8..79b3c9e0 100644
--- a/apps/contracts/Cargo.toml
+++ b/apps/contracts/Cargo.toml
@@ -6,10 +6,11 @@ exclude = [
resolver = "2"
[workspace.package]
-version = "1.0.0"
+version = "0.1.0"
edition = "2021"
license = "GPL-3.0"
repository = "https://github.com/paltalabs/defindex"
+homepage = "https://defindex.io"
[workspace.dependencies]
soroban-sdk = "21.7.6"
diff --git a/apps/contracts/strategies/core/Cargo.toml b/apps/contracts/strategies/core/Cargo.toml
index 7949f80b..97cc36d3 100644
--- a/apps/contracts/strategies/core/Cargo.toml
+++ b/apps/contracts/strategies/core/Cargo.toml
@@ -6,6 +6,9 @@ license = { workspace = true }
edition = { workspace = true }
publish = false
repository = { workspace = true }
+homepage = { workspace = true }
+keywords = ["soroban", "defindex", "strategy", "core", "stellar"]
+categories = ["cryptography::cryptocurrencies", "no-std", "development-tools"]
[dependencies]
soroban-sdk = { workspace = true }
diff --git a/apps/contracts/strategies/core/README.md b/apps/contracts/strategies/core/README.md
new file mode 100644
index 00000000..0f59f1b9
--- /dev/null
+++ b/apps/contracts/strategies/core/README.md
@@ -0,0 +1,77 @@
+# DeFindex Strategy Core
+
+The defindex-strategy-core package is a foundational library designed to facilitate the development of strategies for DeFindex. It provides reusable abstractions and utilities that streamline the creation, management, and integration of strategies into the DeFindex ecosystem.
+
+### Features
+
+- **Reusable Events**: Predefined events to log actions such as deposits, withdrawals, and harvests.
+- **Custom Errors**: A unified error handling system to ensure consistent and informative feedback across strategies.
+- **Core Abstractions**: Base traits and utilities to define and implement strategies with minimal boilerplate.
+
+### Structure
+
+This package includes the following modules:
+1. **Error**: Provides custom error types to handle various edge cases and ensure smooth execution.
+2. **Event**: Includes predefined events for logging and monitoring strategy activity.
+3. **Core Traits**: Defines the DeFindexStrategyTrait, which serves as the contract for developing new strategies.
+
+### Installation
+
+Add the defindex-strategy-core package to your Cargo.toml dependencies:
+
+```toml
+[dependencies]
+defindex-strategy-core = "0.1.0"
+```
+
+### Usage
+
+Here is a simple example of how to use this package to build a custom strategy:
+
+1. Import the Core Library
+```rust
+use defindex_strategy_core::{DeFindexStrategyTrait, StrategyError, event};
+```
+
+2. Implement the Strategy Trait
+
+Define your custom strategy by implementing the DeFindexStrategyTrait:
+```rust
+#[contract]
+struct MyCustomStrategy;
+
+#[contractimpl]
+impl DeFindexStrategyTrait for MyCustomStrategy {
+ fn initialize(e: Env, asset: Address, init_args: Vec) -> Result<(), StrategyError> {
+ // Initialization logic
+ Ok(())
+ }
+
+ fn deposit(e: Env, amount: i128, from: Address) -> Result<(), StrategyError> {
+ // Deposit logic
+ Ok(())
+ }
+
+ fn withdraw(e: Env, amount: i128, from: Address) -> Result {
+ // Withdrawal logic
+ Ok(amount)
+ }
+
+ fn balance(e: Env, from: Address) -> Result {
+ // Balance check logic
+ Ok(0)
+ }
+
+ fn harvest(e: Env, from: Address) -> Result<(), StrategyError> {
+ // Harvest logic
+ Ok(())
+ }
+}
+```
+
+3. Emit Events
+
+Use the event module to log actions:
+```rust
+event::emit_deposit(&e, String::from("MyCustomStrategy"), amount, from.clone());
+```
\ No newline at end of file
From 742aa4f45fe84a3b26303e24532a5ddbd083150a Mon Sep 17 00:00:00 2001
From: coderipper
Date: Mon, 18 Nov 2024 15:30:58 -0300
Subject: [PATCH 06/21] publish tru
---
apps/contracts/strategies/core/Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/contracts/strategies/core/Cargo.toml b/apps/contracts/strategies/core/Cargo.toml
index 97cc36d3..c597e1b6 100644
--- a/apps/contracts/strategies/core/Cargo.toml
+++ b/apps/contracts/strategies/core/Cargo.toml
@@ -4,7 +4,7 @@ version = { workspace = true }
authors = ["coderipper "]
license = { workspace = true }
edition = { workspace = true }
-publish = false
+publish = true
repository = { workspace = true }
homepage = { workspace = true }
keywords = ["soroban", "defindex", "strategy", "core", "stellar"]
From 4c589625993b1290fb1ad4d3eeb6bd6a10abcde5 Mon Sep 17 00:00:00 2001
From: coderipper
Date: Mon, 18 Nov 2024 15:34:01 -0300
Subject: [PATCH 07/21] added description
---
apps/contracts/strategies/core/Cargo.toml | 1 +
1 file changed, 1 insertion(+)
diff --git a/apps/contracts/strategies/core/Cargo.toml b/apps/contracts/strategies/core/Cargo.toml
index c597e1b6..a32161a9 100644
--- a/apps/contracts/strategies/core/Cargo.toml
+++ b/apps/contracts/strategies/core/Cargo.toml
@@ -1,5 +1,6 @@
[package]
name = "defindex-strategy-core"
+description = "A foundational library for developing and integrating strategies into the DeFindex ecosystem, providing reusable abstractions, events, and custom error handling."
version = { workspace = true }
authors = ["coderipper "]
license = { workspace = true }
From fe508d894db6f87ef0de6c3d14dd2a9b9c2109bf Mon Sep 17 00:00:00 2001
From: coderipper
Date: Mon, 18 Nov 2024 15:38:32 -0300
Subject: [PATCH 08/21] updated scf rtacker
---
scf-tracker.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scf-tracker.md b/scf-tracker.md
index f10d6fc0..0366cf32 100644
--- a/scf-tracker.md
+++ b/scf-tracker.md
@@ -34,7 +34,7 @@
- **Result:**
- ✅ Code available on [GitHub](https://github.com/paltalabs/defindex/tree/main/apps/contracts/strategies)
- - 🛠️ Adapter Struct published at crates.io
+ - ✅ Adapter Struct published at crates.io
- 🛠️ SEP proposal
---
From fc9b2198e14781f0e86b87ff0b6f1b50af5ea7e8 Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Mon, 18 Nov 2024 20:25:56 -0300
Subject: [PATCH 09/21] =?UTF-8?q?=F0=9F=A9=B9Fix=20resetNewVault?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/components/DeployVault/ConfirmDelpoyModal.tsx | 4 +++-
apps/dapp/src/store/lib/features/vaultStore.ts | 11 ++++++++++-
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
index eec5324c..616acc00 100644
--- a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
+++ b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
@@ -18,6 +18,7 @@ import { ModalContext, TransactionStatusModalStatus } from "@/contexts";
import { AccordionItems, FormControlInterface, VaultPreview } from "./VaultPreview";
import { DialogBody, DialogCloseTrigger, DialogFooter, DialogHeader, DialogTitle } from "../ui/dialog";
import { Button } from "@chakra-ui/react"
+import { resetNewVault } from "@/store/lib/features/vaultStore";
interface Status {
isSuccess: boolean,
@@ -279,8 +280,9 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
...newVault,
address: parsedResult
}
- txModal.handleSuccess(result.txHash);
+ await txModal.handleSuccess(result.txHash);
dispatch(pushVault(tempVault));
+ dispatch(resetNewVault());
return result;
}
diff --git a/apps/dapp/src/store/lib/features/vaultStore.ts b/apps/dapp/src/store/lib/features/vaultStore.ts
index c09fb6f8..7400031f 100644
--- a/apps/dapp/src/store/lib/features/vaultStore.ts
+++ b/apps/dapp/src/store/lib/features/vaultStore.ts
@@ -97,7 +97,16 @@ export const newVaultSlice = createSlice({
state.TVL = action.payload.TVL;
}),
resetNewVault: ((state) => {
- state = initialState;
+ state.address = "";
+ state.emergencyManager = "";
+ state.feeReceiver = "";
+ state.manager = "";
+ state.name = "";
+ state.symbol = "";
+ state.vaultShare = 0;
+ state.assets = [];
+ state.amounts = [];
+ state.TVL = 0;
}),
}
})
From 5c83021f3a305e688a6310fee0d6d31d4e9cac86 Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Mon, 18 Nov 2024 20:29:18 -0300
Subject: [PATCH 10/21] =?UTF-8?q?=F0=9F=90=9BFix=20asset=20symbol=20assign?=
=?UTF-8?q?ment=20in=20useVault=20hook?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/dapp/src/hooks/useVault.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/apps/dapp/src/hooks/useVault.ts b/apps/dapp/src/hooks/useVault.ts
index c5d6a1d6..9a363003 100644
--- a/apps/dapp/src/hooks/useVault.ts
+++ b/apps/dapp/src/hooks/useVault.ts
@@ -80,7 +80,8 @@ export const useVault = (vaultAddress?: string | undefined) => {
]);
for (let asset of assets){
const symbol = await getTokenSymbol(asset.address, sorobanContext);
- if(symbol === 'native') asset.symbol = 'XLM';
+ if(symbol === 'native') asset.symbol = 'XLM'
+ else asset.symbol = symbol
}
getInvestedFunds(vaultAddress);
const newData: VaultData = {
From 27d9b14049b32fa1147e75bcd5f71a19b37a7264 Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Mon, 18 Nov 2024 21:26:36 -0300
Subject: [PATCH 11/21] =?UTF-8?q?=F0=9F=A9=B9Remove=20unnecesary=20loading?=
=?UTF-8?q?=20on=20select=20strategy?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../DeployVault/AddNewStrategyButton.tsx | 112 ++++++++----------
1 file changed, 47 insertions(+), 65 deletions(-)
diff --git a/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx b/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
index 86ff3b42..72496720 100644
--- a/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
+++ b/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
@@ -44,13 +44,34 @@ function AddNewStrategyButton() {
const [open, setOpen] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const [defaultStrategies, setDefaultStrategies] = useState([])
- const [asset, setAsset] = useState({ address: '', strategies: [] })
+ const [selectedAsset, setSelectedAsset] = useState({ address: '', strategies: [], symbol: '' })
+ const [assets, setAssets] = useState([])
const [amountInput, setAmountInput] = useState({ amount: 0, enabled: false })
+ const resetForm = () => {
+ setSelectedAsset({ address: '', strategies: [], symbol: '' })
+ setAmountInput({ amount: 0, enabled: false })
+ setOpen(false)
+ }
+
+ const getSymbol = async (address: string) => {
+ const symbol = await getTokenSymbol(address, sorobanContext)
+ if (!symbol) return '';
+ return symbol === 'native' ? 'XLM' : symbol
+ }
+
useEffect(() => {
const fetchStrategies = async () => {
const tempStrategies = await getDefaultStrategies(activeChain?.name?.toLowerCase() || 'testnet')
- for (const strategy of tempStrategies) {
+ setDefaultStrategies(tempStrategies)
+ }
+ fetchStrategies();
+ }, [activeChain?.networkPassphrase])
+
+ useEffect(() => {
+ const fetchStrategies = async () => {
+ const rawDefaultStrategies = await getDefaultStrategies(activeChain?.name?.toLowerCase() || 'testnet')
+ const defaultStrategiesWithAssets = await Promise.all(rawDefaultStrategies.map(async (strategy) => {
const assetAddress = await strategyCallback(
strategy.address,
StrategyMethod.ASSET,
@@ -62,66 +83,39 @@ function AddNewStrategyButton() {
return asset;
})
const assetSymbol = await getSymbol(assetAddress)
- setAsset({ ...asset, address: assetAddress, symbol: assetSymbol! })
+ const asset = { address: assetAddress, strategies: [strategy], symbol: assetSymbol! }
+ return asset
}
- setDefaultStrategies(tempStrategies)
+ ))
+ setAssets(defaultStrategiesWithAssets)
}
fetchStrategies();
}, [activeChain?.networkPassphrase])
- const resetForm = () => {
- setAsset({ address: '', strategies: [] })
- setAmountInput({ amount: 0, enabled: false })
- setOpen(false)
- }
-
- const getSymbol = async (address: string) => {
- const symbol = await getTokenSymbol(address, sorobanContext)
- if (!symbol) return '';
- return symbol === 'native' ? 'XLM' : symbol
+ const handleSelectStrategy = (value: boolean, strategy: Strategy) => {
+ const selectedAsset = assets.find((asset) => asset.strategies.some((str) => str.address === strategy.address))
+ if (selectedAsset) {
+ setSelectedAsset(selectedAsset)
+ }
}
- const handleSelectStrategy = (value: boolean, strategy: Strategy) => {
- setIsLoading(true)
- switch (value) {
- case true:
- const fetchAssets = async () => {
- try {
- const asset = await strategyCallback(
- strategy.address,
- StrategyMethod.ASSET,
- undefined,
- false
- ).then((result) => {
- const resultScval = result as xdr.ScVal;
- const asset = scValToNative(resultScval);
- return asset;
- });
- const symbol = await getSymbol(asset);
- const newAsset = { address: asset, symbol: symbol!, strategies: [strategy] }
- console.log(newAsset)
- setAsset({ address: asset, symbol: symbol!, strategies: [strategy] })
- } catch (error) {
- console.error(error);
- } finally {
- setIsLoading(false)
- }
- };
- fetchAssets();
- break
- case false:
- setAsset({ ...asset, strategies: asset.strategies.filter(str => str.address !== strategy.address) })
- setIsLoading(false)
- break
+ const handleAmountInput = async (e: any) => {
+ const input = e.target.value
+ const decimalRegex = /^(\d+)?(\.\d{0,7})?$/
+ if (!decimalRegex.test(input)) return
+ if (input.startsWith('.')) {
+ setAmountInput({ amount: 0 + input, enabled: true });
+ return
}
+ setAmountInput({ amount: input, enabled: true });
}
const addAsset = async () => {
const newAsset: Asset = {
- address: asset.address,
- strategies: asset.strategies,
- symbol: asset.symbol
+ address: selectedAsset.address,
+ strategies: selectedAsset.strategies,
+ symbol: selectedAsset.symbol
}
await dispatch(pushAsset(newAsset))
if (amountInput.enabled && amountInput.amount! > 0) {
@@ -130,18 +124,6 @@ function AddNewStrategyButton() {
resetForm()
}
-
-
- const handleAmountInput = async (e: any) => {
- const input = e.target.value
- const decimalRegex = /^(\d+)?(\.\d{0,7})?$/
- if (!decimalRegex.test(input)) return
- if (input.startsWith('.')) {
- setAmountInput({ amount: 0 + input, enabled: true });
- return
- }
- setAmountInput({ amount: input, enabled: true });
- }
return (
{ setOpen(e.open) }} placement={'center'}>
@@ -161,11 +143,11 @@ function AddNewStrategyButton() {
{isLoading && }
{!isLoading && str.address === strategy.address)}
+ checked={selectedAsset.strategies.some((str) => str.address === strategy.address)}
onCheckedChange={(e) => handleSelectStrategy(!!e.checked, strategy)}
label={strategy.name}
/>}
- {asset.strategies.some((str) => str.address === strategy.address) &&
+ {selectedAsset.strategies.some((str) => str.address === strategy.address) &&
Initial deposit:
@@ -187,7 +169,7 @@ function AddNewStrategyButton() {
@@ -204,7 +186,7 @@ function AddNewStrategyButton() {
Close
Date: Mon, 18 Nov 2024 21:39:28 -0300
Subject: [PATCH 12/21] =?UTF-8?q?=F0=9F=A9=B9Fix=20vault=20tvl=20after=20c?=
=?UTF-8?q?reate=20&=20deposit?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/InteractWithVault/InteractWithVault.tsx | 2 +-
apps/dapp/src/components/ManageVaults/AllVaults.tsx | 6 +++++-
apps/dapp/src/store/lib/features/walletStore.ts | 8 ++++----
3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx b/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
index 427033be..cb15e024 100644
--- a/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
+++ b/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
@@ -71,7 +71,7 @@ export const InteractWithVault = () => {
).finally(async () => {
const newTVL = await vault.getTVL(selectedVault?.address!)
const parsedNewTVL = Number(newTVL) / 10 ** 7
- dispatch(setVaultTVL(parsedNewTVL))
+ dispatch(setVaultTVL({ value: parsedNewTVL, address: selectedVault?.address! }))
});
}
catch (error: any) {
diff --git a/apps/dapp/src/components/ManageVaults/AllVaults.tsx b/apps/dapp/src/components/ManageVaults/AllVaults.tsx
index 2e63d4b1..6e2d2590 100644
--- a/apps/dapp/src/components/ManageVaults/AllVaults.tsx
+++ b/apps/dapp/src/components/ManageVaults/AllVaults.tsx
@@ -6,7 +6,7 @@ import { shortenAddress } from '@/helpers/address'
import { useVault } from '@/hooks/useVault'
import { FactoryMethod, useFactoryCallback } from '@/hooks/useFactory'
-import { setIsVaultsLoading, setVaults, setVaultUserBalance } from '@/store/lib/features/walletStore'
+import { setIsVaultsLoading, setVaults, setVaultTVL, setVaultUserBalance } from '@/store/lib/features/walletStore'
import { useAppDispatch, useAppSelector } from '@/store/lib/storeHooks'
import { VaultData } from '@/store/lib/types'
@@ -94,6 +94,10 @@ export const AllVaults = ({
if (userBalance) {
dispatch(setVaultUserBalance({ address: v.address, vaule: userBalance }))
}
+ const TVL = await vault.getTVL(v.address)
+ if (TVL) {
+ dispatch(setVaultTVL({ value: TVL, address: v.address }))
+ }
})
}
}, [createdVaults])
diff --git a/apps/dapp/src/store/lib/features/walletStore.ts b/apps/dapp/src/store/lib/features/walletStore.ts
index f03bd9be..307a911b 100644
--- a/apps/dapp/src/store/lib/features/walletStore.ts
+++ b/apps/dapp/src/store/lib/features/walletStore.ts
@@ -88,10 +88,10 @@ export const walletSlice = createSlice({
setVaults: (state, action: PayloadAction) => {
state.vaults.createdVaults = action.payload
},
- setVaultTVL: (state, action: PayloadAction) => {
+ setVaultTVL: (state, action: PayloadAction<{address:string, value: number}>) => {
state.vaults.createdVaults.forEach(vault => {
- if (vault.address === state.vaults.selectedVault?.address) {
- vault.TVL = action.payload
+ if (vault.address === action.payload.address) {
+ vault.TVL = action.payload.value
}
})
},
@@ -104,7 +104,7 @@ export const walletSlice = createSlice({
vault.userBalance = action.payload.vaule
}
})
- }
+ },
},
extraReducers(builder) {
builder.addCase(fetchDefaultAddresses.pending, (state) => {
From 98ca74d1dd32254adaa04dffa013add43f6d5434 Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:01:03 -0300
Subject: [PATCH 13/21] =?UTF-8?q?=F0=9F=90=9BFix=20user=20balance=20retrie?=
=?UTF-8?q?val=20logic=20in=20AllVaults=20component?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/components/ManageVaults/AllVaults.tsx | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/apps/dapp/src/components/ManageVaults/AllVaults.tsx b/apps/dapp/src/components/ManageVaults/AllVaults.tsx
index 6e2d2590..68274157 100644
--- a/apps/dapp/src/components/ManageVaults/AllVaults.tsx
+++ b/apps/dapp/src/components/ManageVaults/AllVaults.tsx
@@ -85,15 +85,11 @@ export const AllVaults = ({
useEffect(() => {
getDefindexVaults()
- }, [activeChain?.networkPassphrase, address])
+ }, [activeChain?.networkPassphrase])
useEffect(() => {
if (address) {
createdVaults.forEach(async (v: VaultData) => {
- const userBalance = await vault.getUserBalance(v.address, address)
- if (userBalance) {
- dispatch(setVaultUserBalance({ address: v.address, vaule: userBalance }))
- }
const TVL = await vault.getTVL(v.address)
if (TVL) {
dispatch(setVaultTVL({ value: TVL, address: v.address }))
@@ -102,6 +98,17 @@ export const AllVaults = ({
}
}, [createdVaults])
+ useEffect(() => {
+ if (address) {
+ createdVaults.forEach(async (v: VaultData) => {
+ const userBalance = await vault.getUserBalance(v.address, address)
+ if (userBalance) {
+ dispatch(setVaultUserBalance({ address: v.address, vaule: userBalance }))
+ }
+ })
+ }
+ }, [createdVaults, address])
+
return (
{!isMobile ? (
From 3b8d48358d3191b80d904deca9b82279385f3db8 Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Mon, 18 Nov 2024 22:27:06 -0300
Subject: [PATCH 14/21] =?UTF-8?q?=F0=9F=A9=B9Refactor=20ConfirmDeployModal?=
=?UTF-8?q?=20and=20useVault=20hook=20by=20removing=20unused=20code=20and?=
=?UTF-8?q?=20console=20logs?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../DeployVault/ConfirmDelpoyModal.tsx | 42 +------------------
apps/dapp/src/hooks/useVault.ts | 2 -
2 files changed, 1 insertion(+), 43 deletions(-)
diff --git a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
index 616acc00..f26ffd8e 100644
--- a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
+++ b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
@@ -41,7 +41,6 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
const { activeChain, address } = sorobanContext;
const factory = useFactoryCallback();
const newVault: NewVaultState = useAppSelector(state => state.newVault);
- //const strategies: Strategy[] = newVault.strategies;
const indexName = useAppSelector(state => state.newVault.name)
const indexSymbol = useAppSelector(state => state.newVault.symbol)
const indexShare = useAppSelector(state => state.newVault.vaultShare)
@@ -50,14 +49,6 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
const feeReceiverString = useAppSelector(state => state.newVault.feeReceiver)
const { transactionStatusModal: txModal } = useContext(ModalContext);
const dispatch = useAppDispatch();
- const [assets, setAssets] = useState([]);
- const [status, setStatus] = useState({
- isSuccess: false,
- hasError: false,
- network: undefined,
- message: undefined,
- txHash: undefined
- });
const [deployDisabled, setDeployDisabled] = useState(true);
@@ -74,35 +65,6 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
}
}, [managerString, emergencyManagerString, feeReceiverString])
-
-
-
- /* useEffect(() => {
- const newChartData: ChartData[] = strategies.map((strategy: Strategy, index: number) => {
- return {
- id: index,
- label: strategy.name,
- address: strategy.address,
- value: strategy.share,
- }
- });
- const total = newChartData.reduce((acc: number, curr: ChartData) => acc + curr.value, 0)
- if (total == 100) {
- setChartData(newChartData);
- return;
- } else {
- newChartData.push({
- id: newChartData.length,
- label: 'Unassigned',
- value: 100 - newChartData.reduce((acc: number, curr: ChartData) => acc + curr.value, 0),
- address: undefined,
- color: '#e0e0e0'
- })
- setChartData(newChartData);
- return;
- }
- }, [strategies]); */
-
const autoCloseModal = async () => {
await new Promise(resolve => setTimeout(resolve, 30000))
txModal.resetModal();
@@ -307,14 +269,12 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
- {(activeStep == 0 && !status.hasError) && (
- )}
+
>
diff --git a/apps/dapp/src/hooks/useVault.ts b/apps/dapp/src/hooks/useVault.ts
index 9a363003..aab1737c 100644
--- a/apps/dapp/src/hooks/useVault.ts
+++ b/apps/dapp/src/hooks/useVault.ts
@@ -182,7 +182,6 @@ export const useVault = (vaultAddress?: string | undefined) => {
assets.forEach((asset)=>{
idleFunds.push({address: asset, amount: Number(rawIdleFunds[asset]) / 10 ** 7})
})
- console.log(idleFunds);
return idleFunds;
} catch (error) {
console.error(error);
@@ -196,7 +195,6 @@ export const useVault = (vaultAddress?: string | undefined) => {
assets.forEach((asset)=>{
investedFunds.push({address: asset, amount: Number(rawInvestedFunds[asset]) / 10 ** 7})
})
- console.log(investedFunds);
return investedFunds;
} catch (error) {
console.error(error);
From 26c188f919b47d213332233d5a4e7542d23e856d Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Mon, 18 Nov 2024 23:12:20 -0300
Subject: [PATCH 15/21] =?UTF-8?q?=F0=9F=A9=B9Refactor=20AddNewStrategyButt?=
=?UTF-8?q?on=20and=20ConfirmDeployModal=20to=20improve=20state=20manageme?=
=?UTF-8?q?nt=20and=20add=20setAmountByAddress=20action?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../DeployVault/AddNewStrategyButton.tsx | 23 +++++++++++--------
.../DeployVault/ConfirmDelpoyModal.tsx | 13 ++++++++---
.../dapp/src/store/lib/features/vaultStore.ts | 9 +++++++-
3 files changed, 32 insertions(+), 13 deletions(-)
diff --git a/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx b/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
index 72496720..feef64df 100644
--- a/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
+++ b/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
@@ -9,8 +9,8 @@ import {
} from '@/components/ui/dialog'
import { getTokenSymbol } from '@/helpers/getTokenInfo'
import { StrategyMethod, useStrategyCallback } from '@/hooks/useStrategy'
-import { getDefaultStrategies, pushAmount, pushAsset } from '@/store/lib/features/vaultStore'
-import { useAppDispatch } from '@/store/lib/storeHooks'
+import { getDefaultStrategies, pushAmount, pushAsset, setAmountByAddress } from '@/store/lib/features/vaultStore'
+import { useAppDispatch, useAppSelector } from '@/store/lib/storeHooks'
import { Asset, Strategy } from '@/store/lib/types'
import {
Button,
@@ -42,8 +42,8 @@ function AddNewStrategyButton() {
const { activeChain } = useSorobanReact()
const strategyCallback = useStrategyCallback();
const [open, setOpen] = useState(false)
- const [isLoading, setIsLoading] = useState(false)
- const [defaultStrategies, setDefaultStrategies] = useState([])
+ const newVault = useAppSelector((state) => state.newVault)
+ const [defaultStrategies, setDefaultStrategies] = useState([])
const [selectedAsset, setSelectedAsset] = useState({ address: '', strategies: [], symbol: '' })
const [assets, setAssets] = useState([])
const [amountInput, setAmountInput] = useState({ amount: 0, enabled: false })
@@ -110,13 +110,19 @@ function AddNewStrategyButton() {
}
setAmountInput({ amount: input, enabled: true });
}
-
+ const strategyExists = (strategy: Strategy) => {
+ const exists = newVault.assets.some((asset) => asset.strategies.some((str) => str.address === strategy.address))
+ return exists
+ }
const addAsset = async () => {
const newAsset: Asset = {
address: selectedAsset.address,
strategies: selectedAsset.strategies,
symbol: selectedAsset.symbol
}
+ if (strategyExists(selectedAsset.strategies[0]!)) {
+ await dispatch(setAmountByAddress({ address: selectedAsset.address, amount: amountInput.amount }))
+ }
await dispatch(pushAsset(newAsset))
if (amountInput.enabled && amountInput.amount! > 0) {
await dispatch(pushAmount(amountInput.amount!))
@@ -141,12 +147,11 @@ function AddNewStrategyButton() {
{(strategy, index) => (
- {isLoading && }
- {!isLoading && str.address === strategy.address)}
+ str.address === strategy.address)}
onCheckedChange={(e) => handleSelectStrategy(!!e.checked, strategy)}
label={strategy.name}
- />}
+ />
{selectedAsset.strategies.some((str) => str.address === strategy.address) &&
diff --git a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
index f26ffd8e..b2930cca 100644
--- a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
+++ b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
@@ -76,7 +76,6 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
autoCloseModal();
}
}, [txModal.status])
- const activeStep: number = 0;
const [buttonText, setButtonText] = useState('')
const [accordionValue, setAccordionValue] = useState([AccordionItems.STRATEGY_DETAILS])
const [formControl, setFormControl] = useState({
@@ -107,6 +106,7 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
}
}, [managerString, emergencyManagerString, feeReceiverString, indexShare])
+
const deployDefindex = async () => {
if (managerString === '' || emergencyManagerString === '') {
console.log('please fill manager config')
@@ -170,9 +170,13 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
]);
});
const assetParamsScValVec = xdr.ScVal.scvVec(assetParamsScVal);
- const amountsScVal = newVault.amounts.map((amount) => {
- return nativeToScVal((amount * Math.pow(10, 7)), { type: "i128" });
+ const amountsScVal = newVault.assets.map((asset, index) => {
+ if (newVault.amounts.length === 0) return nativeToScVal(0, { type: "i128" });
+ return nativeToScVal((newVault.amounts[index]!) * 100, { type: "i128" });
});
+ /* const amountsScVal = newVault.amounts.map((amount) => {
+ return nativeToScVal((amount * Math.pow(10, 7)), { type: "i128" });
+ }); */
const amountsScValVec = xdr.ScVal.scvVec(amountsScVal);
/* fn create_defindex_vault(
emergency_manager: address,
@@ -185,6 +189,7 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
salt: bytesn<32>) -> result
*/
let result: any;
+
if (amountsScVal.length === 0) {
const createDefindexParams: xdr.ScVal[] = [
emergencyManager.toScVal(),
@@ -205,6 +210,7 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
}
catch (e: any) {
console.error(e)
+ dispatch(resetNewVault());
txModal.handleError(e.toString());
return
}
@@ -232,6 +238,7 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
}
catch (e: any) {
console.error(e)
+ dispatch(resetNewVault());
txModal.handleError(e.toString());
return
}
diff --git a/apps/dapp/src/store/lib/features/vaultStore.ts b/apps/dapp/src/store/lib/features/vaultStore.ts
index 7400031f..889aa76c 100644
--- a/apps/dapp/src/store/lib/features/vaultStore.ts
+++ b/apps/dapp/src/store/lib/features/vaultStore.ts
@@ -85,6 +85,12 @@ export const newVaultSlice = createSlice({
pushAmount: ((state, action: PayloadAction) => {
state.amounts?.push(action.payload);
}),
+ setAmountByAddress: ((state, action: PayloadAction<{address:string, amount:number}>) => {
+ const index = state.assets.findIndex(asset => asset.address === action.payload.address);
+ if(index !== -1) {
+ state.amounts[index] = action.payload.amount;
+ }
+ }),
removeAmountByIndex: ((state, action: PayloadAction) => {
state.amounts?.splice(action.payload, 1);
}),
@@ -124,7 +130,8 @@ export const {
removeAmountByIndex,
resetAssets,
openEditVault,
- resetNewVault
+ resetNewVault,
+ setAmountByAddress
} = newVaultSlice.actions
// Other code such as selectors can use the imported `RootState` type
From cb98c0cb77c0eb7ab196846637762f4dba891e88 Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Tue, 19 Nov 2024 09:09:50 -0300
Subject: [PATCH 16/21] =?UTF-8?q?=F0=9F=90=9BFix=20amount=20handling=20in?=
=?UTF-8?q?=20AddNewStrategyButton=20and=20update=20initial=20deposit=20di?=
=?UTF-8?q?splay=20in=20DeployVault?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx | 4 ++++
apps/dapp/src/components/DeployVault/DeployVault.tsx | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx b/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
index feef64df..313f43ce 100644
--- a/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
+++ b/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
@@ -121,7 +121,11 @@ function AddNewStrategyButton() {
symbol: selectedAsset.symbol
}
if (strategyExists(selectedAsset.strategies[0]!)) {
+ if (amountInput.enabled && amountInput.amount! > 0) {
await dispatch(setAmountByAddress({ address: selectedAsset.address, amount: amountInput.amount }))
+ } else if (amountInput.enabled == false || amountInput.amount! == 0) {
+ await dispatch(setAmountByAddress({ address: selectedAsset.address, amount: 0 }))
+ }
}
await dispatch(pushAsset(newAsset))
if (amountInput.enabled && amountInput.amount! > 0) {
diff --git a/apps/dapp/src/components/DeployVault/DeployVault.tsx b/apps/dapp/src/components/DeployVault/DeployVault.tsx
index 987f13aa..7432b96d 100644
--- a/apps/dapp/src/components/DeployVault/DeployVault.tsx
+++ b/apps/dapp/src/components/DeployVault/DeployVault.tsx
@@ -103,7 +103,7 @@ export const DeployVault = () => {
Strategy Address: {shortenAddress(strategy.address)}
- {amounts[j] && Initial deposit: ${amounts[j]} {asset.symbol}}
+ {(amounts[j]! > 0) && Initial deposit: ${amounts[j]} {asset.symbol}}
)}
From 2e94614a65a535c45532ec0c38b3ae6f72813b24 Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Tue, 19 Nov 2024 20:58:19 -0300
Subject: [PATCH 17/21] =?UTF-8?q?=F0=9F=A9=B9Refactor=20ConfirmDeployModal?=
=?UTF-8?q?=20and=20InteractWithVault=20components=20to=20enhance=20state?=
=?UTF-8?q?=20management=20and=20integrate=20vault=20data=20handling?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../DeployVault/ConfirmDelpoyModal.tsx | 28 +++++++++++++++----
.../InteractWithVault/InteractWithVault.tsx | 8 ++++--
.../components/ManageVaults/InspectVault.tsx | 5 ++--
apps/dapp/src/providers/modal-provider.tsx | 13 ++++-----
.../src/store/lib/features/walletStore.ts | 25 ++++++++++++++++-
5 files changed, 60 insertions(+), 19 deletions(-)
diff --git a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
index b2930cca..6293b532 100644
--- a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
+++ b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
@@ -10,7 +10,7 @@ import { randomBytes } from "crypto";
import { useAppDispatch, useAppSelector } from "@/store/lib/storeHooks"
import { pushVault } from '@/store/lib/features/walletStore'
-import { Asset, NewVaultState } from "@/store/lib/types";
+import { Asset, NewVaultState, VaultData } from "@/store/lib/types";
import { useFactoryCallback, FactoryMethod } from '@/hooks/useFactory'
import { ModalContext, TransactionStatusModalStatus } from "@/contexts";
@@ -19,6 +19,7 @@ import { AccordionItems, FormControlInterface, VaultPreview } from "./VaultPrevi
import { DialogBody, DialogCloseTrigger, DialogFooter, DialogHeader, DialogTitle } from "../ui/dialog";
import { Button } from "@chakra-ui/react"
import { resetNewVault } from "@/store/lib/features/vaultStore";
+import { useVault } from "@/hooks/useVault";
interface Status {
isSuccess: boolean,
@@ -47,8 +48,9 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
const managerString = useAppSelector(state => state.newVault.manager)
const emergencyManagerString = useAppSelector(state => state.newVault.emergencyManager)
const feeReceiverString = useAppSelector(state => state.newVault.feeReceiver)
- const { transactionStatusModal: txModal } = useContext(ModalContext);
+ const { transactionStatusModal: txModal, deployVaultModal: deployModal } = useContext(ModalContext);
const dispatch = useAppDispatch();
+ const { getIdleFunds, getInvestedFunds, getTVL, getUserBalance } = useVault()
const [deployDisabled, setDeployDisabled] = useState(true);
@@ -118,6 +120,7 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
setAccordionValue([AccordionItems.FEES_CONFIGS])
return
}
+ deployModal.setIsOpen(false)
txModal.initModal();
const vaultName = nativeToScVal(indexName, { type: "string" })
@@ -190,7 +193,8 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
*/
let result: any;
- if (amountsScVal.length === 0) {
+
+ if (newVault.amounts.length === 0) {
const createDefindexParams: xdr.ScVal[] = [
emergencyManager.toScVal(),
feeReceiver.toScVal(),
@@ -245,10 +249,24 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
}
const parsedResult: string = scValToNative(result.returnValue);
if (parsedResult.length !== 56) throw new Error('Invalid result')
- const tempVault: any = {
+ const idleFunds = newVault.assets.map((asset, index) => {
+ return {
+ address: asset.address,
+ amount: newVault.amounts[index] || 0
+ }
+ })
+ const tempVault: VaultData = {
...newVault,
- address: parsedResult
+ address: parsedResult,
+ emergencyManager: emergencyManagerString,
+ feeReceiver: feeReceiverString,
+ manager: managerString,
+ TVL: 0,
+ totalSupply: 0,
+ idleFunds: idleFunds,
+ investedFunds: [{ address: '', amount: 0 }],
}
+ console.log(tempVault)
await txModal.handleSuccess(result.txHash);
dispatch(pushVault(tempVault));
dispatch(resetNewVault());
diff --git a/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx b/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
index cb15e024..b160c4a9 100644
--- a/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
+++ b/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
@@ -66,8 +66,11 @@ export const InteractWithVault = () => {
selectedVault?.address!,
params,
true,
- ).then((res) =>
- statusModal.handleSuccess(res.txHash)
+ ).then((res) => {
+ interactModal.setIsOpen(false),
+ inspectModal.setIsOpen(false),
+ statusModal.handleSuccess(res.txHash)
+ }
).finally(async () => {
const newTVL = await vault.getTVL(selectedVault?.address!)
const parsedNewTVL = Number(newTVL) / 10 ** 7
@@ -76,6 +79,7 @@ export const InteractWithVault = () => {
}
catch (error: any) {
console.error('Error:', error)
+ interactModal.setIsOpen(false)
statusModal.handleError(error.toString())
}
}
diff --git a/apps/dapp/src/components/ManageVaults/InspectVault.tsx b/apps/dapp/src/components/ManageVaults/InspectVault.tsx
index 2678d439..81ff6d08 100644
--- a/apps/dapp/src/components/ManageVaults/InspectVault.tsx
+++ b/apps/dapp/src/components/ManageVaults/InspectVault.tsx
@@ -2,7 +2,7 @@
import { useSorobanReact } from "@soroban-react/core"
import { shortenAddress } from "@/helpers/address"
-import { VaultMethod } from "@/hooks/useVault"
+import { useVault, VaultMethod } from "@/hooks/useVault"
import { useAppSelector } from "@/store/lib/storeHooks"
import { Asset, AssetAmmount, VaultData } from "@/store/lib/types"
@@ -12,7 +12,6 @@ import { DialogBody, DialogContent, DialogFooter, DialogHeader } from "../ui/dia
import { FaRegEdit } from "react-icons/fa"
import { IoClose } from "react-icons/io5"
-
export const InspectVault = ({
handleOpenDeployVault,
handleOpenInteract,
@@ -24,8 +23,8 @@ export const InspectVault = ({
}) => {
const selectedVault: VaultData | undefined = useAppSelector(state => state.wallet.vaults.selectedVault)
const { address } = useSorobanReact()
- if (!selectedVault) return null
+ if (!selectedVault) return null
return (
diff --git a/apps/dapp/src/providers/modal-provider.tsx b/apps/dapp/src/providers/modal-provider.tsx
index 8564ab67..3b4beeaf 100644
--- a/apps/dapp/src/providers/modal-provider.tsx
+++ b/apps/dapp/src/providers/modal-provider.tsx
@@ -26,10 +26,6 @@ export const ModalProvider = ({
const [txHash, setTxHash] = React.useState('')
const handleResetModal = () => {
- console.log('resetting modal')
- setIsDeployVaultModalOpen(false)
- setIsInspectVaultModalOpen(false)
- setIsInteractWithVaultModalOpen(false)
setIsTransactionStatusModalOpen(false)
setTransactionStatusModalStep(0)
setTransactionStatusModalStatus(TransactionStatusModalStatus.PENDING)
@@ -38,23 +34,23 @@ export const ModalProvider = ({
setTxHash('')
}
+ const handleFirstStep = setTimeout(() => setTransactionStatusModalStep(1), 3000)
useEffect(() => {
- const handleFirstStep = setTimeout(() => setTransactionStatusModalStep(1), 3000)
if (isTransactionStatusModalOpen && transactionStatusModalStep === 0 && transactionStatusModalStatus === TransactionStatusModalStatus.PENDING) {
- console.log('modal is open')
handleFirstStep
- } else {
+ } else if (transactionStatusModalStatus !== TransactionStatusModalStatus.PENDING) {
clearTimeout(handleFirstStep)
+ setTransactionStatusModalStep(2)
}
}, [isTransactionStatusModalOpen, transactionStatusModalStep, transactionStatusModalStatus])
const handleInitModal = () => {
- console.log('init modal')
handleResetModal()
setIsTransactionStatusModalOpen(true)
}
const handleError = (error: string) => {
+ clearTimeout(handleFirstStep)
setTransactionStatusModalError(error)
setTransactionStatusModalStatus(TransactionStatusModalStatus.ERROR)
setTransactionStatusModalStep(2)
@@ -62,6 +58,7 @@ export const ModalProvider = ({
}
const handleSuccess = (txHash: string) => {
+ clearTimeout(handleFirstStep)
setTxHash(txHash)
setTransactionStatusModalStatus(TransactionStatusModalStatus.SUCCESS)
setTransactionStatusModalStep(2)
diff --git a/apps/dapp/src/store/lib/features/walletStore.ts b/apps/dapp/src/store/lib/features/walletStore.ts
index 307a911b..47b7bf83 100644
--- a/apps/dapp/src/store/lib/features/walletStore.ts
+++ b/apps/dapp/src/store/lib/features/walletStore.ts
@@ -5,6 +5,7 @@ import { ChainMetadata } from '@soroban-react/types'
import vaults from '@/constants/constants.json'
import { Networks } from '@stellar/stellar-sdk'
import { SelectedVault, VaultData, WalletState } from '../types'
+import { VaultMethod } from '@/hooks/useVault'
const getDefaultVaults = async (network: string) => {
const filteredVaults = vaults.filter(vault => {
@@ -105,6 +106,27 @@ export const walletSlice = createSlice({
}
})
},
+ updateVaultData: (state, action: PayloadAction>) => {
+ state.vaults.createdVaults.forEach(vault => {
+ if (vault.address === action.payload.address) {
+ Object.assign(vault, action.payload)
+ }
+ })
+ state.vaults.selectedVault = {
+ address: action.payload.address ?? state.vaults.selectedVault?.address ?? '',
+ name: action.payload.name ?? state.vaults.selectedVault?.name ?? '',
+ manager: action.payload.manager ?? state.vaults.selectedVault?.manager ?? '',
+ emergencyManager: action.payload.emergencyManager ?? state.vaults.selectedVault?.emergencyManager ?? '',
+ feeReceiver: action.payload.feeReceiver ?? state.vaults.selectedVault?.feeReceiver ?? '',
+ TVL: action.payload.TVL ?? state.vaults.selectedVault?.TVL ?? 0,
+ userBalance: action.payload.userBalance ?? state.vaults.selectedVault?.userBalance ?? 0,
+ assets: action.payload.assets ?? state.vaults.selectedVault?.assets ?? [],
+ idleFunds: action.payload.idleFunds ?? state.vaults.selectedVault?.idleFunds ?? [],
+ investedFunds: action.payload.investedFunds ?? state.vaults.selectedVault?.investedFunds ?? [],
+ totalSupply: action.payload.totalSupply ?? state.vaults.selectedVault?.totalSupply ?? 0,
+ method: state.vaults.selectedVault?.method || VaultMethod.DEPOSIT,
+ }
+ },
},
extraReducers(builder) {
builder.addCase(fetchDefaultAddresses.pending, (state) => {
@@ -131,7 +153,8 @@ export const {
setVaults,
setVaultTVL,
resetSelectedVault,
- setVaultUserBalance
+ setVaultUserBalance,
+ updateVaultData
} = walletSlice.actions
// Other code such as selectors can use the imported `RootState` type
From b513ec59a538742e02d5faa49496094b3698310f Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Wed, 20 Nov 2024 09:27:58 -0300
Subject: [PATCH 18/21] =?UTF-8?q?=F0=9F=A9=B9Refactor=20InteractWithVault?=
=?UTF-8?q?=20component=20to=20enhance=20user=20balance=20handling=20and?=
=?UTF-8?q?=20update=20vault=20data=20management?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../InteractWithVault/InteractWithVault.tsx | 43 ++++++++++++-------
.../src/store/lib/features/walletStore.ts | 14 ------
2 files changed, 27 insertions(+), 30 deletions(-)
diff --git a/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx b/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
index b160c4a9..04176201 100644
--- a/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
+++ b/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
@@ -3,8 +3,8 @@ import { Address, nativeToScVal, xdr } from '@stellar/stellar-sdk'
import { useSorobanReact } from '@soroban-react/core'
import { useAppDispatch, useAppSelector } from '@/store/lib/storeHooks'
-import { setVaultTVL } from '@/store/lib/features/walletStore'
-import { Strategy } from '@/store/lib/types'
+import { setVaultTVL, setVaultUserBalance, updateVaultData } from '@/store/lib/features/walletStore'
+import { Strategy, VaultData } from '@/store/lib/types'
import { VaultMethod, useVaultCallback, useVault } from '@/hooks/useVault'
import { ModalContext } from '@/contexts'
@@ -36,7 +36,7 @@ export const InteractWithVault = () => {
const { transactionStatusModal: statusModal, interactWithVaultModal: interactModal, inspectVaultModal: inspectModal } = useContext(ModalContext)
const vaultOperation = async () => {
- if (!address || !vaultMethod) return;
+ if (!address || !vaultMethod || !selectedVault.address) return;
if (!amount) throw new Error('Amount is required');
const parsedAmount = parseFloat(amount.toString())
const convertedAmount = parsedAmount * Math.pow(10, 7)
@@ -52,42 +52,53 @@ export const InteractWithVault = () => {
};
if (vaultMethod === VaultMethod.WITHDRAW) {
const withdrawAmount = ((amount * selectedVault.totalSupply) / selectedVault.TVL)
- const convertedWithdrawAmount = withdrawAmount * Math.pow(10, 7)
+ const truncatedWithdrawAmount = Math.floor(withdrawAmount * 1e7) / 1e7;
+ const convertedWithdrawAmount = Number(truncatedWithdrawAmount) * Math.pow(10, 7)
const withdrawParams: xdr.ScVal[] = [
- nativeToScVal(convertedWithdrawAmount, { type: "i128" }),
+ nativeToScVal(Math.ceil(convertedWithdrawAmount), { type: "i128" }),
new Address(address).toScVal(),
]
params = withdrawParams
};
- console.log('Vault method:', vaultMethod)
try {
const result = await vaultCB(
vaultMethod!,
selectedVault?.address!,
params,
true,
- ).then((res) => {
- interactModal.setIsOpen(false),
- inspectModal.setIsOpen(false),
- statusModal.handleSuccess(res.txHash)
+ ).then(async (res) => {
+ await statusModal.handleSuccess(res.txHash)
}
).finally(async () => {
+ const newBalance = await vault.getUserBalance(selectedVault.address, address)
+ const newIdleFunds = await vault.getIdleFunds(selectedVault.address!)
+ const newInvestedFunds = await vault.getInvestedFunds(selectedVault.address)
const newTVL = await vault.getTVL(selectedVault?.address!)
- const parsedNewTVL = Number(newTVL) / 10 ** 7
- dispatch(setVaultTVL({ value: parsedNewTVL, address: selectedVault?.address! }))
+ const newVaultData: Partial = {
+ address: selectedVault.address,
+ userBalance: newBalance || 0,
+ idleFunds: newIdleFunds,
+ investedFunds: newInvestedFunds,
+ TVL: newTVL
+ }
+ dispatch(updateVaultData(newVaultData))
});
}
catch (error: any) {
console.error('Error:', error)
- interactModal.setIsOpen(false)
- statusModal.handleError(error.toString())
+ await statusModal.handleError(error.toString())
+ } finally {
+ set_amount(0)
+ await setTimeout(() => {
+ interactModal.setIsOpen(false)
+ inspectModal.setIsOpen(false)
+ }, 3000)
}
}
const setAmount = (input: any) => {
if (input < 0 || !selectedVault) return;
if (vaultMethod === VaultMethod.WITHDRAW) {
- console.log(input, selectedVault?.userBalance)
if (input > selectedVault.userBalance!) return;
}
const decimalRegex = /^(\d+)?(\.\d{0,7})?$/;
@@ -122,7 +133,7 @@ export const InteractWithVault = () => {
Total value locked: ${selectedVault?.TVL} {selectedVault.assets[0]?.symbol}
- User balance in vault: ${selectedVault?.userBalance} {selectedVault.assets[0]?.symbol}
+ User balance in vault: ${`${selectedVault.userBalance ?? 0}`} {selectedVault.assets[0]?.symbol}
{vaultMethod != VaultMethod.EMERGENCY_WITHDRAW &&
diff --git a/apps/dapp/src/store/lib/features/walletStore.ts b/apps/dapp/src/store/lib/features/walletStore.ts
index 47b7bf83..07e7db2c 100644
--- a/apps/dapp/src/store/lib/features/walletStore.ts
+++ b/apps/dapp/src/store/lib/features/walletStore.ts
@@ -112,20 +112,6 @@ export const walletSlice = createSlice({
Object.assign(vault, action.payload)
}
})
- state.vaults.selectedVault = {
- address: action.payload.address ?? state.vaults.selectedVault?.address ?? '',
- name: action.payload.name ?? state.vaults.selectedVault?.name ?? '',
- manager: action.payload.manager ?? state.vaults.selectedVault?.manager ?? '',
- emergencyManager: action.payload.emergencyManager ?? state.vaults.selectedVault?.emergencyManager ?? '',
- feeReceiver: action.payload.feeReceiver ?? state.vaults.selectedVault?.feeReceiver ?? '',
- TVL: action.payload.TVL ?? state.vaults.selectedVault?.TVL ?? 0,
- userBalance: action.payload.userBalance ?? state.vaults.selectedVault?.userBalance ?? 0,
- assets: action.payload.assets ?? state.vaults.selectedVault?.assets ?? [],
- idleFunds: action.payload.idleFunds ?? state.vaults.selectedVault?.idleFunds ?? [],
- investedFunds: action.payload.investedFunds ?? state.vaults.selectedVault?.investedFunds ?? [],
- totalSupply: action.payload.totalSupply ?? state.vaults.selectedVault?.totalSupply ?? 0,
- method: state.vaults.selectedVault?.method || VaultMethod.DEPOSIT,
- }
},
},
extraReducers(builder) {
From 788794f13b22f3ad7f3f8b8004f53f458085a7f9 Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Wed, 20 Nov 2024 09:36:28 -0300
Subject: [PATCH 19/21] =?UTF-8?q?=E2=9C=A8Add=20clipboard=20functionality?=
=?UTF-8?q?=20for=20vault=20addresses?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../InteractWithVault/InteractWithVault.tsx | 16 ++++----
.../components/ManageVaults/InspectVault.tsx | 10 ++++-
apps/dapp/src/components/ui/clipboard.tsx | 39 ++++++++++---------
3 files changed, 38 insertions(+), 27 deletions(-)
diff --git a/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx b/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
index 04176201..2fb0431d 100644
--- a/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
+++ b/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx
@@ -23,6 +23,7 @@ import {
NativeSelectField,
HStack,
} from '@chakra-ui/react'
+import { ClipboardIconButton, ClipboardRoot } from '../ui/clipboard'
export const InteractWithVault = () => {
const [amount, set_amount] = useState(0)
@@ -121,13 +122,14 @@ export const InteractWithVault = () => {
Vault address:
-
+
+
+
+ {selectedVault.address}
+
+
+
+
Total value locked: ${selectedVault?.TVL} {selectedVault.assets[0]?.symbol}
diff --git a/apps/dapp/src/components/ManageVaults/InspectVault.tsx b/apps/dapp/src/components/ManageVaults/InspectVault.tsx
index 81ff6d08..7bbe175e 100644
--- a/apps/dapp/src/components/ManageVaults/InspectVault.tsx
+++ b/apps/dapp/src/components/ManageVaults/InspectVault.tsx
@@ -11,6 +11,7 @@ import { Button, Grid, GridItem, HStack, Icon, Stack, Text } from "@chakra-ui/re
import { DialogBody, DialogContent, DialogFooter, DialogHeader } from "../ui/dialog"
import { FaRegEdit } from "react-icons/fa"
import { IoClose } from "react-icons/io5"
+import { ClipboardIconButton, ClipboardRoot } from "../ui/clipboard"
export const InspectVault = ({
handleOpenDeployVault,
@@ -50,7 +51,14 @@ export const InspectVault = ({
Vault address
- {selectedVault.address}
+
+
+
+ {selectedVault.address}
+
+
+
+
diff --git a/apps/dapp/src/components/ui/clipboard.tsx b/apps/dapp/src/components/ui/clipboard.tsx
index 1955276a..958cb59f 100644
--- a/apps/dapp/src/components/ui/clipboard.tsx
+++ b/apps/dapp/src/components/ui/clipboard.tsx
@@ -5,10 +5,10 @@ import {
IconButton,
Input,
} from "@chakra-ui/react"
-import { forwardRef } from "react"
+import * as React from "react"
import { LuCheck, LuClipboard, LuLink } from "react-icons/lu"
-const ClipboardIcon = forwardRef<
+const ClipboardIcon = React.forwardRef<
HTMLDivElement,
ChakraClipboard.IndicatorProps
>(function ClipboardIcon(props, ref) {
@@ -19,7 +19,7 @@ const ClipboardIcon = forwardRef<
)
})
-const ClipboardCopyText = forwardRef<
+const ClipboardCopyText = React.forwardRef<
HTMLDivElement,
ChakraClipboard.IndicatorProps
>(function ClipboardCopyText(props, ref) {
@@ -30,7 +30,7 @@ const ClipboardCopyText = forwardRef<
)
})
-export const ClipboardLabel = forwardRef<
+export const ClipboardLabel = React.forwardRef<
HTMLLabelElement,
ChakraClipboard.LabelProps
>(function ClipboardLabel(props, ref) {
@@ -46,7 +46,7 @@ export const ClipboardLabel = forwardRef<
)
})
-export const ClipboardButton = forwardRef(
+export const ClipboardButton = React.forwardRef(
function ClipboardButton(props, ref) {
return (
@@ -59,7 +59,7 @@ export const ClipboardButton = forwardRef(
},
)
-export const ClipboardLink = forwardRef(
+export const ClipboardLink = React.forwardRef(
function ClipboardLink(props, ref) {
return (
@@ -81,20 +81,21 @@ export const ClipboardLink = forwardRef(
},
)
-export const ClipboardIconButton = forwardRef(
- function ClipboardIconButton(props, ref) {
- return (
-
-
-
-
-
-
- )
- },
-)
+export const ClipboardIconButton = React.forwardRef<
+ HTMLButtonElement,
+ ButtonProps
+>(function ClipboardIconButton(props, ref) {
+ return (
+
+
+
+
+
+
+ )
+})
-export const ClipboardInput = forwardRef(
+export const ClipboardInput = React.forwardRef(
function ClipboardInputElement(props, ref) {
return (
From fe847140cf99d781ba06dc9363e311a32207a12e Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Wed, 20 Nov 2024 10:35:43 -0300
Subject: [PATCH 20/21] =?UTF-8?q?=F0=9F=A9=B9Fix=20initial=20deposit=20amo?=
=?UTF-8?q?unts?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../dapp/src/components/DeployVault/AddNewStrategyButton.tsx | 5 +++--
apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx | 5 ++++-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx b/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
index 313f43ce..e7da6c9f 100644
--- a/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
+++ b/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx
@@ -120,7 +120,8 @@ function AddNewStrategyButton() {
strategies: selectedAsset.strategies,
symbol: selectedAsset.symbol
}
- if (strategyExists(selectedAsset.strategies[0]!)) {
+ const exists = strategyExists(selectedAsset.strategies[0]!)
+ if (exists) {
if (amountInput.enabled && amountInput.amount! > 0) {
await dispatch(setAmountByAddress({ address: selectedAsset.address, amount: amountInput.amount }))
} else if (amountInput.enabled == false || amountInput.amount! == 0) {
@@ -128,7 +129,7 @@ function AddNewStrategyButton() {
}
}
await dispatch(pushAsset(newAsset))
- if (amountInput.enabled && amountInput.amount! > 0) {
+ if (!exists && amountInput.enabled && amountInput.amount! > 0) {
await dispatch(pushAmount(amountInput.amount!))
}
resetForm()
diff --git a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
index 6293b532..e4c7b914 100644
--- a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
+++ b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
@@ -174,8 +174,11 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
});
const assetParamsScValVec = xdr.ScVal.scvVec(assetParamsScVal);
const amountsScVal = newVault.assets.map((asset, index) => {
+ const parsedAmount = newVault.amounts[index] || 0;
+ const truncatedAmount = Math.floor(parsedAmount * 1e7) / 1e7;
+ const convertedAmount = Number(truncatedAmount) * Math.pow(10, 7)
if (newVault.amounts.length === 0) return nativeToScVal(0, { type: "i128" });
- return nativeToScVal((newVault.amounts[index]!) * 100, { type: "i128" });
+ return nativeToScVal(convertedAmount, { type: "i128" });
});
/* const amountsScVal = newVault.amounts.map((amount) => {
return nativeToScVal((amount * Math.pow(10, 7)), { type: "i128" });
From d6ac37d4a06d643901a68265b621d3673296d2c2 Mon Sep 17 00:00:00 2001
From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com>
Date: Wed, 20 Nov 2024 10:36:20 -0300
Subject: [PATCH 21/21] =?UTF-8?q?=F0=9F=94=A5Removed=20unused=20log?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
index e4c7b914..11a76033 100644
--- a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
+++ b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx
@@ -269,7 +269,6 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo
idleFunds: idleFunds,
investedFunds: [{ address: '', amount: 0 }],
}
- console.log(tempVault)
await txModal.handleSuccess(result.txHash);
dispatch(pushVault(tempVault));
dispatch(resetNewVault());