Skip to content

Commit

Permalink
Merge branch 'blockworks-foundation-main'
Browse files Browse the repository at this point in the history
  • Loading branch information
sjillen committed Dec 15, 2021
2 parents d8bbb71 + aa58517 commit 5081866
Show file tree
Hide file tree
Showing 12 changed files with 170 additions and 51 deletions.
2 changes: 1 addition & 1 deletion @types/types.tsx → @types/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AccountInfo, PublicKey } from '@solana/web3.js'
import type { AccountInfo, PublicKey } from '@solana/web3.js'

export interface EndpointInfo {
name: string
Expand Down
32 changes: 23 additions & 9 deletions components/TreasuryAccount/SendTokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import AccountLabel from './AccountHeader'
import Tooltip from '@components/Tooltip'
import useGovernanceAssets from '@hooks/useGovernanceAssets'
import { getTransferInstruction } from '@utils/instructionTools'
import VoteBySwitch from 'pages/dao/[symbol]/proposal/components/VoteBySwitch'

const SendTokens = () => {
const {
Expand All @@ -62,7 +63,9 @@ const SendTokens = () => {
ownVoterWeight,
mint,
councilMint,
canChooseWhoVote,
} = useRealm()

const { canUseTransferInstruction } = useGovernanceAssets()
const tokenInfo = useTreasuryAccountStore((s) => s.compact.tokenInfo)
const { fmtUrlWithCluster } = useQueryContext()
Expand All @@ -80,7 +83,8 @@ const SendTokens = () => {
title: '',
description: '',
})
const [showReferenceFields, setShowReferenceFields] = useState(false)
const [voteByCouncil, setVoteByCouncil] = useState(false)
const [showOptions, setShowOptions] = useState(false)
const [
destinationAccount,
setDestinationAccount,
Expand Down Expand Up @@ -192,15 +196,17 @@ const SendTokens = () => {
governance!.info.config
)

// Select the governing token mint for the proposal
// By default we choose the community mint if it has positive supply (otherwise nobody can vote)
// TODO: If token holders for both mints can vote the we should add the option in the UI to choose who votes (community or the council)
const proposalMint = !mint?.supply.isZero()
const defaultProposalMint = !mint?.supply.isZero()
? realm.info.communityMint
: !councilMint?.supply.isZero()
? realm.info.config.councilMint
: undefined

const proposalMint =
canChooseWhoVote && voteByCouncil
? realm.info.config.councilMint
: defaultProposalMint

if (!proposalMint) {
throw new Error(
'There is no suitable governing token for the proposal'
Expand Down Expand Up @@ -334,14 +340,14 @@ const SendTokens = () => {
</small>
<div
className={'flex items-center hover:cursor-pointer w-24'}
onClick={() => setShowReferenceFields(!showReferenceFields)}
onClick={() => setShowOptions(!showOptions)}
>
{showReferenceFields ? (
{showOptions ? (
<ArrowCircleUpIcon className="h-4 w-4 mr-1 text-primary-light" />
) : (
<ArrowCircleDownIcon className="h-4 w-4 mr-1 text-primary-light" />
)}
<small className="text-fgd-3">Reference</small>
<small className="text-fgd-3">Options</small>
{/* popover with description maybe will be needed later */}
{/* <Popover className="relative ml-auto border-none flex">
<Popover.Button className="focus:outline-none">
Expand All @@ -357,7 +363,7 @@ const SendTokens = () => {
</Popover.Panel>
</Popover> */}
</div>
{showReferenceFields && (
{showOptions && (
<>
<Input
noMaxWidth={true}
Expand Down Expand Up @@ -391,6 +397,14 @@ const SendTokens = () => {
})
}
></Textarea>
{canChooseWhoVote && (
<VoteBySwitch
checked={voteByCouncil}
onChange={() => {
setVoteByCouncil(!voteByCouncil)
}}
></VoteBySwitch>
)}
</>
)}
</div>
Expand Down
11 changes: 9 additions & 2 deletions components/chat/Comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ChatMessage } from '../../models/chat/accounts'
import { abbreviateAddress, fmtTokenAmount } from '../../utils/formatting'
import useRealm from '../../hooks/useRealm'
import { MintInfo } from '@solana/spl-token'
import { isPublicKey } from '@tools/core/pubkey'

const Comment = ({
chatMessage,
Expand All @@ -22,7 +23,13 @@ const Comment = ({
proposalMint: MintInfo | undefined
}) => {
const { author, postedAt, body } = chatMessage
const { symbol } = useRealm()
const { realmInfo } = useRealm()

const voteSymbol = !realmInfo
? ''
: isPublicKey(realmInfo.symbol)
? realmInfo.displayName
: realmInfo.symbol

return (
<div className="border-b border-fgd-4 mt-4 pb-4 last:pb-0 last:border-b-0">
Expand Down Expand Up @@ -65,7 +72,7 @@ const Comment = ({
{`${fmtTokenAmount(
voteRecord.getVoteWeight(),
proposalMint?.decimals
).toLocaleString()} ${symbol}`}
).toLocaleString()} ${voteSymbol}`}
</span>
</div>
)}
Expand Down
24 changes: 20 additions & 4 deletions hooks/useRealm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { isPublicKey } from '@tools/core/pubkey'
import { useRouter } from 'next/router'
import { useMemo, useState } from 'react'
import { getRealmInfo, RealmInfo } from '../models/registry/api'
import {
createUnchartedRealmInfo,
getCertifiedRealmInfo,
RealmInfo,
} from '../models/registry/api'
import { VoterWeight } from '../models/voteWeights'

import useWalletStore from '../stores/useWalletStore'
Expand All @@ -27,9 +32,13 @@ export default function useRealm() {
const [realmInfo, setRealmInfo] = useState<RealmInfo | undefined>(undefined)

useMemo(async () => {
const realm = await getRealmInfo(symbol as string, connection)
setRealmInfo(realm)
}, [symbol])
const realmInfo = isPublicKey(symbol as string)
? realm
? createUnchartedRealmInfo(realm)
: undefined
: await getCertifiedRealmInfo(symbol as string, connection)
setRealmInfo(realmInfo)
}, [symbol, realm])

const realmTokenAccount = useMemo(
() =>
Expand Down Expand Up @@ -68,6 +77,12 @@ export default function useRealm() {
[tokenRecords, wallet, connected]
)

const canChooseWhoVote =
realm?.info.communityMint &&
!mint?.supply.isZero() &&
realm.info.config.councilMint &&
!councilMint?.supply.isZero()

return {
realm,
realmInfo,
Expand All @@ -86,5 +101,6 @@ export default function useRealm() {
ownCouncilTokenRecord,
ownVoterWeight: new VoterWeight(ownTokenRecord, ownCouncilTokenRecord),
realmDisplayName: realmInfo?.displayName ?? realm?.info?.name,
canChooseWhoVote,
}
}
36 changes: 22 additions & 14 deletions models/registry/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Realm } from '@models/accounts'
import { getRealms } from '@models/api'
import { ParsedAccount } from '@models/core/accounts'
import { PublicKey } from '@solana/web3.js'
import { arrayToMap, arrayToUnique } from '@tools/core/script'

Expand Down Expand Up @@ -27,23 +29,27 @@ export interface RealmInfo {
twitter?: string
// og:image
ogImage?: string

isCertified: boolean
}

interface RealmInfoAsJSON extends Omit<RealmInfo, 'programId' | 'realmId'> {
interface RealmInfoAsJSON
extends Omit<RealmInfo, 'programId' | 'realmId' | 'isCertified'> {
programId: string
realmId: string
}

// TODO: Once governance program clones registry program and governance
// accounts metadata is on-chain the list should be moved there
const MAINNET_REALMS = parseRealms(mainnetBetaRealms)
const DEVNET_REALMS = parseRealms(devnetRealms)
const MAINNET_REALMS = parseCertifiedRealms(mainnetBetaRealms)
const DEVNET_REALMS = parseCertifiedRealms(devnetRealms)

function parseRealms(realms: RealmInfoAsJSON[]) {
function parseCertifiedRealms(realms: RealmInfoAsJSON[]) {
return realms.map((realm) => ({
...realm,
programId: new PublicKey(realm.programId),
realmId: new PublicKey(realm.realmId),
isCertified: true,
})) as ReadonlyArray<RealmInfo>
}

Expand All @@ -54,7 +60,7 @@ export function getCertifiedRealmInfos({ cluster }: ConnectionContext) {
return cluster === 'mainnet' ? MAINNET_REALMS : DEVNET_REALMS
}

export async function getRealmInfo(
export async function getCertifiedRealmInfo(
realmId: string,
connection: ConnectionContext
) {
Expand Down Expand Up @@ -138,8 +144,6 @@ export async function getUnchartedRealmInfos(connection: ConnectionContext) {
.flatMap((r) => Object.values(r))
.sort((r1, r2) => r1.info.name.localeCompare(r2.info.name))

const programVersion = 1

const excludedRealms = arrayToMap(certifiedRealms, (r) =>
r.realmId.toBase58()
)
Expand All @@ -150,14 +154,18 @@ export async function getUnchartedRealmInfos(connection: ConnectionContext) {
excludedRealms.has(r.pubkey.toBase58()) ||
EXCLUDED_REALMS.has(r.pubkey.toBase58())
)
? ({
symbol: r.info.name,
programId: r.account.owner,
programVersion,
realmId: r.pubkey,
displayName: r.info.name,
} as RealmInfo)
? createUnchartedRealmInfo(r)
: undefined
})
.filter(Boolean) as readonly RealmInfo[]
}

export function createUnchartedRealmInfo(realm: ParsedAccount<Realm>) {
return {
symbol: realm.info.name,
programId: new PublicKey(realm.account.owner),
realmId: realm.pubkey,
displayName: realm.info.name,
isCertified: false,
} as RealmInfo
}
17 changes: 17 additions & 0 deletions pages/dao/[symbol]/proposal/components/VoteBySwitch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Switch from '@components/Switch'
import React from 'react'

const VoteBySwitch = ({ checked, onChange }) => {
return (
<div className="text-sm mb-3">
<div className="mb-2">Vote by</div>
<div className="flex flex-row text-xs items-center">
Community
<Switch className="ml-2 mr-2" checked={checked} onChange={onChange} />
Council
</div>
</div>
)
}

export default VoteBySwitch
27 changes: 20 additions & 7 deletions pages/dao/[symbol]/proposal/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import RegisterMangoDepository from './components/instructions/RegisterMangoDepo
import SetMangoDepositoriesRedeemableSoftCap from './components/instructions/SetMangoDepositoriesRedeemableSoftCap'
import DepositInsuranceToMangoDepository from './components/instructions/DepositInsuranceToMangoDepository'
import WithdrawInsuranceFromMangoDepository from './components/instructions/WithdrawInsuranceFromMangoDepository'
import VoteBySwitch from './components/VoteBySwitch'

const schema = yup.object().shape({
title: yup.string().required('Title is required'),
})
Expand All @@ -66,7 +68,9 @@ const New = () => {
ownVoterWeight,
mint,
councilMint,
canChooseWhoVote,
} = useRealm()

const { getAvailableInstructions } = useGovernanceAssets()
const availableInstructions = getAvailableInstructions()
const wallet = useWalletStore((s) => s.current)
Expand All @@ -75,7 +79,7 @@ const New = () => {
fetchRealmGovernance,
fetchTokenAccountsForSelectedRealmGovernances,
} = useWalletStore((s) => s.actions)

const [voteByCouncil, setVoteByCouncil] = useState(false)
const [form, setForm] = useState({
title: '',
description: '',
Expand Down Expand Up @@ -208,16 +212,17 @@ const New = () => {
const ownTokenRecord = ownVoterWeight.getTokenRecordToCreateProposal(
governance.info.config
)

// Select the governing token mint for the proposal
// By default we choose the community mint if it has positive supply (otherwise nobody can vote)
// TODO: If token holders for both mints can vote the we should add the option in the UI to choose who votes (community or the council)
const proposalMint = !mint?.supply.isZero()
const defaultProposalMint = !mint?.supply.isZero()
? realm.info.communityMint
: !councilMint?.supply.isZero()
? realm.info.config.councilMint
: undefined

const proposalMint =
canChooseWhoVote && voteByCouncil
? realm.info.config.councilMint
: defaultProposalMint

if (!proposalMint) {
throw new Error(
'There is no suitable governing token for the proposal'
Expand Down Expand Up @@ -353,9 +358,9 @@ const New = () => {
/>
</div>
<Textarea
className="mb-3"
label="Description"
placeholder="Description of your proposal or use a github gist link (optional)"
wrapperClassName="mb-5"
value={form.description}
onChange={(evt) =>
handleSetForm({
Expand All @@ -364,6 +369,14 @@ const New = () => {
})
}
></Textarea>
{canChooseWhoVote && (
<VoteBySwitch
checked={voteByCouncil}
onChange={() => {
setVoteByCouncil(!voteByCouncil)
}}
></VoteBySwitch>
)}
<NewProposalContext.Provider
value={{
instructionsData,
Expand Down
8 changes: 6 additions & 2 deletions pages/realms/components/RealmsDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export default function RealmsDashboard({
const { fmtUrlWithCluster } = useQueryContext()
const { connected } = useWalletStore((s) => s)

const goToRealm = ({ symbol }) => {
const goToRealm = (realmInfo: RealmInfo) => {
const symbol =
realmInfo.isCertified && realmInfo.symbol
? realmInfo.symbol
: realmInfo.realmId.toBase58()
const url = fmtUrlWithCluster(`/dao/${symbol}`)
router.push(url)
}
Expand Down Expand Up @@ -69,7 +73,7 @@ export default function RealmsDashboard({
</div>
)}
</div>
<h3 className="text-center">
<h3 className="text-center break-all">
{realm.displayName ?? realm.symbol}
</h3>
</div>
Expand Down
6 changes: 6 additions & 0 deletions public/realms/devnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
"programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw",
"realmId": "Ap2qT88wk4CPENAcdZN6Q356mauZym4yrQptGXD2AqVF"
},
{
"symbol": "czekoladowy",
"displayName": "czekoladowy",
"programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw",
"realmId": "5VKggTk22qfm3Jpz41TYRx9RpBY37RDr4HKR1AM3D8LF"
},
{
"symbol": "Realm-8TitF",
"displayName": "Realm-8TitF",
Expand Down
Loading

1 comment on commit 5081866

@vercel
Copy link

@vercel vercel bot commented on 5081866 Dec 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.