`
`;
const DetailText = styled(Box)`
-padding: 0 0.2rem;
+ padding: 0 0.2rem;
-@media only screen and (min-width: 768px) {
- padding - right: 0.5rem;
-}
+ @media only screen and (min-width: 768px) {
+ padding-right: 0.5rem;
+ }
`;
const ProposalStatus: React.FC
= ({
diff --git a/src/Components/ProposalStatus/__snapshots__/ProposalStatus.test.tsx.snap b/src/Components/ProposalStatus/__snapshots__/ProposalStatus.test.tsx.snap
index eeac15f29..330d476b0 100644
--- a/src/Components/ProposalStatus/__snapshots__/ProposalStatus.test.tsx.snap
+++ b/src/Components/ProposalStatus/__snapshots__/ProposalStatus.test.tsx.snap
@@ -10,7 +10,7 @@ exports[`ProposalStatus loading 1`] = `
class="sc-iBPTik gOtsle"
>
= ({
const ensAvatar = useENSAvatar(proposal?.creator, MAINNET_ID);
- // Make into hooks
- const timeDetail = useMemo(() => {
- if (!proposal?.endTime) return null;
-
- const currentTime = moment();
- if (proposal.endTime?.isBefore(currentTime)) {
- return proposal.endTime.fromNow();
- } else {
- return proposal.endTime.toNow();
- }
- }, [proposal]);
-
- // Make into singular guild state hook
- const status = useMemo(() => {
- if (!proposal?.endTime) return null;
- switch (proposal.state) {
- case ProposalState.Active:
- const currentTime = moment();
- if (currentTime.isSameOrAfter(proposal.endTime)) {
- return ProposalState.Failed;
- } else {
- return ProposalState.Active;
- }
- case ProposalState.Executed:
- return ProposalState.Executed;
- case ProposalState.Passed:
- return ProposalState.Passed;
- case ProposalState.Failed:
- return ProposalState.Failed;
- default:
- return proposal.state;
- }
- }, [proposal]);
+ const status = useProposalState(proposal);
return (
= ({
ensAvatar={ensAvatar}
votes={votes}
href={`/${chainName}/${guildId}/proposal/${proposalId}`}
- statusProps={{ timeDetail, status, endTime: proposal?.endTime }}
+ statusProps={{
+ timeDetail: proposal?.timeDetail,
+ status,
+ endTime: proposal?.endTime,
+ }}
summaryActions={summaryActions}
/>
);
diff --git a/src/hooks/Guilds/ether-swr/guild/useProposal.ts b/src/hooks/Guilds/ether-swr/guild/useProposal.ts
index 7f8534d85..a3a138f36 100644
--- a/src/hooks/Guilds/ether-swr/guild/useProposal.ts
+++ b/src/hooks/Guilds/ether-swr/guild/useProposal.ts
@@ -1,16 +1,35 @@
-import { unix } from 'moment';
+import moment, { unix } from 'moment';
import { Middleware, SWRHook } from 'swr';
-import { Proposal } from '../../../../types/types.guilds';
import useEtherSWR from '../useEtherSWR';
import ERC20GuildContract from 'contracts/ERC20Guild.json';
+import { Proposal, ContractState } from 'types/types.guilds.d';
const formatterMiddleware: Middleware =
(useSWRNext: SWRHook) => (key, fetcher, config) => {
const swr = useSWRNext(key, fetcher, config);
if (swr.data) {
const original = swr.data as any;
-
const clone: any = Object.assign({}, swr.data);
+
+ //rename state to contractState
+ clone.contractState = clone.state;
+ delete clone.state;
+
+ switch (clone.contractState) {
+ case 1:
+ clone.contractState = ContractState.Active;
+ break;
+ case 2:
+ clone.contractState = ContractState.Rejected;
+ break;
+ case 3:
+ clone.contractState = ContractState.Executed;
+ break;
+ case 4:
+ clone.contractState = ContractState.Failed;
+ break;
+ }
+
clone.startTime = original.startTime
? unix(original.startTime.toNumber())
: null;
@@ -18,17 +37,28 @@ const formatterMiddleware: Middleware =
? unix(original.endTime.toNumber())
: null;
+ // Add timeDetail
+ const currentTime = moment();
+ let differenceInMilliseconds = currentTime.diff(clone.endTime);
+ let timeDifference = moment.duration(differenceInMilliseconds).humanize();
+ if (clone.endTime.isBefore(currentTime)) {
+ clone.timeDetail = `ended ${timeDifference} ago`;
+ } else {
+ clone.timeDetail = `${timeDifference} left`;
+ }
+
return { ...swr, data: clone };
}
return swr;
};
export const useProposal = (guildId: string, proposalId: string) => {
- return useEtherSWR(
+ let result = useEtherSWR(
guildId && proposalId ? [guildId, 'getProposal', proposalId] : [],
{
use: [formatterMiddleware],
ABIs: new Map([[guildId, ERC20GuildContract.abi]]),
}
);
+ return result;
};
diff --git a/src/hooks/Guilds/guild/useProposalCalls.ts b/src/hooks/Guilds/guild/useProposalCalls.ts
index 279fee59f..f60bf3d6c 100644
--- a/src/hooks/Guilds/guild/useProposalCalls.ts
+++ b/src/hooks/Guilds/guild/useProposalCalls.ts
@@ -2,12 +2,12 @@ import { useState, useEffect, useMemo } from 'react';
import { useTheme } from 'styled-components';
import { useWeb3React } from '@web3-react/core';
import { bulkDecodeCallsFromOptions } from '../contracts/useDecodedCall';
-import useProposalMetadata from 'hooks/Guilds/ether-swr/guild/useProposalMetadata';
import { decodeCall } from 'hooks/Guilds/contracts/useDecodedCall';
import { useProposal } from '../ether-swr/guild/useProposal';
import { useVotingResults } from 'hooks/Guilds/ether-swr/guild/useVotingResults';
import { Call, Option } from 'old-components/Guilds/ActionsBuilder/types';
import { ZERO_HASH } from 'utils';
+import useProposalMetadata from '../useProposalMetadata';
import { useRichContractRegistry } from '../contracts/useRichContractRegistry';
import { ERC20_APPROVE_SIGNATURE } from 'utils';
import useGuildImplementationTypeConfig from './useGuildImplementationType';
diff --git a/src/hooks/Guilds/useExecutable/index.test.ts b/src/hooks/Guilds/useExecutable/index.test.ts
new file mode 100644
index 000000000..3d45bb634
--- /dev/null
+++ b/src/hooks/Guilds/useExecutable/index.test.ts
@@ -0,0 +1,92 @@
+import { renderHook } from '@testing-library/react-hooks';
+import { BigNumber } from 'ethers';
+import { ContractState } from 'types/types.guilds.d';
+import useExecutable from '.';
+import * as hooks from '../ether-swr/guild/useProposal';
+
+jest.mock('moment', () => {
+ return () =>
+ jest.requireActual('moment')('01.01.2022 10:10', 'DD.MM.YYYY HH:mm');
+});
+
+let mockedData = {
+ id: '0x0',
+ creator: '0x0',
+ startTime: jest.requireActual('moment')(
+ '01.01.2022 10:10',
+ 'DD.MM.YYYY HH:mm'
+ ),
+ endTime: jest.requireActual('moment')('01.01.2022 11:10', 'DD.MM.YYYY HH:mm'),
+ timeDetail: '',
+ to: ['0x0', '0x0'],
+ data: ['0x0', '0x0'],
+ value: [BigNumber.from(0), BigNumber.from(0)],
+ totalActions: BigNumber.from(0),
+ title: 'Proposal Title',
+ contentHash: '0x0',
+ contractState: ContractState.Active,
+ totalVotes: [BigNumber.from(0)],
+};
+
+jest.mock('react-router-dom', () => ({
+ _esModule: true,
+ useParams: () => ({
+ guildId: 'guild_id',
+ proposalId: 'proposal_id',
+ }),
+ useRouteMatch: () => ({ url: '/guild_id/proposal_id/' }),
+}));
+
+jest.mock('contexts/Guilds/transactions', () => ({
+ useTransactions: () => ({
+ transactions: {
+ hash: '0x0',
+ from: '0x0',
+ addedTime: 0,
+ },
+ pendingTransaction: {
+ summary: 'filler transaction',
+ transactionHash: '0x0',
+ cancelled: false,
+ showModal: true,
+ },
+ createTransaction: jest.fn(() => true),
+ clearAllTransactions: jest.fn(),
+ }),
+}));
+
+jest.mock('hooks/Guilds/contracts/useContract', () => ({
+ useERC20Guild: () => ({
+ contractId: '0x0',
+ abi: 'anything',
+ provider: jest.fn(),
+ account: '0x0',
+ chainId: 0,
+ walletChainId: 0,
+ withSignerIfPossible: false,
+ }),
+}));
+
+describe('useExecutable', () => {
+ it(`executeProposal function is valid if there is proposal data`, async () => {
+ jest.spyOn(hooks, 'useProposal').mockImplementation(() => ({
+ data: mockedData,
+ isValidating: false,
+ mutate: null,
+ }));
+ const { result } = renderHook(() => useExecutable());
+ expect(result.current.loading).toBeFalsy();
+ expect(result.current.data.executeProposal).toBeTruthy();
+ });
+
+ it(`executeProposal function is null if there isn't proposal data`, async () => {
+ jest.spyOn(hooks, 'useProposal').mockImplementation(() => ({
+ data: null,
+ isValidating: false,
+ mutate: null,
+ }));
+ const { result } = renderHook(() => useExecutable());
+ expect(result.current.loading).toBeTruthy();
+ expect(result.current.data.executeProposal).toBeNull();
+ });
+});
diff --git a/src/hooks/Guilds/useExecutable/index.ts b/src/hooks/Guilds/useExecutable/index.ts
new file mode 100644
index 000000000..d8b298071
--- /dev/null
+++ b/src/hooks/Guilds/useExecutable/index.ts
@@ -0,0 +1,47 @@
+import { useTransactions } from 'contexts/Guilds/transactions';
+import { useERC20Guild } from 'hooks/Guilds/contracts/useContract';
+import { useMemo } from 'react';
+import { useParams } from 'react-router-dom';
+import { useProposal } from '../ether-swr/guild/useProposal';
+
+interface useExecutableReturns {
+ data: {
+ executeProposal: () => void;
+ };
+ error: Error;
+ loading: boolean;
+}
+
+function useExecutable(): useExecutableReturns {
+ const { guildId, proposalId } =
+ useParams<{ guildId?: string; proposalId?: string }>();
+ const { data: proposal, error } = useProposal(guildId, proposalId);
+ const { createTransaction } = useTransactions();
+ const guildContract = useERC20Guild(guildId);
+
+ const { data, loading } = useMemo(() => {
+ const executeProposal = () =>
+ createTransaction('Execute Proposal', async () => {
+ return guildContract.endProposal(proposalId);
+ });
+
+ if (!proposal)
+ return {
+ data: { executeProposal: null },
+ loading: true,
+ error: error,
+ };
+
+ let result = {
+ data: { executeProposal },
+ loading: false,
+ error: error,
+ };
+
+ return result;
+ }, [createTransaction, error, guildContract, proposal, proposalId]);
+
+ return { data, error, loading };
+}
+
+export default useExecutable;
diff --git a/src/hooks/Guilds/ether-swr/guild/useProposalMetadata.ts b/src/hooks/Guilds/useProposalMetadata.ts
similarity index 91%
rename from src/hooks/Guilds/ether-swr/guild/useProposalMetadata.ts
rename to src/hooks/Guilds/useProposalMetadata.ts
index bcf186997..a78934ab3 100644
--- a/src/hooks/Guilds/ether-swr/guild/useProposalMetadata.ts
+++ b/src/hooks/Guilds/useProposalMetadata.ts
@@ -2,7 +2,7 @@ import useIPFSFile from 'hooks/Guilds/ipfs/useIPFSFile';
import { useMemo } from 'react';
import { ProposalMetadata } from 'types/types.guilds';
import contentHash from 'content-hash';
-import { useProposal } from './useProposal';
+import { useProposal } from './ether-swr/guild/useProposal';
function useProposalMetadata(guildId: string, proposalId: string) {
const { data: proposal, error } = useProposal(guildId, proposalId);
diff --git a/src/hooks/Guilds/useProposalState/index.test.ts b/src/hooks/Guilds/useProposalState/index.test.ts
new file mode 100644
index 000000000..a3a68745e
--- /dev/null
+++ b/src/hooks/Guilds/useProposalState/index.test.ts
@@ -0,0 +1,82 @@
+import useProposalState from '.';
+import { Proposal, ContractState } from 'types/types.guilds.d';
+import { BigNumber } from 'ethers';
+import { renderHook } from '@testing-library/react-hooks';
+
+jest.mock('moment', () => {
+ return () =>
+ jest.requireActual('moment')('01.01.2022 11:10', 'DD.MM.YYYY HH:mm');
+});
+
+const proposal: Proposal = {
+ id: '0x0',
+ creator: '0x0',
+ startTime: jest.requireActual('moment')(
+ '01.01.2022 10:10',
+ 'DD.MM.YYYY HH:mm'
+ ),
+ endTime: jest.requireActual('moment')('01.01.2022 12:10', 'DD.MM.YYYY HH:mm'),
+ timeDetail: '',
+ to: ['0x0', '0x0'],
+ data: ['0x0', '0x0'],
+ value: [BigNumber.from(0), BigNumber.from(0)],
+ totalActions: BigNumber.from(0),
+ title: 'Proposal Title',
+ contentHash: '0x0',
+ contractState: ContractState.Active,
+ totalVotes: [BigNumber.from(0)],
+};
+
+describe(`useProposalState`, () => {
+ it(`Should return null if there's no endTime property`, () => {
+ const tempProposal = { ...proposal };
+ tempProposal.endTime = null;
+
+ const { result } = renderHook(() => useProposalState(tempProposal));
+ expect(result.current).toBeNull();
+ });
+
+ it(`Should return 'Active' if the state is 'Active' and the current time is before endTime`, () => {
+ const tempProposal = { ...proposal };
+ tempProposal.contractState = ContractState.Active;
+
+ const { result } = renderHook(() => useProposalState(tempProposal));
+ expect(result.current).toBe('Active');
+ });
+
+ it(`Should return 'Executable' if the state is 'Active' and the current time is after the endTime`, () => {
+ const tempProposal = { ...proposal };
+ tempProposal.contractState = ContractState.Active;
+ tempProposal.endTime = jest.requireActual('moment')(
+ '01.01.2022 11:00',
+ 'DD.MM.YYYY HH:mm'
+ );
+
+ const { result } = renderHook(() => useProposalState(tempProposal));
+ expect(result.current).toBe('Executable');
+ });
+
+ it(`Should return 'Executed' if the state is 'Executed'`, () => {
+ const tempProposal = { ...proposal };
+ tempProposal.contractState = ContractState.Executed;
+
+ const { result } = renderHook(() => useProposalState(tempProposal));
+ expect(result.current).toBe('Executed');
+ });
+
+ it(`Should return 'Rejected' if the state is 'Rejected'`, () => {
+ const tempProposal = { ...proposal };
+ tempProposal.contractState = ContractState.Rejected;
+
+ const { result } = renderHook(() => useProposalState(tempProposal));
+ expect(result.current).toBe('Rejected');
+ });
+
+ it(`Should return 'Failed' if the state is 'Failed'`, () => {
+ const tempProposal = { ...proposal };
+ tempProposal.contractState = ContractState.Failed;
+
+ const { result } = renderHook(() => useProposalState(tempProposal));
+ expect(result.current).toBe('Failed');
+ });
+});
diff --git a/src/hooks/Guilds/useProposalState/index.tsx b/src/hooks/Guilds/useProposalState/index.tsx
new file mode 100644
index 000000000..7341842c9
--- /dev/null
+++ b/src/hooks/Guilds/useProposalState/index.tsx
@@ -0,0 +1,28 @@
+import moment from 'moment';
+import { Proposal, ContractState, ProposalState } from 'types/types.guilds.d';
+
+// Contract state is direct contract storage state but we want to show more accurate up to date data to the user so we process into proposalState
+
+export const useProposalState = (proposal: Proposal): ProposalState => {
+ if (!proposal?.endTime) return null;
+ switch (proposal.contractState) {
+ case ContractState.Active:
+ const currentTime = moment();
+
+ if (currentTime.isSameOrAfter(proposal.endTime)) {
+ return ProposalState.Executable;
+ } else {
+ return ProposalState.Active;
+ }
+ case ContractState.Executed:
+ return ProposalState.Executed;
+ case ContractState.Rejected:
+ return ProposalState.Rejected;
+ case ContractState.Failed:
+ return ProposalState.Failed;
+ default:
+ return null;
+ }
+};
+
+export default useProposalState;
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index 833cdaa13..51db0c813 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -9,6 +9,7 @@
"actions_one": "Action",
"actions_other": "Actions",
"save": "Save",
+ "execute": "Execute",
"core": "Core",
"switch": "Switch",
"wallet": "Wallet",
diff --git a/src/old-components/Guilds/ProposalPage/ProposalDescription/index.tsx b/src/old-components/Guilds/ProposalPage/ProposalDescription/index.tsx
index 84bbb2ded..bdb6a0bc3 100644
--- a/src/old-components/Guilds/ProposalPage/ProposalDescription/index.tsx
+++ b/src/old-components/Guilds/ProposalPage/ProposalDescription/index.tsx
@@ -1,8 +1,8 @@
import { useTypedParams } from 'Modules/Guilds/Hooks/useTypedParams';
-import useProposalMetadata from 'hooks/Guilds/ether-swr/guild/useProposalMetadata';
import Markdown from 'markdown-to-jsx';
import { Loading } from 'Components/Primitives/Loading';
import styled from 'styled-components';
+import useProposalMetadata from 'hooks/Guilds/useProposalMetadata';
const ProposalDescriptionWrapper = styled.div`
margin: 1.5rem 0;
diff --git a/src/old-components/Guilds/ProposalPage/ProposalInfoCard/index.tsx b/src/old-components/Guilds/ProposalPage/ProposalInfoCard/index.tsx
index 5046ff97f..7b2d469ef 100644
--- a/src/old-components/Guilds/ProposalPage/ProposalInfoCard/index.tsx
+++ b/src/old-components/Guilds/ProposalPage/ProposalInfoCard/index.tsx
@@ -74,11 +74,8 @@ const ProposalInfoCard: React.FC = () => {
if (!proposal || !proposal.endTime) return null;
const currentTime = moment();
- if (proposal.endTime.isBefore(currentTime)) {
- return `Ended ${proposal.endTime.fromNow()}`;
- } else {
- return `Ends ${proposal.endTime.toNow()}`;
- }
+ let prefix = proposal.endTime.isBefore(currentTime) ? 'Ended' : 'Ends';
+ return `${prefix} ${proposal.endTime.fromNow()}`;
}, [proposal]);
if (error) return Error
;
diff --git a/src/old-components/Guilds/ProposalPage/ProposalVoteCard/VoteResults.tsx b/src/old-components/Guilds/ProposalPage/ProposalVoteCard/VoteResults.tsx
index 7eb77b1a1..aa26af52a 100644
--- a/src/old-components/Guilds/ProposalPage/ProposalVoteCard/VoteResults.tsx
+++ b/src/old-components/Guilds/ProposalPage/ProposalVoteCard/VoteResults.tsx
@@ -1,11 +1,11 @@
import { useTypedParams } from 'Modules/Guilds/Hooks/useTypedParams';
import { formatUnits } from 'ethers/lib/utils';
-import useProposalMetadata from 'hooks/Guilds/ether-swr/guild/useProposalMetadata';
import { useVotingResults } from 'hooks/Guilds/ether-swr/guild/useVotingResults';
import useVotingPowerPercent from 'hooks/Guilds/guild/useVotingPowerPercent';
import Bullet from 'old-components/Guilds/common/Bullet';
import { Loading } from 'Components/Primitives/Loading';
import styled, { useTheme } from 'styled-components';
+import useProposalMetadata from 'hooks/Guilds/useProposalMetadata';
const VotesRowWrapper = styled.div`
display: flex;
diff --git a/src/old-components/Guilds/ProposalPage/ProposalVoteCard/index.tsx b/src/old-components/Guilds/ProposalPage/ProposalVoteCard/index.tsx
index b7533aae1..4914fc7aa 100644
--- a/src/old-components/Guilds/ProposalPage/ProposalVoteCard/index.tsx
+++ b/src/old-components/Guilds/ProposalPage/ProposalVoteCard/index.tsx
@@ -12,7 +12,6 @@ import { useTransactions } from 'contexts/Guilds';
import { BigNumber } from 'ethers';
import { useERC20Guild } from 'hooks/Guilds/contracts/useContract';
import { useProposal } from 'hooks/Guilds/ether-swr/guild/useProposal';
-import useProposalMetadata from 'hooks/Guilds/ether-swr/guild/useProposalMetadata';
import useSnapshotId from 'hooks/Guilds/ether-swr/guild/useSnapshotId';
import { useVotingPowerOf } from 'hooks/Guilds/ether-swr/guild/useVotingPowerOf';
import { useVotingResults } from 'hooks/Guilds/ether-swr/guild/useVotingResults';
@@ -23,6 +22,7 @@ import { Loading } from 'Components/Primitives/Loading';
import { useState, useMemo } from 'react';
import { toast } from 'react-toastify';
import styled, { css, useTheme } from 'styled-components';
+import useProposalMetadata from 'hooks/Guilds/useProposalMetadata';
const ButtonsContainer = styled.div`
flex-direction: column;
diff --git a/src/pages/Guilds/Proposal.tsx b/src/pages/Guilds/Proposal.tsx
index ebac71415..0c7087b32 100644
--- a/src/pages/Guilds/Proposal.tsx
+++ b/src/pages/Guilds/Proposal.tsx
@@ -14,12 +14,15 @@ import useProposalCalls from 'hooks/Guilds/guild/useProposalCalls';
import { ActionsBuilder } from 'old-components/Guilds/CreateProposalPage';
import { Loading } from 'Components/Primitives/Loading';
import Result, { ResultState } from 'old-components/Guilds/common/Result';
-import React, { useContext, useMemo } from 'react';
+import React, { useContext } from 'react';
import { FaChevronLeft } from 'react-icons/fa';
import { FiArrowLeft } from 'react-icons/fi';
import styled from 'styled-components';
-import moment from 'moment';
-import { ProposalState } from 'Components/Types';
+import ExecuteButton from 'Components/ExecuteButton';
+import { useProposalState } from 'hooks/Guilds/useProposalState';
+import useExecutable from 'hooks/Guilds/useExecutable';
+import { useGuildConfig } from 'hooks/Guilds/ether-swr/guild/useGuildConfig';
+import { ProposalState } from 'types/types.guilds.d';
const PageContainer = styled(Box)`
display: grid;
@@ -85,40 +88,13 @@ const ProposalPage: React.FC = () => {
const { data: proposalIds } = useGuildProposalIds(guildId);
const { data: proposal, error } = useProposal(guildId, proposalId);
const { options } = useProposalCalls(guildId, proposalId);
+ const { data: guildConfig } = useGuildConfig(guildId);
- // TODO These are copied from ProposalCardWrapper and to be replaced
- const timeDetail = useMemo(() => {
- if (!proposal?.endTime) return null;
+ const status = useProposalState(proposal);
- const currentTime = moment();
- if (proposal.endTime?.isBefore(currentTime)) {
- return proposal.endTime.fromNow();
- } else {
- return proposal.endTime.toNow();
- }
- }, [proposal]);
-
- // TODO These are copied from ProposalCardWrapper and to be replaced
- const status = useMemo(() => {
- if (!proposal?.endTime) return null;
- switch (proposal.state) {
- case ProposalState.Active:
- const currentTime = moment();
- if (currentTime.isSameOrAfter(proposal.endTime)) {
- return ProposalState.Failed;
- } else {
- return ProposalState.Active;
- }
- case ProposalState.Executed:
- return ProposalState.Executed;
- case ProposalState.Passed:
- return ProposalState.Passed;
- case ProposalState.Failed:
- return ProposalState.Failed;
- default:
- return proposal.state;
- }
- }, [proposal]);
+ const {
+ data: { executeProposal },
+ } = useExecutable();
if (!isGuildAvailabilityLoading) {
if (!proposalIds?.includes(proposalId)) {
@@ -154,15 +130,19 @@ const ProposalPage: React.FC = () => {
- DXdao
+ {' '}
+ {guildConfig?.name}
+ {status === ProposalState.Executable && (
+
+ )}
{proposal?.title || (
diff --git a/src/types/types.guilds.d.ts b/src/types/types.guilds.d.ts
index f982d1605..8cce96325 100644
--- a/src/types/types.guilds.d.ts
+++ b/src/types/types.guilds.d.ts
@@ -1,28 +1,39 @@
import { Moment } from 'moment';
import {
- BigNumber,
+ BigNumber
} from 'ethers';
export interface Proposal {
id: string;
creator: string;
startTime: Moment;
endTime: Moment;
+ timeDetail: string | null;
to: string[];
data: string[];
value: BigNumber[];
totalActions: BigNumber;
title: string;
contentHash: string;
- state: ProposalState;
+ contractState: ContractState;
totalVotes: BigNumber[];
}
+
export enum ProposalState {
- Active = "Active",
- Passed = "Passed",
- Executed = "Executed",
- Failed = "Failed",
+ Active = 'Active',
+ Executable = 'Executable',
+ Executed = 'Executed',
+ Rejected = 'Rejected',
+ Failed = 'Failed',
+}
+
+export enum ContractState {
+ Active = 'Active',
+ Rejected = 'Rejected',
+ Executed = 'Executed',
+ Failed = 'Failed',
}
+
export interface ProposalMetadata {
description: string;
voteOptions: string[];