From cbafcc2f973eebf619016e5a127e0f676d78af63 Mon Sep 17 00:00:00 2001 From: Manank Patni Date: Fri, 6 Jan 2023 03:26:25 +0530 Subject: [PATCH 1/6] Remove administrator field and set current account as admin Signed-off-by: Manank Patni --- src/modules/creator/steps/DaoSettings.tsx | 48 +++-------------------- 1 file changed, 5 insertions(+), 43 deletions(-) diff --git a/src/modules/creator/steps/DaoSettings.tsx b/src/modules/creator/steps/DaoSettings.tsx index a79740a9..37e23c96 100644 --- a/src/modules/creator/steps/DaoSettings.tsx +++ b/src/modules/creator/steps/DaoSettings.tsx @@ -23,6 +23,7 @@ import { TitleBlock } from "modules/common/TitleBlock" import { CreatorContext, ActionTypes, OrgSettings } from "modules/creator/state" import { InfoRounded } from "@material-ui/icons" import { useTokenMetadata } from "services/contracts/baseDAO/hooks/useTokenMetadata" +import { useTezos } from "services/beacon/hooks/useTezos" const SecondContainer = styled(Grid)({ marginTop: 25 @@ -298,39 +299,6 @@ const DaoSettingsForm = withRouter(({ submitForm, values, setFieldValue, errors, {errors.description && touched.description ? {errors.description} : null} - - - - {" "} - Administrator{" "} - - - - - setFieldTouched("administrator")} - placeholder="tz1PXn...." - component={CustomFormikTextField} - inputProps={{ - maxLength: 36 - }} - InputProps={{ - endAdornment: ( - - - - - - ) - }} - > - - {errors.administrator && touched.administrator ? {errors.administrator} : null} - - @@ -388,14 +356,6 @@ const validateForm = (values: OrgSettings) => { errors.description = "Required" } - if (!values.administrator) { - errors.administrator = "Required" - } - - if (values.administrator && isInvalidKtOrTzAddress(values.administrator)) { - errors.administrator = "Invalid address" - } - if (!values.guardian) { errors.guardian = "Required" } @@ -439,15 +399,17 @@ export const DaoSettings = (): JSX.Element => { const { state, dispatch, updateCache } = useContext(CreatorContext) const { orgSettings } = state.data const history = useHistory() + const { account } = useTezos() const saveStepInfo = (values: OrgSettings, { setSubmitting }: { setSubmitting: (b: boolean) => void }) => { + const newValues: OrgSettings = { ...values, administrator: account } const newState = { ...state.data, - orgSettings: values + orgSettings: newValues } updateCache(newState) setSubmitting(true) - dispatch({ type: ActionTypes.UPDATE_ORGANIZATION_SETTINGS, org: values }) + dispatch({ type: ActionTypes.UPDATE_ORGANIZATION_SETTINGS, org: newValues }) history.push(`voting`) } From 2c9c4adc5081e0ba315ac98e8ff6c27cf39ca3cb Mon Sep 17 00:00:00 2001 From: Manank Patni Date: Thu, 12 Jan 2023 04:17:25 +0530 Subject: [PATCH 2/6] Creator inputs bug fix (#458) (#459) * Squashed commit of the following: commit b4bb2cce33b518ffc1c51571cd4eba1e3d3809e6 Author: fabiolalombardim Date: Wed Dec 21 12:16:17 2022 +0100 internal link to Lite * input values converted to numbers again Co-authored-by: fabiolalombardim <37227394+fabiolalombardim@users.noreply.github.com> --- src/modules/creator/steps/Governance.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/creator/steps/Governance.tsx b/src/modules/creator/steps/Governance.tsx index 301e35b9..8da396f9 100644 --- a/src/modules/creator/steps/Governance.tsx +++ b/src/modules/creator/steps/Governance.tsx @@ -653,6 +653,9 @@ export const Governance: React.FC = () => { const history = useHistory() const saveStepInfo = (values: VotingSettings, { setSubmitting }: { setSubmitting: (b: boolean) => void }) => { + values.proposalExpiryBlocks = Number(values.proposalExpiryBlocks) + values.proposalFlushBlocks = Number(values.proposalFlushBlocks) + values.votingBlocks = Number(values.votingBlocks) const newState = { ...state.data, votingSettings: values From e9308459b9ba84768f5595e9202c56ea842b2649 Mon Sep 17 00:00:00 2001 From: Manank Patni Date: Wed, 25 Jan 2023 17:29:34 +0530 Subject: [PATCH 3/6] Add Unstake from all proposals button (#473) (#477) * Add Unstake from all proposals button Signed-off-by: Manank Patni * Move Unstake Votes button from Proposals page to User Page Signed-off-by: Manank Patni Signed-off-by: Manank Patni Signed-off-by: Manank Patni --- .../explorer/hooks/useCanDropProposal.ts | 6 +- .../explorer/pages/ProposalDetails/index.tsx | 19 +++--- .../explorer/pages/Proposals/index.tsx | 22 ++++--- src/modules/explorer/pages/User/index.tsx | 62 ++++++++++++++++--- src/services/contracts/baseDAO/class.ts | 11 ++++ .../hooks/useUnstakeFromAllProposals.ts | 54 ++++++++++++++++ .../indexer/dao/mappers/proposal/types.ts | 4 +- src/services/indexer/dao/queries.ts | 2 + src/services/indexer/types.ts | 1 + 9 files changed, 151 insertions(+), 30 deletions(-) create mode 100644 src/services/contracts/baseDAO/hooks/useUnstakeFromAllProposals.ts diff --git a/src/modules/explorer/hooks/useCanDropProposal.ts b/src/modules/explorer/hooks/useCanDropProposal.ts index a848d172..17e25cf7 100644 --- a/src/modules/explorer/hooks/useCanDropProposal.ts +++ b/src/modules/explorer/hooks/useCanDropProposal.ts @@ -20,12 +20,14 @@ export const useCanDropProposal = (daoId: string, proposalId: string) => { const isGuardian = dao.data.guardian.toLowerCase() === account.toLowerCase() - const isNotExecutedOrDropped = true + const isNotExecutedOrDropped = + (cycleInfo && proposal.getStatus(cycleInfo.currentLevel).status === ProposalStatus.DROPPED) || + (cycleInfo && proposal.getStatus(cycleInfo.currentLevel).status === ProposalStatus.EXECUTED) // dao.data.proposalsToFlush.find( // (id) => id.toLowerCase() === proposal.id.toLowerCase() // ); - return isNotExecutedOrDropped && (isProposer || hasExpired || isGuardian) + return !isNotExecutedOrDropped && (isProposer || hasExpired || isGuardian) }, [account, cycleInfo, dao, proposal]) } diff --git a/src/modules/explorer/pages/ProposalDetails/index.tsx b/src/modules/explorer/pages/ProposalDetails/index.tsx index a287caf5..7e90bd8a 100644 --- a/src/modules/explorer/pages/ProposalDetails/index.tsx +++ b/src/modules/explorer/pages/ProposalDetails/index.tsx @@ -193,13 +193,13 @@ export const ProposalDetails: React.FC = () => { const canVote = cycleInfo && proposal?.getStatus(cycleInfo.currentLevel).status === ProposalStatus.ACTIVE - const canUnstakeVotes = - cycleInfo && - proposal && - account && - (proposal.getStatus(cycleInfo.currentLevel).status === ProposalStatus.DROPPED || - proposal.getStatus(cycleInfo.currentLevel).status === ProposalStatus.EXECUTED) && - proposal.voters.some(({ address }) => address.toLowerCase() === account.toLowerCase()) + // const canUnstakeVotes = + // cycleInfo && + // proposal && + // account && + // (proposal.getStatus(cycleInfo.currentLevel).status === ProposalStatus.DROPPED || + // proposal.getStatus(cycleInfo.currentLevel).status === ProposalStatus.EXECUTED) && + // !dao?.data.ledger.find(l => l.holder.address.toLowerCase() === account.toLowerCase())?.staked.isZero() const parseReadableConfigValue = (configKey: keyof Proposal["metadata"]["config"], value: BigNumber) => { if (dao) { @@ -237,9 +237,8 @@ export const ProposalDetails: React.FC = () => { - + {/* { > - + */} diff --git a/src/modules/explorer/pages/Proposals/index.tsx b/src/modules/explorer/pages/Proposals/index.tsx index 1be87278..148c01c3 100644 --- a/src/modules/explorer/pages/Proposals/index.tsx +++ b/src/modules/explorer/pages/Proposals/index.tsx @@ -1,23 +1,23 @@ +import { Button, Grid, styled, Tooltip, Typography } from "@material-ui/core" import React, { useCallback, useState } from "react" -import { Grid, styled, Typography, Button, Tooltip } from "@material-ui/core" import { useFlush } from "services/contracts/baseDAO/hooks/useFlush" import { useDAO } from "services/indexer/dao/hooks/useDAO" import { useProposals } from "services/indexer/dao/hooks/useProposals" import { useDAOID } from "../DAO/router" -import { UserBalancesBox } from "../../components/UserBalances" -import { ContentContainer } from "../../components/ContentContainer" -import { ProposalsList } from "../../components/ProposalsList" -import { DAOStatsRow } from "../../components/DAOStatsRow" +import { ProposalSelectionMenuLambda } from "modules/explorer/components/ProposalSelectionMenuLambda" +import { useTezos } from "services/beacon/hooks/useTezos" +import { useUnstakeFromAllProposals } from "services/contracts/baseDAO/hooks/useUnstakeFromAllProposals" import { ProposalStatus } from "services/indexer/dao/mappers/proposal/types" -import { InfoIcon } from "../../components/styled/InfoIcon" import { useIsProposalButtonDisabled } from "../../../../services/contracts/baseDAO/hooks/useCycleInfo" -import { ProposalSelectionMenu } from "../../components/ProposalSelectionMenu" import { useDropAllExpired } from "../../../../services/contracts/baseDAO/hooks/useDropAllExpired" -import { SmallButton } from "../../../common/SmallButton" import { MainButton } from "../../../common/MainButton" -import { ProposalSelectionMenuLambda } from "modules/explorer/components/ProposalSelectionMenuLambda" +import { SmallButton } from "../../../common/SmallButton" +import { ContentContainer } from "../../components/ContentContainer" +import { ProposalSelectionMenu } from "../../components/ProposalSelectionMenu" +import { ProposalsList } from "../../components/ProposalsList" +import { InfoIcon } from "../../components/styled/InfoIcon" const HeroContainer = styled(ContentContainer)({ padding: "38px 38px" @@ -45,11 +45,15 @@ export const Proposals: React.FC = () => { const { data, cycleInfo } = useDAO(daoId) const { mutate } = useFlush() const { mutate: dropAllExpired } = useDropAllExpired() + const { mutate: unstakeFromAllProposals } = useUnstakeFromAllProposals() const shouldDisable = useIsProposalButtonDisabled(daoId) const { data: proposals } = useProposals(daoId) const { data: activeProposals } = useProposals(daoId, ProposalStatus.ACTIVE) const { data: executableProposals } = useProposals(daoId, ProposalStatus.EXECUTABLE) const { data: expiredProposals } = useProposals(daoId, ProposalStatus.EXPIRED) + const { data: executedProposals } = useProposals(daoId, ProposalStatus.EXECUTED) + const { data: droppedProposals } = useProposals(daoId, ProposalStatus.DROPPED) + const { account } = useTezos() const onFlush = useCallback(async () => { if (executableProposals && expiredProposals && executableProposals.length && data) { diff --git a/src/modules/explorer/pages/User/index.tsx b/src/modules/explorer/pages/User/index.tsx index c886c4b7..20cc01f3 100644 --- a/src/modules/explorer/pages/User/index.tsx +++ b/src/modules/explorer/pages/User/index.tsx @@ -1,21 +1,23 @@ import { Box, Grid, Theme, Typography } from "@material-ui/core" import { styled } from "@material-ui/styles" import dayjs from "dayjs" -import React, { useEffect, useMemo } from "react" +import { useDAOID } from "modules/explorer/pages/DAO/router" +import React, { useCallback, useEffect, useMemo } from "react" import { useHistory } from "react-router" import { useAgoraTopic } from "services/agora/hooks/useTopic" import { useTezos } from "services/beacon/hooks/useTezos" +import { useUnstakeFromAllProposals } from "services/contracts/baseDAO/hooks/useUnstakeFromAllProposals" import { toShortAddress } from "services/contracts/utils" import { useDAO } from "services/indexer/dao/hooks/useDAO" import { useProposals } from "services/indexer/dao/hooks/useProposals" import { Proposal, ProposalStatus } from "services/indexer/dao/mappers/proposal/types" -import { ProfileAvatar } from "../../components/styled/ProfileAvatar" -import { UserProfileName } from "../../components/UserProfileName" -import { useDAOID } from "modules/explorer/pages/DAO/router" import { FreezeDialog } from "../../components/FreezeDialog" -import { UserBalances } from "../../components/UserBalances" -import { StatusBadge } from "../../components/StatusBadge" import { ProposalsList } from "../../components/ProposalsList" +import { StatusBadge } from "../../components/StatusBadge" +import { ProfileAvatar } from "../../components/styled/ProfileAvatar" +import { UserBalances } from "../../components/UserBalances" +import { UserProfileName } from "../../components/UserProfileName" +import { DropButton } from "../Proposals" const ContentBlockItem = styled(Grid)({ padding: "35px 52px", @@ -36,7 +38,7 @@ const MainContainer = styled(Box)({ }) const UsernameText = styled(Typography)({ - fontSize: 28, + fontSize: 18, wordBreak: "break-all" }) @@ -94,9 +96,15 @@ export const ProposalItem: React.FC<{ export const User: React.FC = () => { const { account } = useTezos() const daoId = useDAOID() - const { cycleInfo } = useDAO(daoId) + const { data, cycleInfo } = useDAO(daoId) const { data: proposals } = useProposals(daoId) const history = useHistory() + const { data: activeProposals } = useProposals(daoId, ProposalStatus.ACTIVE) + const { data: executableProposals } = useProposals(daoId, ProposalStatus.EXECUTABLE) + const { data: expiredProposals } = useProposals(daoId, ProposalStatus.EXPIRED) + const { data: executedProposals } = useProposals(daoId, ProposalStatus.EXECUTED) + const { data: droppedProposals } = useProposals(daoId, ProposalStatus.DROPPED) + const { mutate: unstakeFromAllProposals } = useUnstakeFromAllProposals() useEffect(() => { if (!account) { @@ -120,6 +128,34 @@ export const User: React.FC = () => { return proposals.filter(p => p.voters.map(voter => voter.address.toLowerCase()).includes(account.toLowerCase())) }, [account, proposals]) + const onUnstakeFromAllProposals = useCallback(async () => { + if (droppedProposals && executedProposals && data) { + const allProposals = droppedProposals.concat(executedProposals) + + const proposalsWithStakedTokens: Proposal[] = [] + + allProposals.forEach((proposal: Proposal) => { + const userVote = proposal.voters.find(voter => voter.address === account) + if (userVote && userVote.staked) { + proposalsWithStakedTokens.push(proposal) + } + }) + + unstakeFromAllProposals({ + dao: data, + allProposals: proposalsWithStakedTokens.map(p => p.id) + }) + return + } + }, [data, account, unstakeFromAllProposals, droppedProposals, executedProposals]) + + const canUnstakeVotes: boolean | undefined = + executedProposals && + droppedProposals && + executedProposals + .concat(droppedProposals) + .some(proposal => proposal.voters.find(vote => vote.address === account)?.staked) + const getVoteDecision = (proposal: Proposal) => proposal.voters.find(voter => voter.address.toLowerCase())?.support as boolean @@ -150,6 +186,16 @@ export const User: React.FC = () => { + + + Unstake Votes + + diff --git a/src/services/contracts/baseDAO/class.ts b/src/services/contracts/baseDAO/class.ts index 7fe671ae..4b127d93 100644 --- a/src/services/contracts/baseDAO/class.ts +++ b/src/services/contracts/baseDAO/class.ts @@ -155,6 +155,17 @@ export abstract class BaseDAO { return await batch.send() } + public unstakeFromAllProposals = async (proposals: string[], account: string, tezos: TezosToolkit) => { + const daoContract = await getContract(tezos, this.data.address) + const initialBatch = await tezos.wallet.batch() + + const batch = proposals.reduce((prev, current) => { + return prev.withContractCall(daoContract.methods.unstake_vote([current])) + }, initialBatch) + + return await batch.send() + } + public sendXtz = async (xtzAmount: BigNumber, tezos: TezosToolkit) => { const contract = await getContract(tezos, this.data.address) diff --git a/src/services/contracts/baseDAO/hooks/useUnstakeFromAllProposals.ts b/src/services/contracts/baseDAO/hooks/useUnstakeFromAllProposals.ts new file mode 100644 index 00000000..c4e9e1d6 --- /dev/null +++ b/src/services/contracts/baseDAO/hooks/useUnstakeFromAllProposals.ts @@ -0,0 +1,54 @@ +import { useNotification } from "modules/common/hooks/useNotification" +import { useMutation, useQueryClient } from "react-query" +import { useTezos } from "services/beacon/hooks/useTezos" +import { BaseDAO } from ".." +import { networkNameMap } from "../../../bakingBad" + +export const useUnstakeFromAllProposals = () => { + const queryClient = useQueryClient() + const openNotification = useNotification() + const { network, tezos, account, connect } = useTezos() + + return useMutation( + async params => { + const { key: unstakeNotification, closeSnackbar: closeFlushNotification } = openNotification({ + message: "Please sign the transaction to unstake tokens from all proposals", + persist: true, + variant: "info" + }) + try { + let tezosToolkit = tezos + + if (!account) { + tezosToolkit = await connect() + } + + const data = await params.dao.unstakeFromAllProposals(params.allProposals, account, tezosToolkit) + closeFlushNotification(unstakeNotification) + + await data.confirmation(1) + openNotification({ + message: "Execute transaction confirmed!", + autoHideDuration: 5000, + variant: "success", + detailsLink: `https://${networkNameMap[network]}.tzkt.io/` + data.opHash + }) + + return data + } catch (e) { + closeFlushNotification(unstakeNotification) + openNotification({ + message: "An error has happened with execute transaction!", + variant: "error", + autoHideDuration: 5000 + }) + return new Error((e as Error).message) + } + }, + { + onSuccess: () => { + queryClient.resetQueries() + } + } + ) +} diff --git a/src/services/indexer/dao/mappers/proposal/types.ts b/src/services/indexer/dao/mappers/proposal/types.ts index a622111d..17503698 100644 --- a/src/services/indexer/dao/mappers/proposal/types.ts +++ b/src/services/indexer/dao/mappers/proposal/types.ts @@ -120,6 +120,7 @@ export abstract class Proposal { address: string value: BigNumber support: boolean + staked: boolean }[] type: DAOTemplate @@ -143,7 +144,8 @@ export abstract class Proposal { this.voters = dto.votes.map(vote => ({ address: vote.holder.address, value: parseUnits(new BigNumber(vote.amount), this.dao.data.token.decimals), - support: Boolean(vote.support) + support: Boolean(vote.support), + staked: vote.staked })) this.upVotes = this.voters.reduce((acc, voter) => { if (voter.support) { diff --git a/src/services/indexer/dao/queries.ts b/src/services/indexer/dao/queries.ts index 7667ad87..36867a37 100644 --- a/src/services/indexer/dao/queries.ts +++ b/src/services/indexer/dao/queries.ts @@ -191,6 +191,7 @@ export const GET_PROPOSALS_QUERY = gql` } id support + staked } } } @@ -234,6 +235,7 @@ export const GET_PROPOSAL_QUERY = gql` } id support + staked } } } diff --git a/src/services/indexer/types.ts b/src/services/indexer/types.ts index 16989c79..02f05ac5 100644 --- a/src/services/indexer/types.ts +++ b/src/services/indexer/types.ts @@ -181,6 +181,7 @@ export interface VoteDTO { amount: string support: boolean holder: HolderDTO + staked: boolean } export interface DAOListItem { From c81089d50c6762b093eb47eb99ebb662a34be5ba Mon Sep 17 00:00:00 2001 From: Manank Patni Date: Thu, 26 Jan 2023 18:36:38 +0530 Subject: [PATCH 4/6] Merge Develop to Master (#482) * Add Unstake from all proposals button (#473) * Add Unstake from all proposals button Signed-off-by: Manank Patni * Move Unstake Votes button from Proposals page to User Page Signed-off-by: Manank Patni Signed-off-by: Manank Patni * Fa1.2 warning banner and Filter (#480) * Squashed commit of the following: commit b4bb2cce33b518ffc1c51571cd4eba1e3d3809e6 Author: fabiolalombardim Date: Wed Dec 21 12:16:17 2022 +0100 internal link to Lite * warning banner added * Remove fa2 tokens from the balances and make warning close non appear everytime Add error in dao creator for FA1.2 not supported Signed-off-by: Manank Patni Signed-off-by: Manank Patni Co-authored-by: Manank Patni Signed-off-by: Manank Patni Co-authored-by: fabiolalombardim <37227394+fabiolalombardim@users.noreply.github.com> --- src/App.tsx | 10 ++++++++++ src/models/Token.ts | 3 +++ src/modules/common/WarningFooter.tsx | 14 +++++++++++--- src/modules/creator/steps/DaoSettings.tsx | 8 ++++++++ src/services/bakingBad/tokenBalances/index.ts | 16 ++++++++++------ src/services/bakingBad/tokenBalances/types.ts | 2 ++ src/services/indexer/types.ts | 1 + 7 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 8574cab7..6609c537 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -103,11 +103,21 @@ const App: React.FC = () => { + +
diff --git a/src/models/Token.ts b/src/models/Token.ts index 100a03b7..fd9a0695 100644 --- a/src/models/Token.ts +++ b/src/models/Token.ts @@ -11,6 +11,7 @@ interface TokenParams { decimals: number network: Network supply: string + standard: string } export const SUPPORTED_MIME_TYPES = [ @@ -49,6 +50,7 @@ export class Token { decimals: number network: Network supply: BigNumber + standard: string constructor(params: TokenParams) { this.id = params.id @@ -60,6 +62,7 @@ export class Token { this.decimals = params.decimals this.network = params.network this.supply = new BigNumber(params.supply) + this.standard = params.standard ? params.standard : "" } } diff --git a/src/modules/common/WarningFooter.tsx b/src/modules/common/WarningFooter.tsx index cc85a37d..adf8cfc9 100644 --- a/src/modules/common/WarningFooter.tsx +++ b/src/modules/common/WarningFooter.tsx @@ -1,6 +1,6 @@ import { Box, Grid, IconButton, Typography } from "@material-ui/core" import { styled } from "@material-ui/styles" -import React, { useState } from "react" +import React, { useEffect, useState } from "react" import { ReactComponent as WarningIcon } from "assets/logos/warning.svg" import CloseIcon from "@material-ui/icons/Close" import hexToRgba from "hex-to-rgba" @@ -31,9 +31,17 @@ const ContainerText = styled(Typography)({ export const WarningFooter: React.FC<{ text: string }> = ({ text }) => { const [open, setOpen] = useState(true) + const isWarningClosed = localStorage.getItem("warning-closed") + + const closeButton = () => { + localStorage.setItem("warning-closed", "true") + console.log("warning-closed") + setOpen(false) + } + return ( <> - {open && ( + {open && !isWarningClosed && isWarningClosed !== "true" && ( @@ -44,7 +52,7 @@ export const WarningFooter: React.FC<{ text: string }> = ({ text }) => { {text} - setOpen(false)}> + diff --git a/src/modules/creator/steps/DaoSettings.tsx b/src/modules/creator/steps/DaoSettings.tsx index 37e23c96..0df9f21d 100644 --- a/src/modules/creator/steps/DaoSettings.tsx +++ b/src/modules/creator/steps/DaoSettings.tsx @@ -391,6 +391,14 @@ const validateForm = (values: OrgSettings) => { address: "Could not find token" } } + + if (values.governanceToken.tokenMetadata?.standard === "fa1.2") { + errors.governanceToken = { + ...errors.governanceToken, + address: "FA1.2 Tokens Not Supported" + } + } + console.log(errors) return errors } diff --git a/src/services/bakingBad/tokenBalances/index.ts b/src/services/bakingBad/tokenBalances/index.ts index c35f085c..3e174092 100644 --- a/src/services/bakingBad/tokenBalances/index.ts +++ b/src/services/bakingBad/tokenBalances/index.ts @@ -33,7 +33,7 @@ export const getDAOBalances = async ( offset = 0, balances: DAOBalance[] = [] ): Promise => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances?account=${daoId}&limit=${ELEMENTS_PER_REQUEST}&offset=${offset}&token.metadata.artifactUri.null=true` + const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances?account=${daoId}&limit=${ELEMENTS_PER_REQUEST}&offset=${offset}&token.metadata.artifactUri.null=true&token.standard=fa2` const response = await fetch(url) if (!response.ok) { @@ -60,7 +60,8 @@ export const getDAOBalances = async ( level: balance.firstLevel, name: tokenData.metadata?.name || "", decimals: parseInt(tokenData.metadata?.decimals) || 0, - balance: balance.balance + balance: balance.balance, + standard: tokenData.standard } return tokenBalance }) @@ -82,7 +83,7 @@ export const getDAONFTBalances = async ( offset = 0, balances: DAOBalance[] = [] ): Promise => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances?account=${daoId}&limit=${ELEMENTS_PER_REQUEST}&offset=${offset}&token.metadata.artifactUri.null=false` + const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances?account=${daoId}&limit=${ELEMENTS_PER_REQUEST}&offset=${offset}&token.metadata.artifactUri.null=false&token.standard=fa2` const response = await fetch(url) if (!response.ok) { @@ -121,7 +122,8 @@ export const getDAONFTBalances = async ( uri: "" } ], - balance: balance.balance + balance: balance.balance, + standard: tokenData.standard } return tokenBalance }) @@ -168,7 +170,8 @@ export const getTokenMetadata = async (contractAddress: string, network: Network creators: tokenData.metadata?.creators, tags: tokenData.metadata?.tags, formats: tokenData.metadata?.formats, - balance: "" + balance: "", + standard: tokenData.standard } } else { result = { @@ -181,7 +184,8 @@ export const getTokenMetadata = async (contractAddress: string, network: Network level: tokenData.firstLevel, name: tokenData.metadata?.name || "", decimals: parseInt(tokenData.metadata?.decimals) || 0, - balance: "" + balance: "", + standard: tokenData.standard } } diff --git a/src/services/bakingBad/tokenBalances/types.ts b/src/services/bakingBad/tokenBalances/types.ts index 194a0e27..81ef7a07 100644 --- a/src/services/bakingBad/tokenBalances/types.ts +++ b/src/services/bakingBad/tokenBalances/types.ts @@ -13,6 +13,7 @@ export interface FA2TokenDTO { network: Network supply: string balance: string + standard: string } export interface NFTDTO { @@ -36,6 +37,7 @@ export interface NFTDTO { uri: string }[] balance: string + standard: string } export interface BalanceTZKT { diff --git a/src/services/indexer/types.ts b/src/services/indexer/types.ts index 02f05ac5..c8db2fc2 100644 --- a/src/services/indexer/types.ts +++ b/src/services/indexer/types.ts @@ -23,6 +23,7 @@ export interface TokenDTO { should_prefer_symbol: boolean supply: string daos?: DAODTO[] + standard: string } export interface DAODTO { From c6dc13dd3c3ba2896689c2b024863cbb175321b0 Mon Sep 17 00:00:00 2001 From: Manank Patni Date: Tue, 7 Feb 2023 03:19:50 +0530 Subject: [PATCH 5/6] Add FA1.2 support and remove banner (#489) Signed-off-by: Manank Patni --- src/App.tsx | 8 +- .../explorer/components/ProposalForm.tsx | 9 +- src/services/bakingBad/tokenBalances/index.ts | 4 +- .../transfer_proposal_type.json | 325 ++++++++++-------- .../contracts/baseDAO/lambdaDAO/types.ts | 15 +- src/services/contracts/baseDAO/types.ts | 11 +- .../indexer/dao/mappers/proposal/index.ts | 42 ++- .../indexer/dao/mappers/proposal/types.ts | 2 +- 8 files changed, 260 insertions(+), 156 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 6609c537..328a4c2e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -103,21 +103,21 @@ const App: React.FC = () => { - + /> */} - + /> */}
diff --git a/src/modules/explorer/components/ProposalForm.tsx b/src/modules/explorer/components/ProposalForm.tsx index 97194296..dc538e84 100644 --- a/src/modules/explorer/components/ProposalForm.tsx +++ b/src/modules/explorer/components/ProposalForm.tsx @@ -125,16 +125,17 @@ export const ProposalFormContainer: React.FC = ({ open, handleClose, defa const mappedTransfers = [...values.transferForm.transfers, ...values.nftTransferForm.transfers] .filter(transfer => !!transfer.amount && !!transfer.asset && !!transfer.recipient) - .map(transfer => - (transfer.asset as Asset).symbol === "XTZ" + .map(transfer => { + const type = (transfer.asset as Token).standard === "fa2" ? "FA2" : "FA1.2" + return (transfer.asset as Asset).symbol === "XTZ" ? { ...transfer, amount: transfer.amount, type: "XTZ" as const } : { ...transfer, amount: transfer.amount, asset: transfer.asset as Token, - type: "FA2" as const + type: type } - ) + }) const mappedList = values.registryUpdateForm.list.filter(item => !!item.key && !!item.value) diff --git a/src/services/bakingBad/tokenBalances/index.ts b/src/services/bakingBad/tokenBalances/index.ts index 3e174092..55ec5c1f 100644 --- a/src/services/bakingBad/tokenBalances/index.ts +++ b/src/services/bakingBad/tokenBalances/index.ts @@ -33,7 +33,7 @@ export const getDAOBalances = async ( offset = 0, balances: DAOBalance[] = [] ): Promise => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances?account=${daoId}&limit=${ELEMENTS_PER_REQUEST}&offset=${offset}&token.metadata.artifactUri.null=true&token.standard=fa2` + const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances?account=${daoId}&limit=${ELEMENTS_PER_REQUEST}&offset=${offset}&token.metadata.artifactUri.null=true` const response = await fetch(url) if (!response.ok) { @@ -83,7 +83,7 @@ export const getDAONFTBalances = async ( offset = 0, balances: DAOBalance[] = [] ): Promise => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances?account=${daoId}&limit=${ELEMENTS_PER_REQUEST}&offset=${offset}&token.metadata.artifactUri.null=false&token.standard=fa2` + const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances?account=${daoId}&limit=${ELEMENTS_PER_REQUEST}&offset=${offset}&token.metadata.artifactUri.null=false` const response = await fetch(url) if (!response.ok) { diff --git a/src/services/contracts/baseDAO/lambdaDAO/michelson/supported_lambda_types/transfer_proposal_type.json b/src/services/contracts/baseDAO/lambdaDAO/michelson/supported_lambda_types/transfer_proposal_type.json index 3887df12..07c93b5f 100644 --- a/src/services/contracts/baseDAO/lambdaDAO/michelson/supported_lambda_types/transfer_proposal_type.json +++ b/src/services/contracts/baseDAO/lambdaDAO/michelson/supported_lambda_types/transfer_proposal_type.json @@ -1,137 +1,190 @@ { - "prim": "pair", - "args": [ - { - "prim": "pair", - "args": [ - { - "prim": "nat", - "annots": [ - "%agora_post_id" - ] - }, - { - "prim": "list", - "annots": [ - "%registry_diff" - ], - "args": [ - { - "prim": "pair", - "args": [ - { - "prim": "string" - }, - { - "prim": "option", - "args": [ - { - "prim": "string" - } - ] - } - ] - } - ] - } - ] - }, - { - "prim": "list", - "annots": [ - "%transfers" - ], - "args": [ - { - "prim": "or", - "args": [ - { - "prim": "pair", - "annots": [ - "%xtz_transfer_type" - ], - "args": [ - { - "prim": "mutez", - "annots": [ - "%amount" - ] - }, - { - "prim": "address", - "annots": [ - "%recipient" - ] - } - ] - }, - { - "prim": "pair", - "annots": [ - "%token_transfer_type" - ], - "args": [ - { - "prim": "address", - "annots": [ - "%contract_address" - ] - }, - { - "prim": "list", - "annots": [ - "%transfer_list" - ], - "args": [ - { - "prim": "pair", - "args": [ - { - "prim": "address", - "annots": [ - "%from_" - ] - }, - { - "prim": "list", - "annots": [ - "%txs" - ], - "args": [ - { - "prim": "pair", - "args": [ - { - "prim": "address", - "annots": [ - "%to_" - ] - }, - { - "prim": "nat", - "annots": [ - "%token_id" - ] - }, - { - "prim": "nat", - "annots": [ - "%amount" - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } \ No newline at end of file + "prim": "pair", + "args": [ + { + "prim": "pair", + "args": [ + { + "prim": "nat", + "annots": [ + "%agora_post_id" + ] + }, + { + "prim": "list", + "annots": [ + "%registry_diff" + ], + "args": [ + { + "prim": "pair", + "args": [ + { + "prim": "string" + }, + { + "prim": "option", + "args": [ + { + "prim": "string" + } + ] + } + ] + } + ] + } + ] + }, + { + "prim": "list", + "annots": [ + "%transfers" + ], + "args": [ + { + "prim": "or", + "args": [ + { + "prim": "pair", + "annots": [ + "%xtz_transfer_type" + ], + "args": [ + { + "prim": "mutez", + "annots": [ + "%amount" + ] + }, + { + "prim": "address", + "annots": [ + "%recipient" + ] + } + ] + }, + { + "prim": "or", + "args": [ + { + "prim": "pair", + "annots": [ + "%token_transfer_type" + ], + "args": [ + { + "prim": "address", + "annots": [ + "%contract_address" + ] + }, + { + "prim": "list", + "annots": [ + "%transfer_list" + ], + "args": [ + { + "prim": "pair", + "args": [ + { + "prim": "address", + "annots": [ + "%from_" + ] + }, + { + "prim": "list", + "annots": [ + "%txs" + ], + "args": [ + { + "prim": "pair", + "args": [ + { + "prim": "address", + "annots": [ + "%to_" + ] + }, + { + "prim": "nat", + "annots": [ + "%token_id" + ] + }, + { + "prim": "nat", + "annots": [ + "%amount" + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "prim": "pair", + "annots": [ + "%legacy_token_transfer_type" + ], + "args": [ + { + "prim": "address", + "annots": [ + "%contract_address" + ] + }, + { + "prim": "pair", + "annots": [ + "%transfer" + ], + "args": [ + { + "prim": "address", + "annots": [ + "%from" + ] + }, + { + "prim": "pair", + "annots": [ + "%target" + ], + "args": [ + { + "prim": "address", + "annots": [ + "%to" + ] + }, + { + "prim": "nat", + "annots": [ + "%value" + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/services/contracts/baseDAO/lambdaDAO/types.ts b/src/services/contracts/baseDAO/lambdaDAO/types.ts index 23a2eff7..d3dfd685 100644 --- a/src/services/contracts/baseDAO/lambdaDAO/types.ts +++ b/src/services/contracts/baseDAO/lambdaDAO/types.ts @@ -365,6 +365,17 @@ export interface PMFA2TransferType { ] } +export interface PMFA12TransferType { + contract_address: string + transfer: { + from: string + target: { + to: string + value: BigNumber + } + } +} + interface ConfigProposalDTO { frozen_extra_value?: string frozen_scale_value?: string @@ -389,7 +400,7 @@ export type PMTreasuryProposal = | { transfer_proposal: { agora_post_id: string - transfers: (PMXTZTransferType | PMFA2TransferType)[] + transfers: (PMXTZTransferType | PMFA2TransferType | PMFA12TransferType)[] } } @@ -402,7 +413,7 @@ export type PMRegistryProposal = "0": string "1": string }[] - transfers: (PMXTZTransferType | PMFA2TransferType)[] + transfers: (PMXTZTransferType | PMFA2TransferType | PMFA12TransferType)[] } } diff --git a/src/services/contracts/baseDAO/types.ts b/src/services/contracts/baseDAO/types.ts index a2eb2a8d..95b426a5 100644 --- a/src/services/contracts/baseDAO/types.ts +++ b/src/services/contracts/baseDAO/types.ts @@ -12,7 +12,7 @@ export interface TokenHolder { balance: number } -export type TransferParams = XTZTransferParams | FA2TransferParams +export type TransferParams = XTZTransferParams | FA2TransferParams | FA12TransferParams export interface XTZTransferParams { amount: number @@ -23,7 +23,14 @@ export interface XTZTransferParams { export interface FA2TransferParams { amount: number recipient: string - type: "FA2" + type: string + asset: TokenModel +} + +export interface FA12TransferParams { + amount: number + recipient: string + type: string asset: TokenModel } diff --git a/src/services/indexer/dao/mappers/proposal/index.ts b/src/services/indexer/dao/mappers/proposal/index.ts index 969e4aa4..5a7185ef 100644 --- a/src/services/indexer/dao/mappers/proposal/index.ts +++ b/src/services/indexer/dao/mappers/proposal/index.ts @@ -1,10 +1,12 @@ import { Transfer } from "./types" import { formatUnits, xtzToMutez } from "services/contracts/utils" import BigNumber from "bignumber.js" -import { FA2TransferParams, TransferParams, XTZTransferParams } from "services/contracts/baseDAO" -import { PMFA2TransferType, PMXTZTransferType } from "services/contracts/baseDAO/lambdaDAO/types" +import { FA12TransferParams, FA2TransferParams, TransferParams, XTZTransferParams } from "services/contracts/baseDAO" +import { PMFA12TransferType, PMFA2TransferType, PMXTZTransferType } from "services/contracts/baseDAO/lambdaDAO/types" -export const extractTransfersData = (transfersDTO: (PMXTZTransferType | PMFA2TransferType)[]): Transfer[] => { +export const extractTransfersData = ( + transfersDTO: (PMXTZTransferType | PMFA2TransferType | PMFA12TransferType)[] +): Transfer[] => { const transfers = transfersDTO.map((transfer: any) => { if (transfer.hasOwnProperty("xtz_transfer_type")) { const xtzTransfer = transfer @@ -14,7 +16,7 @@ export const extractTransfersData = (transfersDTO: (PMXTZTransferType | PMFA2Tra beneficiary: xtzTransfer.xtz_transfer_type.recipient, type: "XTZ" as const } - } else { + } else if (transfer.hasOwnProperty("token_transfer_type")) { const fa2Transfer = transfer return { @@ -24,6 +26,17 @@ export const extractTransfersData = (transfersDTO: (PMXTZTransferType | PMFA2Tra tokenId: fa2Transfer.token_transfer_type.transfer_list[0].txs[0].token_id, type: "FA2" as const } + } else { + const fa12Transfer = transfer + console.log("fa12Transfer: ", fa12Transfer) + + return { + amount: fa12Transfer.legacy_token_transfer_type.transfer.target.value, + beneficiary: fa12Transfer.legacy_token_transfer_type.transfer.target.to, + contractAddress: fa12Transfer.legacy_token_transfer_type.contract_address, + type: "FA1.2" as const, + tokenId: "0" + } } }) @@ -59,12 +72,31 @@ const mapFA2TransfersArgs = (transfer: FA2TransferParams, daoAddress: string) => } } +const mapFA12TransfersArgs = (transfer: FA12TransferParams, daoAddress: string) => { + return { + legacy_token_transfer_type: { + contract_address: transfer.asset.contract, + transfer: { + from: daoAddress, + target: { + to: transfer.recipient, + value: formatUnits(new BigNumber(transfer.amount), transfer.asset.decimals).toNumber() + } + } + } + } +} + export const mapTransfersArgs = (transfers: TransferParams[], daoAddress: string) => { return transfers.map(transfer => { if (transfer.type === "FA2") { return mapFA2TransfersArgs(transfer, daoAddress) } - return mapXTZTransfersArgs(transfer) + if (transfer.type === "FA1.2") { + return mapFA12TransfersArgs(transfer as FA12TransferParams, daoAddress) + } + + return mapXTZTransfersArgs(transfer as XTZTransferParams) }) } diff --git a/src/services/indexer/dao/mappers/proposal/types.ts b/src/services/indexer/dao/mappers/proposal/types.ts index 17503698..e38c2a9e 100644 --- a/src/services/indexer/dao/mappers/proposal/types.ts +++ b/src/services/indexer/dao/mappers/proposal/types.ts @@ -37,7 +37,7 @@ export enum ProposalStatus { export interface Transfer { amount: BigNumber beneficiary: string - type: "XTZ" | "FA2" + type: "XTZ" | "FA2" | "FA1.2" } export interface FA2Transfer extends Transfer { From 496f7b09748b3bc049c52a590f9fb2b0e6ba653d Mon Sep 17 00:00:00 2001 From: Manank Patni Date: Tue, 7 Feb 2023 04:52:59 +0530 Subject: [PATCH 6/6] Fix README.md Signed-off-by: Manank Patni --- README.md | 127 +++++++++++++++++++++++++----------------------------- 1 file changed, 58 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 14790fbb..dc06ad1c 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,39 @@ # Tezos Homebase + [![](https://img.shields.io/badge/license-MIT-brightgreen)](LICENSE) Homebase is a platform designed to let users create and manage DAOs on the Tezos blockchain. - + # Prerequisites + The following dependencies are required to run homebase-app: | Dependency | Version | | ---------- | ------------------- | -| Node | `v12.18.4` or above | +| Node | `v16.16.0` or above | | Yarn | `v1.22.*` or above | # Third Party Services The following third party services are being used by Homebase: -## [Better Call Dev API](https://better-call.dev/docs) -### Base URL: https://api.better-call.dev/v1 - -| Endpoint | URL | METHOD | -| ------------------- | -------------------------------------------------------------------- | ------ | -| BigMap Keys | /bigmap/{network}/{number}/keys | GET | -| Contract | /contract/{network}/{address} | GET | -| Contract Operations | /contract/{network}/{address}/operations?size=10000&entrypoints=vote | GET | -| Contract Storage | /contract/{network}/{address}/storage | GET | - -## [Pinata IPFS](https://pinata.cloud/) -### Base URL: https://api.pinata.cloud - -| Endpoint | URL | METHOD | -| ------------- | --------------------------- | ------ | -| Pin to IPFS | /pinning/pinJSONToIPFS | POST | -| Pin List | /data/pinList?status=pinned | GET | -| Hash Metadata | /pinning/hashMetadata | PUT | - ## [TZKT API](https://api.tzkt.io/) + ### Base URL: https://api.tzkt.io/ | Endpoint | URL | METHOD | | ---------- | ---------------------------------- | ------ | | Operations | /v1/accounts/${address}/operations | GET | +## [Taquito Beacon Wallet](https://docs.walletbeacon.io/) + +### Version: 13.0.1 -## [Airgap's Beacon SDK](https://github.com/airgap-it/beacon-sdk) -### Version: 2.2.1 # Using Homebase ## Creating a DAO -1. Go to https://tezos-homebase.netlify.app/ +1. Go to https://tezos-homebase.io/ 2. Click on the `Create a DAO` button You will be taken to the DAO Creator, from which you will be asked to choose on the currently supported DAO templates. @@ -58,25 +43,25 @@ You will be taken to the DAO Creator, from which you will be asked to choose on **DAO Settings**: - * DAO Name: this will also be the name of the DAO's token. - * Token Symbol - * Description +- DAO Name: this will also be the name of the DAO's token. +- Token Symbol +- Description **Proposals and Voting**: - * **`Voting period duration`** - * **`Required stake to propose`**: required amount of DAO tokens to stake at the time of proposing. Currently follows the formula: `b + proposalSize`. Where: - - Proposal size is autocalculated based on the amount of transfers/registry updates (will get outdated soon on the contracts side) - - B is a constant amount of tokens - * **`Returned stake after proposal rejection`** - * **`Transfer amounts`** **(Treasury only)**: maximum and minimum amounts that can be transferred in a treasury proposal transfer. Currently only supports `XTZ` - * **`Quorum threshold`**: currently a natural number representing the total amount of votes required for a proposal to pass. Each token staked in a vote operation represents a vote. Therefore, with a quorum threshold of 500, a vote that stakes 500 tokens would make the proposal pass. - * **`Maximum proposal size`** +- **`Voting period duration`** +- **`Required stake to propose`**: required amount of DAO tokens to stake at the time of proposing. Currently follows the formula: `b + proposalSize`. Where: + - Proposal size is autocalculated based on the amount of transfers/registry updates (will get outdated soon on the contracts side) + - B is a constant amount of tokens +- **`Returned stake after proposal rejection`** +- **`Transfer amounts`** **(Treasury only)**: maximum and minimum amounts that can be transferred in a treasury proposal transfer. Currently only supports `XTZ` +- **`Quorum threshold`**: currently a natural number representing the total amount of votes required for a proposal to pass. Each token staked in a vote operation represents a vote. Therefore, with a quorum threshold of 500, a vote that stakes 500 tokens would make the proposal pass. +- **`Maximum proposal size`** **Distribution Settings**: - * **`TokenHolders`**: initial token holder addresses and their initial balances. At least 1 is required. - * **`Administrator`** +- **`TokenHolders`**: initial token holder addresses and their initial balances. At least 1 is required. +- **`Administrator`** 5. You will then be taken to the review page. From here, click the `LAUNCH` button on the bottom right corner. 6. You will be redirected to the Launch screen. Do not close your browser tab until the whole process is complete (you are able to see and track progress by looking at the progress bar of this screen). You will be asked to connect your wallet if you haven't already, and then will be asked for 2 signatures: the first one originates the `Metadata Carrier` contract and the second one originates the actual `DAO contract`. When the originations are complete you will see a success message and a `Go to my DAO` button @@ -88,45 +73,48 @@ There is a searchbar available, however, note that searches done using this bar Specific DAOs can be explored by clicking on them in the home screen or by URL: -`https://tezos-homebase.herokuapp.com/explorer/dao/${DAO_ADDRESS}` +`https://tezos-homebase.io/explorer/dao/${DAO_ADDRESS}` ## Managing a DAO All DAOs, regardless of their template, have: **DAO page**: contains all general DAO information. Here you can see: - * Current cycle - * Time left to vote - * DAO name and description - * DAO template type - * Token holders and their balances - * Active proposals - * Frozen tokens - * Voting addresses - * `Execute` button + +- Current cycle +- Time left to vote +- DAO name and description +- DAO template type +- Token holders and their balances +- Active proposals +- Frozen tokens +- Voting addresses +- `Execute` button **Proposals page**: contains all proposals related information and related actions. Here you can see: - * DAO name - * `New Proposal` button and creation modal - * `Execute` button - * Active proposals - * Frozen tokens - * Voting addresses - * Tables with all proposals, passed proposals and active proposals. Each proposal item contains: - * Title - * Hash - * Creation date and cycle - * Quorum reached vs quorum threshold - * For/Against votes vs total votes + +- DAO name +- `New Proposal` button and creation modal +- `Execute` button +- Active proposals +- Frozen tokens +- Voting addresses +- Tables with all proposals, passed proposals and active proposals. Each proposal item contains: + - Title + - Hash + - Creation date and cycle + - Quorum reached vs quorum threshold + - For/Against votes vs total votes **Proposal detail page**: contains all specific information about a proposal and vote actions. Here you can see: - * Breakdown of the proposal's details (transfers to execute, registry items to update, among others) - * Proposal title and description - * Status badge and history - * Quorum reached vs quorum threshold - * Proposer - * For and against votes, each with a detailed modal - * Vote for and against buttons and modals. Only enabled if proposal is active + +- Breakdown of the proposal's details (transfers to execute, registry items to update, among others) +- Proposal title and description +- Status badge and history +- Quorum reached vs quorum threshold +- Proposer +- For and against votes, each with a detailed modal +- Vote for and against buttons and modals. Only enabled if proposal is active **Proposal creation modal**: all proposal creation modals support multiple operations batched in the same proposal and also allow the user to batch upload transactions with a JSON file. This JSON should follow a specific signature, based on the template type of the DAO. See [proposal JSON signatures for each template](#dao-template-specific-pages-and-details) @@ -179,6 +167,7 @@ At a contract level, there is no such distinction, but in the UI it exists to le ``` # Contributing + ## Developer Docs - [Tezos Homebase Docs](https://docs.google.com/document/d/1zZwcvX0jNE8PycOMNSULy2i-mcjg1LJ9FFYbGP4m9TM/edit?usp=sharing) @@ -197,8 +186,8 @@ To run the project: # Glossary -* **Execute (Flush)**: execute all passed proposals from periods previous to the last one. If the proposal is rejected or did not meet the quorum threshold, then the Execute operation removes it from the proposals list. +- **Execute (Flush)**: execute all passed proposals from periods previous to the last one. If the proposal is rejected or did not meet the quorum threshold, then the Execute operation removes it from the proposals list. -* **Administrator**: address with permissions to mint, burn and transfer tokens in the DAO without a proposal. It is configured by the DAO creator and can be another contract (like a multisig) +- **Administrator**: address with permissions to mint, burn and transfer tokens in the DAO without a proposal. It is configured by the DAO creator and can be another contract (like a multisig) -* **Proposal size**: metric that describes the size, in packed bytes, of a proposal's metadata. Therefore, the bigger the proposal arguments are (more transfers or more registry updates), the bigger the proposal size is. +- **Proposal size**: metric that describes the size, in packed bytes, of a proposal's metadata. Therefore, the bigger the proposal arguments are (more transfers or more registry updates), the bigger the proposal size is.