Skip to content

Commit

Permalink
add friktion withdraw option (solana-labs#470)
Browse files Browse the repository at this point in the history
* Friktion (#1)

* remove unused signer

* merge

* merge

* fix

* bump version

* begin adding withdraw

* finish adding friktion withdraw instruction

* pass in dao authority to cVoltSDK

* bump

* fix validation

* fix validation

* remove unused arg
  • Loading branch information
jasonchitla authored Mar 19, 2022
1 parent f2b1e35 commit 5bbf344
Show file tree
Hide file tree
Showing 9 changed files with 637 additions and 10 deletions.
5 changes: 5 additions & 0 deletions hooks/useGovernanceAssets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ export default function useGovernanceAssets() {
name: 'Friktion: Deposit into Volt',
isVisible: canUseAnyInstruction,
},
{
id: Instructions.WithdrawFromVolt,
name: 'Friktion: Withdraw from Volt',
isVisible: canUseAnyInstruction,
},
{
id: Instructions.CreateSolendObligationAccount,
name: 'Solend: Create Obligation Account',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@cardinal/namespaces-components": "^2.5.0",
"@emotion/react": "^11.1.5",
"@emotion/styled": "^11.3.0",
"@friktion-labs/friktion-sdk": "^1.1.13",
"@friktion-labs/friktion-sdk": "^1.1.25",
"@headlessui/react": "^1.4.2",
"@heroicons/react": "^1.0.1",
"@marinade.finance/marinade-ts-sdk": "^2.0.9",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import useGovernanceAssets from '@hooks/useGovernanceAssets'
import { Governance } from '@solana/spl-governance'
import { ProgramAccount } from '@solana/spl-governance'
import GovernedAccountSelect from '../../GovernedAccountSelect'
import { getFriktionDepositInstruction } from '@utils/instructionTools'
import { getFriktionDepositInstruction } from '@utils/instructions/Friktion'
import Select from '@components/inputs/Select'
import { FriktionSnapshot, VoltSnapshot } from '@friktion-labs/friktion-sdk'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import React, { useContext, useEffect, useState } from 'react'
import Input from '@components/inputs/Input'
import useRealm from '@hooks/useRealm'
import { getMintMinAmountAsDecimal } from '@tools/sdk/units'
import { PublicKey } from '@solana/web3.js'
import { precision } from '@utils/formatting'
import useWalletStore from 'stores/useWalletStore'
import { GovernedMultiTypeAccount } from '@utils/tokens'
import {
FriktionWithdrawForm,
UiInstruction,
} from '@utils/uiTypes/proposalCreationTypes'
import { NewProposalContext } from '../../../new'
import { getFriktionWithdrawSchema } from '@utils/validations'
import useGovernanceAssets from '@hooks/useGovernanceAssets'
import { Governance } from '@solana/spl-governance'
import { ProgramAccount } from '@solana/spl-governance'
import GovernedAccountSelect from '../../GovernedAccountSelect'
import { getFriktionWithdrawInstruction } from '@utils/instructions/Friktion'
import Select from '@components/inputs/Select'
import { FriktionSnapshot, VoltSnapshot } from '@friktion-labs/friktion-sdk'

const FriktionWithdraw = ({
index,
governance,
}: {
index: number
governance: ProgramAccount<Governance> | null
}) => {
const connection = useWalletStore((s) => s.connection)
const wallet = useWalletStore((s) => s.current)
const { realmInfo } = useRealm()
const { governedTokenAccountsWithoutNfts } = useGovernanceAssets()
const shouldBeGoverned = index !== 0 && governance
const programId: PublicKey | undefined = realmInfo?.programId
const [form, setForm] = useState<FriktionWithdrawForm>({
amount: undefined,
governedTokenAccount: undefined,
voltVaultId: '',
depositTokenMint: undefined,
programId: programId?.toString(),
mintInfo: undefined,
})
// eslint-disable-next-line @typescript-eslint/ban-types
const [friktionVolts, setFriktionVolts] = useState<VoltSnapshot[] | null>(
null
)
const [governedAccount, setGovernedAccount] = useState<
ProgramAccount<Governance> | undefined
>(undefined)
const [formErrors, setFormErrors] = useState({})
const mintMinAmount = form.mintInfo
? getMintMinAmountAsDecimal(form.mintInfo)
: 1
const currentPrecision = precision(mintMinAmount)
const { handleSetInstructions } = useContext(NewProposalContext)
const handleSetForm = ({ propertyName, value }) => {
setFormErrors({})
setForm({ ...form, [propertyName]: value })
}
const setMintInfo = (value) => {
setForm({ ...form, mintInfo: value })
}
const setAmount = (event) => {
const value = event.target.value
handleSetForm({
value: value,
propertyName: 'amount',
})
}
const validateAmountOnBlur = () => {
const value = form.amount

handleSetForm({
value: parseFloat(
Math.max(
Number(mintMinAmount),
Math.min(Number(Number.MAX_SAFE_INTEGER), Number(value))
).toFixed(currentPrecision)
),
propertyName: 'amount',
})
}

async function getInstruction(): Promise<UiInstruction> {
return getFriktionWithdrawInstruction({
schema,
form,
amount: form.amount ?? 0,
programId,
connection,
wallet,
setFormErrors,
})
}
useEffect(() => {
// call for the mainnet friktion volts
const callfriktionRequest = async () => {
const response = await fetch(
'https://friktion-labs.github.io/mainnet-tvl-snapshots/friktionSnapshot.json'
)
const parsedResponse = (await response.json()) as FriktionSnapshot
setFriktionVolts(parsedResponse.allMainnetVolts as VoltSnapshot[])
}

callfriktionRequest()
}, [])

useEffect(() => {
handleSetForm({
propertyName: 'programId',
value: programId?.toString(),
})
}, [realmInfo?.programId])
useEffect(() => {
handleSetInstructions(
{ governedAccount: governedAccount, getInstruction },
index
)
}, [form])
useEffect(() => {
setGovernedAccount(form.governedTokenAccount?.governance)
setMintInfo(form.governedTokenAccount?.mint?.account)
}, [form.governedTokenAccount])
const schema = getFriktionWithdrawSchema()

return (
<>
<GovernedAccountSelect
label="Source account"
governedAccounts={
governedTokenAccountsWithoutNfts as GovernedMultiTypeAccount[]
}
onChange={(value) => {
handleSetForm({ value, propertyName: 'governedTokenAccount' })
}}
value={form.governedTokenAccount}
error={formErrors['governedTokenAccount']}
shouldBeGoverned={shouldBeGoverned}
governance={governance}
></GovernedAccountSelect>
<Select
label="Friktion Volt"
value={form.voltVaultId}
placeholder="Please select..."
onChange={(value) => {
const volt = friktionVolts?.find((x) => x.voltVaultId === value)
setFormErrors({})
setForm({
...form,
voltVaultId: value,
depositTokenMint: volt?.depositTokenMint,
})
}}
error={formErrors['voltVaultId']}
>
{friktionVolts
?.filter((x) => !x.isInCircuits)
.map((value) => (
<Select.Option key={value.voltVaultId} value={value.voltVaultId}>
<div className="break-all text-fgd-1 ">
<div className="mb-2">{`Volt #${value.voltType} - ${
value.voltType === 1
? 'Generate Income'
: value.voltType === 2
? 'Sustainable Stables'
: ''
} - ${value.underlyingTokenSymbol} - APY: ${value.apy}%`}</div>
<div className="space-y-0.5 text-xs text-fgd-3">
<div className="flex items-center">
Withdraw Token: {value.depositTokenSymbol}
</div>
{/* <div>Capacity: {}</div> */}
</div>
</div>
</Select.Option>
))}
</Select>
<Input
min={mintMinAmount}
label="Amount"
value={form.amount}
type="number"
onChange={setAmount}
step={mintMinAmount}
error={formErrors['amount']}
onBlur={validateAmountOnBlur}
/>
</>
)
}

export default FriktionWithdraw
3 changes: 3 additions & 0 deletions pages/dao/[symbol]/proposal/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import WithdrawObligationCollateralAndRedeemReserveLiquidity from './components/
import SplTokenTransfer from './components/instructions/SplTokenTransfer'
import VoteBySwitch from './components/VoteBySwitch'
import FriktionDeposit from './components/instructions/Friktion/FriktionDeposit'
import FriktionWithdraw from './components/instructions/Friktion/FriktionWithdraw'
import MakeChangePerpMarket from './components/instructions/Mango/MakeChangePerpMarket'
import MakeAddOracle from './components/instructions/Mango/MakeAddOracle'
import MakeAddSpotMarket from './components/instructions/Mango/MakeAddSpotMarket'
Expand Down Expand Up @@ -277,6 +278,8 @@ const New = () => {
)
case Instructions.DepositIntoVolt:
return <FriktionDeposit index={idx} governance={governance} />
case Instructions.WithdrawFromVolt:
return <FriktionWithdraw index={idx} governance={governance} />
case Instructions.CreateSolendObligationAccount:
return <CreateObligationAccount index={idx} governance={governance} />
case Instructions.InitSolendObligationAccount:
Expand Down
Loading

0 comments on commit 5bbf344

Please sign in to comment.