diff --git a/components/instructions/programs/symmetryV2.tsx b/components/instructions/programs/symmetryV2.tsx index 3a0bd424f4..b6820b2f02 100644 --- a/components/instructions/programs/symmetryV2.tsx +++ b/components/instructions/programs/symmetryV2.tsx @@ -18,6 +18,17 @@ const rebalanceAndLpLayout = BufferLayout.seq( 'rebalanceAndLp' ); + +const SymmetryLogoLink = () => { + return + + + + + + +} + export const SYMMETRY_V2_INSTRUCTIONS = { "2KehYt3KsEQR53jYcxjbQp2d2kCp4AkuQW68atufRwSr": { 78: { @@ -43,10 +54,32 @@ export const SYMMETRY_V2_INSTRUCTIONS = { ]).decode(Buffer.from(data), 8) return ( - <> -

Withdraw Amount: {amount / 10**6}

-

Rebalance to USDC: {rebalance === 2 ? 'Yes' : 'No - Withdraw Assets Directly'}

- +
+
+ +
+

Withdraw from Basket

+

Basket Tokens will be burnt to redeem underlying assets:

+
+
+
+
+
+
+
Withdraw:
+
{(amount / 10**6).toFixed(2)} Basket Tokens
+
+
+
Rebalance to USDC:
+
+ {rebalance === 2 ? 'Yes' : 'No - Withdraw Assets Directly'} +
+
+
+
+
+
+ ) }, }, @@ -79,9 +112,25 @@ export const SYMMETRY_V2_INSTRUCTIONS = { ]).decode(Buffer.from(data), 8) return ( - <> -

USDC Deposit Amount: {amount / 10**6}

- +
+
+ +
+

USDC Deposit Information

+

After the deposit, basket tokens will be minted to the DAO.

+
+
+
+
+
+
+
USDC Deposit Amount:
+
{(amount / 10**6).toFixed(2)} USDC
+
+
+
+
+
) }, }, @@ -132,26 +181,78 @@ export const SYMMETRY_V2_INSTRUCTIONS = { }).filter(x => x != null) return ( - <> -

Manager Fee: {managerFee / 100}%

-

Rebalance Check Interval: {rebalanceInterval / 60} minutes

-

Rebalance Trigger Threshold: {rebalanceThreshold / 100}%

-

Maximum Slippage Allowed During Rebalancing: {rebalanceSlippage / 100}%

-

Liquidity Provision Threshold: {lpOffsetThreshold / 100}%

-

Rebalancing Enabled: {rebalanceAndLp[0] === 0 ? "Yes" : "No"}

-

Liquidity Provision Enabled: {rebalanceAndLp[1] === 0 ? "No" : "Yes"}

-

Basket Composition Size: {numOfTokens} Tokens

-
- Basket Composition: - { - composition.map((compItem, i) => { - return
-

{compItem.weight}% {compItem.symbol} ({compItem.tokenMint.slice(0,6)}...)

-
- }) - } +
+
+ + + + + + + +
+

Editing Basket Settings

+

If the proposal passes, the basket will be edited to the following settings:

+
- +
+
+
+
+
Manager Fee:
+
{managerFee / 100}%
+
+
+
Rebalance Check Interval:
+
{rebalanceInterval / 60} minutes
+
+
+
Rebalance Trigger Threshold:
+
{rebalanceThreshold / 100}%
+
+
+
Maximum Slippage Allowed During Rebalancing:
+
{rebalanceSlippage / 100}%
+
+
+
Liquidity Provision Threshold:
+
{lpOffsetThreshold / 100}%
+
+
+
Rebalancing Enabled:
+
{rebalanceAndLp[0] === 0 ? "Yes" : "No"}
+
+
+
Liquidity Provision Enabled:
+
{rebalanceAndLp[1] === 0 ? "Yes" : "No"}
+
+
+
Basket Composition Size:
+
{numOfTokens} Tokens
+
+
+
+
+

Basket Composition:

+ +
+
+
) }, }, @@ -188,7 +289,14 @@ export const SYMMETRY_V2_INSTRUCTIONS = { targetCompositionLayout, targetWeightsLayout, ]).decode(Buffer.from(data), 8) - + const getBasketType = (type) => { + switch (type) { + case 0: return "Bundle"; + case 1: return "Portfolio"; + case 2: return "Private"; + default: return "Unknown"; + } + }; let basketsSdk = await BasketsSDK.init(connection); let tokenData = basketsSdk.getTokenListData(); @@ -213,28 +321,86 @@ export const SYMMETRY_V2_INSTRUCTIONS = { }).filter(x => x != null) return ( - <> -

Manager Fee: {managerFee / 100}%

-

Host Platform Fee: {hostFee / 100}%

-

Basket Type: {basketType === 0 ? "Bundle" : basketType === 1 ? "Portfolio" : "Private"}

-

Rebalance Check Interval: {rebalanceInterval / 60} minutes

-

Rebalance Trigger Threshold: {rebalanceThreshold / 100}%

-

Maximum Slippage Allowed During Rebalancing: {rebalanceSlippage / 100}%

-

Liquidity Provision Threshold: {lpOffsetThreshold / 100}%

-

Rebalancing Enabled: {rebalanceAndLp[0] === 0 ? "Yes" : "No"}

-

Liquidity Provision Enabled: {rebalanceAndLp[1] === 0 ? "No" : "Yes"}

-

Basket Composition Size: {numOfTokens} Tokens

-
- Basket Composition: - { - composition.map((compItem, i) => { - return
-

{compItem.weight}% {compItem.symbol} ({compItem.tokenMint.slice(0,6)}...)

-
- }) - } +
+
+ + + + + + + +
+

Creating a Basket

+

If the proposal passes, a basket will be created with the following settings:

+
+
+
+
+
+
+
Manager Fee:
+
{managerFee / 100}%
+
+
+
Host Platform Fee:
+
{hostFee / 100}%
+
+
+
Basket Type:
+
{getBasketType(basketType)}
+
+
+
Rebalance Check Interval:
+
{rebalanceInterval / 60} minutes
+
+
+
Rebalance Trigger Threshold:
+
{rebalanceThreshold / 100}%
+
+
+
Maximum Slippage Allowed During Rebalancing:
+
{rebalanceSlippage / 100}%
+
+
+
Liquidity Provision Threshold:
+
{lpOffsetThreshold / 100}%
+
+
+
Rebalancing Enabled:
+
{rebalanceAndLp[0] === 0 ? "Yes" : "No"}
+
+
+
Liquidity Provision Enabled:
+
{rebalanceAndLp[1] === 0 ? "Yes" : "No"}
+
+
+
Basket Composition Size:
+
{numOfTokens} Tokens
+
+
+
+
+

Basket Composition:

+ +
- +
) }, }, diff --git a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryCreateBasket.tsx b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryCreateBasket.tsx index 92a3d481be..16a1b34999 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryCreateBasket.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryCreateBasket.tsx @@ -315,6 +315,30 @@ const SymmetryCreateBasket = ({ }
+ { + form.governedAccount && +
+ + + + + +

+ Make sure {form.governedAccount?.pubkey.toBase58()} has at least 0.22 SOL, which will required to deploy the basket after the proposal passes. +

+
+ } ) } diff --git a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryDeposit.tsx b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryDeposit.tsx index ea8cb31184..208f3a0697 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryDeposit.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryDeposit.tsx @@ -5,12 +5,13 @@ import Input from '@components/inputs/Input' import { NewProposalContext } from '../../../new'; import { BasketsSDK, FilterOption } from "@symmetry-hq/baskets-sdk"; import { buyBasketIx } from "@symmetry-hq/baskets-sdk/dist/basketInstructions"; - +import ArrowButton from './components/ArrowButton'; import { useConnection } from '@solana/wallet-adapter-react'; import { PublicKey } from '@solana/web3.js'; import useGovernanceAssets from '@hooks/useGovernanceAssets'; import Select from '@components/inputs/Select'; import GovernedAccountSelect from '../../GovernedAccountSelect'; +import { LoaderIcon } from './SymmetryEditBasket'; const SymmetryDeposit = ({ index, @@ -34,7 +35,6 @@ const SymmetryDeposit = ({ const shouldBeGoverned = !!(index !== 0 && governance) const [assetAccountsLoaded, setAssetAccountsLoaded] = useState(false); - const handleSetForm = ({ propertyName, value }) => { setFormErrors({}) setForm({ ...form, [propertyName]: value }) @@ -46,13 +46,12 @@ const SymmetryDeposit = ({ }, [assetAccounts]); useEffect(() => { - if(assetAccountsLoaded) { - const basketsOwnerAccounts: FilterOption[] = assetAccounts.filter(x => x.isSol).map((token) => { - return { + if(form.governedAccount) { + const basketsOwnerAccounts: FilterOption[] = [{ filterType: 'manager', - filterPubkey: token.pubkey + filterPubkey: form.governedAccount.pubkey } - }) + ] BasketsSDK.init(connection).then((sdk) => { setBasketSdk(sdk); sdk.findBaskets(basketsOwnerAccounts).then((baskets) => { @@ -71,7 +70,7 @@ const SymmetryDeposit = ({ }); }); } - }, [assetAccountsLoaded]); + }, [form.governedAccount]); useEffect(() => { handleSetInstructions( @@ -99,7 +98,28 @@ const SymmetryDeposit = ({ return <> { - managedBaskets ? + assetAccountsLoaded ? + x.isSol)} + onChange={(value) => { + handleSetForm({ value, propertyName: 'governedAccount' }) + }} + value={form.governedAccount} + error={formErrors['governedAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type='wallet' + /> + : +
+ +

Loading DAO Accounts

+
+ } + { + form.governedAccount && + (managedBaskets ? handleSetForm({ propertyName: 'depositAmount', value: e.target.value })} - error={formErrors['depositAmount']} - /> + handleSetForm({ propertyName: 'depositAmount', value: e.target.value })} + error={formErrors['depositAmount']} + /> + + } } diff --git a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryEditBasket.tsx b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryEditBasket.tsx index 49c84f47e8..82a4d0b314 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryEditBasket.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryEditBasket.tsx @@ -15,6 +15,13 @@ import { PublicKey } from '@solana/web3.js'; import { LinkIcon } from '@heroicons/react/solid'; import useGovernanceAssets from '@hooks/useGovernanceAssets'; import Select from '@components/inputs/Select'; +import GovernedAccountSelect from '../../GovernedAccountSelect'; +import ArrowButton from './components/ArrowButton'; + + +export const LoaderIcon = () => { + return
; +} const SymmetryEditBasket = ({ index, @@ -46,6 +53,7 @@ const SymmetryEditBasket = ({ const [addTokenModal, setAddTokenModal] = useState(false); const [supportedTokens, setSupportedTokens] = useState(null); const [assetAccountsLoaded, setAssetAccountsLoaded] = useState(false); + const [govAccount, setGovAccount] = useState(undefined); const handleSetForm = ({ propertyName, value }) => { @@ -87,13 +95,12 @@ const SymmetryEditBasket = ({ }, [assetAccounts]); useEffect(() => { - if(assetAccountsLoaded) { - const basketsOwnerAccounts: FilterOption[] = assetAccounts.filter(x => x.isSol).map((token) => { - return { - filterType: 'manager', - filterPubkey: token.pubkey - } - }) + if(form.governedAccount) { + console.log("govAcc", form.governedAccount); + const basketsOwnerAccounts: FilterOption[] = [{ + filterType: 'manager', + filterPubkey: form.governedAccount.pubkey + }] if(basketsOwnerAccounts.length > 0) { BasketsSDK.init(connection).then((sdk) => { setSupportedTokens(sdk.getTokenListData()); @@ -114,7 +121,7 @@ const SymmetryEditBasket = ({ }); } } - }, [assetAccountsLoaded]); + }, [form.governedAccount]); useEffect(() => { handleSetInstructions( @@ -155,7 +162,29 @@ const SymmetryEditBasket = ({ return <> { - managedBaskets ? + assetAccountsLoaded ? + x.isSol)} + onChange={(value) => { + handleSetForm({ value, propertyName: 'governedAccount' }) + }} + value={form.governedAccount} + error={formErrors['governedAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type='wallet' + /> + : +
+ +

Loading DAO Accounts

+
+ + } + { + form.governedAccount && + (managedBaskets ? { handleSetForm({ propertyName: 'basketAddress', value: new PublicKey(e) }) - setSelectedBasket(managedBaskets.filter(x => x.basket.ownAddress.toBase58() === e)[0]); }} > { @@ -125,16 +145,17 @@ const SymmetryWithdraw = ({ } : -

Loading Baskets Managed by the DAO

+
+ +

Loading Baskets Managed by the Account

+
+ ) } { form.basketAddress &&
-

Selected Basket:

-

{form.basketAddress.toBase58()}

- - -

View Basket on Symmetry

+
+
} @@ -154,33 +175,62 @@ const SymmetryWithdraw = ({ /> } - handleSetForm({ propertyName: 'withdrawAmount', value: e.target.value })} - error={formErrors['withdrawAmount']} - /> - + { + form.basketAddress && form.governedAccount && + <> + handleSetForm({ propertyName: 'withdrawAmount', value: e.target.value })} + error={formErrors['withdrawAmount']} + /> + + + } + { + form.governedAccount && +
+ + + + + +

+ Make sure {form.governedAccount?.pubkey.toBase58()} has at least 0.08 SOL, which is required for a temporary withdrawal account, which will automatically be closed after completion & SOL will be refunded. +

+
+ } } diff --git a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/components/ArrowButton.tsx b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/components/ArrowButton.tsx new file mode 100644 index 0000000000..1e39ed6cf4 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/components/ArrowButton.tsx @@ -0,0 +1,37 @@ +import React from 'react'; + +const ArrowButton = ({ + title, + children=<> +}) => { + return ( + + ) +} + +export default ArrowButton; \ No newline at end of file