mirror of https://github.com/certusone/oyster.git
Governance: Change slots to timestamps (#123)
* feat: use timestamps instead of slots * feat: show amount of deposited tokens
This commit is contained in:
parent
e60ce1b307
commit
7f60b40d7a
|
@ -0,0 +1,47 @@
|
|||
import React from 'react';
|
||||
import { contexts, ParsedAccount } from '@oyster/common';
|
||||
import { TokenOwnerRecord } from '../../models/accounts';
|
||||
import { formatTokenAmount } from '../../tools/text';
|
||||
|
||||
const { useMint } = contexts.Accounts;
|
||||
|
||||
export function RealmDepositBadge({
|
||||
councilTokenOwnerRecord,
|
||||
communityTokenOwnerRecord,
|
||||
}: {
|
||||
councilTokenOwnerRecord: ParsedAccount<TokenOwnerRecord> | undefined;
|
||||
communityTokenOwnerRecord: ParsedAccount<TokenOwnerRecord> | undefined;
|
||||
}) {
|
||||
const communityMint = useMint(
|
||||
communityTokenOwnerRecord?.info.governingTokenMint,
|
||||
);
|
||||
|
||||
const councilMint = useMint(councilTokenOwnerRecord?.info.governingTokenMint);
|
||||
|
||||
if (!councilTokenOwnerRecord && !communityTokenOwnerRecord) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<span>deposited </span>
|
||||
{communityTokenOwnerRecord && (
|
||||
<span>
|
||||
{`tokens: ${formatTokenAmount(
|
||||
communityMint,
|
||||
communityTokenOwnerRecord.info.governingTokenDepositAmount,
|
||||
)}`}
|
||||
</span>
|
||||
)}
|
||||
{communityTokenOwnerRecord && councilTokenOwnerRecord && ', '}
|
||||
{councilTokenOwnerRecord && (
|
||||
<span>
|
||||
{`council tokens: ${formatTokenAmount(
|
||||
councilMint,
|
||||
councilTokenOwnerRecord.info.governingTokenDepositAmount,
|
||||
)}`}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -121,8 +121,8 @@ export const LABELS = {
|
|||
TOKEN_ACCOUNT_ADDRESS: 'token account address',
|
||||
|
||||
MIN_TOKENS_TO_CREATE_PROPOSAL: 'min tokens to create proposal',
|
||||
MIN_INSTRUCTION_HOLD_UP_TIME: 'min instruction hold up time (slots)',
|
||||
MAX_VOTING_TIME: 'max voting time (slots)',
|
||||
MIN_INSTRUCTION_HOLD_UP_TIME_DAYS: 'min instruction hold up time (days)',
|
||||
MAX_VOTING_TIME_DAYS: 'max voting time (days)',
|
||||
|
||||
UPGRADE_AUTHORITY: 'upgrade authority',
|
||||
MINT_AUTHORITY: 'mint authority',
|
||||
|
@ -148,7 +148,7 @@ export const LABELS = {
|
|||
MINIMUM_SLOT_WAITING_PERIOD: 'Minimum slots between proposal and vote',
|
||||
SELECT_CONFIG: 'Select Governed Program',
|
||||
CONFIG: 'Governed Program',
|
||||
GIST_PLACEHOLDER: 'Github Gist link',
|
||||
GIST_PLACEHOLDER: 'Github Gist link (optional)',
|
||||
NAME: 'Name',
|
||||
|
||||
PUBLIC_KEY: 'Public Key',
|
||||
|
@ -158,7 +158,7 @@ export const LABELS = {
|
|||
' Please note that during voting, if you withdraw your tokens, your vote will not count towards the voting total. You must wait for the vote to complete in order for your withdrawal to not affect the voting.',
|
||||
SLOT_MUST_BE_NUMERIC: 'Slot can only be numeric',
|
||||
SLOT_MUST_BE_GREATER_THAN: 'Slot must be greater than or equal to ',
|
||||
HOLD_UP_TIME: 'hold up time',
|
||||
HOLD_UP_TIME_DAYS: 'hold up time (days)',
|
||||
|
||||
MIN_SLOT_MUST_BE_NUMERIC: 'Minimum Slot Waiting Period can only be numeric',
|
||||
TIME_LIMIT_MUST_BE_NUMERIC: 'Time Limit can only be numeric',
|
||||
|
|
|
@ -86,6 +86,15 @@ export function useWalletTokenOwnerRecord(
|
|||
);
|
||||
}
|
||||
|
||||
/// Returns all TokenOwnerRecords for the current wallet
|
||||
export function useWalletTokenOwnerRecords() {
|
||||
const { wallet } = useWallet();
|
||||
|
||||
return useGovernanceAccountsByFilter<TokenOwnerRecord>(TokenOwnerRecord, [
|
||||
pubkeyFilter(1 + 32 + 32, wallet?.publicKey),
|
||||
]);
|
||||
}
|
||||
|
||||
export function useProposalAuthority(proposalOwner: PublicKey | undefined) {
|
||||
const { wallet, connected } = useWallet();
|
||||
const tokenOwnerRecord = useTokenOwnerRecord(proposalOwner);
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
import { ParsedAccount } from '@oyster/common';
|
||||
import { Governance, Proposal } from '../models/accounts';
|
||||
import { useIsBeyondSlot } from './useIsBeyondSlot';
|
||||
import { useIsBeyondTimestamp } from './useIsBeyondTimestamp';
|
||||
|
||||
export const useHasVotingTimeExpired = (
|
||||
governance: ParsedAccount<Governance>,
|
||||
proposal: ParsedAccount<Proposal>,
|
||||
) => {
|
||||
return useIsBeyondSlot(
|
||||
return useIsBeyondTimestamp(
|
||||
proposal.info.votingAt
|
||||
? proposal.info.votingAt.toNumber() +
|
||||
governance.info.config.maxVotingTime.toNumber()
|
||||
? proposal.info.votingAt.toNumber() + governance.info.config.maxVotingTime
|
||||
: undefined,
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
import { useConnection } from '@oyster/common';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const useIsBeyondSlot = (slot: number | undefined) => {
|
||||
const connection = useConnection();
|
||||
const [isBeyondSlot, setIsBeyondSlot] = useState<boolean | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!slot) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sub = (async () => {
|
||||
const currentSlot = await connection.getSlot();
|
||||
if (currentSlot > slot) {
|
||||
setIsBeyondSlot(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsBeyondSlot(false);
|
||||
|
||||
const id = setInterval(() => {
|
||||
connection.getSlot().then(currentSlot => {
|
||||
if (currentSlot > slot) {
|
||||
setIsBeyondSlot(true);
|
||||
clearInterval(id!);
|
||||
}
|
||||
});
|
||||
}, 5000); // TODO: How to estimate the slot distance to avoid uneccesery checks?
|
||||
|
||||
return id;
|
||||
})();
|
||||
|
||||
return () => {
|
||||
sub.then(id => id && clearInterval(id));
|
||||
};
|
||||
}, [connection, slot]);
|
||||
|
||||
return isBeyondSlot;
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
import { useConnection } from '@oyster/common';
|
||||
import moment from 'moment';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const useIsBeyondTimestamp = (timestamp: number | undefined) => {
|
||||
const connection = useConnection();
|
||||
const [isBeyondTimestamp, setIsBeyondTimestamp] = useState<
|
||||
boolean | undefined
|
||||
>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!timestamp) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sub = (async () => {
|
||||
const now = moment().unix();
|
||||
|
||||
if (now > timestamp) {
|
||||
setIsBeyondTimestamp(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsBeyondTimestamp(false);
|
||||
|
||||
const id = setInterval(() => {
|
||||
const now = moment().unix();
|
||||
if (now > timestamp) {
|
||||
setIsBeyondTimestamp(true);
|
||||
clearInterval(id!);
|
||||
}
|
||||
}, 5000); // TODO: Use actual timestamp to calculate the interval
|
||||
|
||||
return id;
|
||||
})();
|
||||
|
||||
return () => {
|
||||
sub.then(id => id && clearInterval(id));
|
||||
};
|
||||
}, [connection, timestamp]);
|
||||
|
||||
return isBeyondTimestamp;
|
||||
};
|
|
@ -83,16 +83,16 @@ export class GovernanceConfig {
|
|||
governedAccount: PublicKey;
|
||||
yesVoteThresholdPercentage: number;
|
||||
minTokensToCreateProposal: number;
|
||||
minInstructionHoldUpTime: BN;
|
||||
maxVotingTime: BN;
|
||||
minInstructionHoldUpTime: number;
|
||||
maxVotingTime: number;
|
||||
|
||||
constructor(args: {
|
||||
realm: PublicKey;
|
||||
governedAccount: PublicKey;
|
||||
yesVoteThresholdPercentage: number;
|
||||
minTokensToCreateProposal: number;
|
||||
minInstructionHoldUpTime: BN;
|
||||
maxVotingTime: BN;
|
||||
minInstructionHoldUpTime: number;
|
||||
maxVotingTime: number;
|
||||
}) {
|
||||
this.realm = args.realm;
|
||||
this.governedAccount = args.governedAccount;
|
||||
|
@ -391,13 +391,13 @@ export class InstructionData {
|
|||
export class ProposalInstruction {
|
||||
accountType = GovernanceAccountType.ProposalInstruction;
|
||||
proposal: PublicKey;
|
||||
holdUpTime: BN;
|
||||
holdUpTime: number;
|
||||
instruction: InstructionData;
|
||||
executedAt: BN | null;
|
||||
|
||||
constructor(args: {
|
||||
proposal: PublicKey;
|
||||
holdUpTime: BN;
|
||||
holdUpTime: number;
|
||||
instruction: InstructionData;
|
||||
executedAt: BN | null;
|
||||
}) {
|
||||
|
|
|
@ -40,12 +40,6 @@ import {
|
|||
} from './accounts';
|
||||
import { serialize } from 'borsh';
|
||||
|
||||
// TODO: Review the limits. Most likely they are leftovers from the legacy version
|
||||
export const MAX_PROPOSAL_DESCRIPTION_LENGTH = 200;
|
||||
export const MAX_PROPOSAL_NAME_LENGTH = 32;
|
||||
export const MAX_REALM_NAME_LENGTH = 32;
|
||||
export const MAX_INSTRUCTION_BASE64_LENGTH = 450;
|
||||
|
||||
// Temp. workaround to support u16.
|
||||
(BinaryReader.prototype as any).readU16 = function () {
|
||||
const reader = (this as unknown) as BinaryReader;
|
||||
|
@ -217,7 +211,7 @@ export const GOVERNANCE_SCHEMA = new Map<any, any>([
|
|||
fields: [
|
||||
['instruction', 'u8'],
|
||||
['index', 'u16'],
|
||||
['holdUpTime', 'u64'],
|
||||
['holdUpTime', 'u32'],
|
||||
['instructionData', InstructionData],
|
||||
],
|
||||
},
|
||||
|
@ -290,8 +284,8 @@ export const GOVERNANCE_SCHEMA = new Map<any, any>([
|
|||
['governedAccount', 'pubkey'],
|
||||
['yesVoteThresholdPercentage', 'u8'],
|
||||
['minTokensToCreateProposal', 'u16'],
|
||||
['minInstructionHoldUpTime', 'u64'],
|
||||
['maxVotingTime', 'u64'],
|
||||
['minInstructionHoldUpTime', 'u32'],
|
||||
['maxVotingTime', 'u32'],
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -381,7 +375,7 @@ export const GOVERNANCE_SCHEMA = new Map<any, any>([
|
|||
fields: [
|
||||
['accountType', 'u8'],
|
||||
['proposal', 'pubkey'],
|
||||
['holdUpTime', 'u64'],
|
||||
['holdUpTime', 'u32'],
|
||||
['instruction', InstructionData],
|
||||
['executedAt', { kind: 'option', type: 'u64' }],
|
||||
],
|
||||
|
|
|
@ -14,7 +14,3 @@ export const formDefaults = {
|
|||
...formVerticalLayout,
|
||||
validateMessages: formValidateMessages,
|
||||
};
|
||||
|
||||
export const formSlotInputStyle = {
|
||||
width: 250,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import { MintInfo } from '@solana/spl-token';
|
||||
import BN from 'bn.js';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
|
||||
export function formatTokenAmount(mint: MintInfo | undefined, amount: BN) {
|
||||
return mint
|
||||
? new BigNumber(amount.toString()).shiftedBy(-mint.decimals).toFormat()
|
||||
: amount.toString();
|
||||
}
|
|
@ -2,10 +2,7 @@ import React, { useState } from 'react';
|
|||
import { ButtonProps, Radio } from 'antd';
|
||||
import { Form, Input } from 'antd';
|
||||
import { PublicKey } from '@solana/web3.js';
|
||||
import {
|
||||
MAX_PROPOSAL_DESCRIPTION_LENGTH,
|
||||
MAX_PROPOSAL_NAME_LENGTH,
|
||||
} from '../../models/serialisation';
|
||||
|
||||
import { LABELS } from '../../constants';
|
||||
import { contexts, ParsedAccount } from '@oyster/common';
|
||||
import { createProposal } from '../../actions/createProposal';
|
||||
|
@ -81,7 +78,7 @@ export function AddNewProposal({
|
|||
governance.info.config.realm,
|
||||
governance.pubkey,
|
||||
values.name,
|
||||
values.descriptionLink,
|
||||
values.descriptionLink ?? '',
|
||||
governingTokenMint,
|
||||
proposalIndex,
|
||||
);
|
||||
|
@ -136,17 +133,14 @@ export function AddNewProposal({
|
|||
label={LABELS.NAME_LABEL}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input maxLength={MAX_PROPOSAL_NAME_LENGTH} />
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="descriptionLink"
|
||||
label={LABELS.DESCRIPTION_LABEL}
|
||||
rules={[{ required: true }]}
|
||||
rules={[{ required: false }]}
|
||||
>
|
||||
<Input
|
||||
maxLength={MAX_PROPOSAL_DESCRIPTION_LENGTH}
|
||||
placeholder={LABELS.GIST_PLACEHOLDER}
|
||||
/>
|
||||
<Input placeholder={LABELS.GIST_PLACEHOLDER} />
|
||||
</Form.Item>
|
||||
</ModalFormAction>
|
||||
);
|
||||
|
|
|
@ -10,15 +10,33 @@ import { RegisterRealm } from './registerRealm';
|
|||
import { LABELS } from '../../constants';
|
||||
|
||||
import { RealmBadge } from '../../components/RealmBadge/realmBadge';
|
||||
import { useWalletTokenOwnerRecords } from '../../hooks/apiHooks';
|
||||
import { RealmDepositBadge } from '../../components/RealmDepositBadge/realmDepositBadge';
|
||||
|
||||
export const HomeView = () => {
|
||||
const history = useHistory();
|
||||
const realms = useRealms();
|
||||
const tokenOwnerRecords = useWalletTokenOwnerRecords();
|
||||
|
||||
const realmItems = useMemo(() => {
|
||||
return realms
|
||||
.sort((r1, r2) => r1.info.name.localeCompare(r2.info.name))
|
||||
.map(r => ({
|
||||
.map(r => {
|
||||
const communityTokenOwnerRecord = tokenOwnerRecords.find(
|
||||
tor =>
|
||||
tor.info.governingTokenMint.toBase58() ===
|
||||
r.info.communityMint.toBase58(),
|
||||
);
|
||||
|
||||
const councilTokenOwnerRecord =
|
||||
r.info.councilMint &&
|
||||
tokenOwnerRecords.find(
|
||||
tor =>
|
||||
tor.info.governingTokenMint.toBase58() ===
|
||||
r.info.councilMint!.toBase58(),
|
||||
);
|
||||
|
||||
return {
|
||||
href: '/realm/' + r.pubkey.toBase58(),
|
||||
title: r.info.name,
|
||||
badge: (
|
||||
|
@ -28,8 +46,15 @@ export const HomeView = () => {
|
|||
></RealmBadge>
|
||||
),
|
||||
key: r.pubkey.toBase58(),
|
||||
}));
|
||||
}, [realms]);
|
||||
description: (
|
||||
<RealmDepositBadge
|
||||
communityTokenOwnerRecord={communityTokenOwnerRecord}
|
||||
councilTokenOwnerRecord={councilTokenOwnerRecord}
|
||||
></RealmDepositBadge>
|
||||
),
|
||||
};
|
||||
});
|
||||
}, [realms, tokenOwnerRecords]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -56,6 +81,7 @@ export const HomeView = () => {
|
|||
<List.Item.Meta
|
||||
avatar={item.badge}
|
||||
title={item.title}
|
||||
description={item.description}
|
||||
></List.Item.Meta>
|
||||
</List.Item>
|
||||
)}
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
|||
import { ButtonProps, Switch } from 'antd';
|
||||
import { Form, Input } from 'antd';
|
||||
import { PublicKey } from '@solana/web3.js';
|
||||
import { MAX_REALM_NAME_LENGTH } from '../../models/serialisation';
|
||||
|
||||
import { LABELS } from '../../constants';
|
||||
import { contexts } from '@oyster/common';
|
||||
import { Redirect } from 'react-router';
|
||||
|
@ -65,7 +65,7 @@ export function RegisterRealm({ buttonProps }: { buttonProps: ButtonProps }) {
|
|||
label={LABELS.NAME_LABEL}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input maxLength={MAX_REALM_NAME_LENGTH} />
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<MintFormItem
|
||||
|
|
|
@ -399,11 +399,12 @@ function InnerProposalView({
|
|||
<Row>
|
||||
<Col span={24}>
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
defaultActiveKey="description"
|
||||
size="large"
|
||||
style={{ marginBottom: 32 }}
|
||||
>
|
||||
<TabPane tab="Description" key="1">
|
||||
{proposal.info.descriptionLink && (
|
||||
<TabPane tab="Description" key="description">
|
||||
{loading ? (
|
||||
<Spin />
|
||||
) : isUrl ? (
|
||||
|
@ -425,7 +426,8 @@ function InnerProposalView({
|
|||
content
|
||||
)}
|
||||
</TabPane>
|
||||
<TabPane tab={LABELS.INSTRUCTIONS} key="2">
|
||||
)}
|
||||
<TabPane tab={LABELS.INSTRUCTIONS} key="instructions">
|
||||
<Row
|
||||
gutter={[
|
||||
{ xs: 8, sm: 16, md: 24, lg: 32 },
|
||||
|
|
|
@ -76,7 +76,7 @@ export function InstructionCard({
|
|||
<>
|
||||
<p>{`${LABELS.INSTRUCTION}: ${instructionDetails.dataBase64}`}</p>
|
||||
<p>
|
||||
{LABELS.HOLD_UP_TIME}: {instruction.info.holdUpTime.toNumber()}
|
||||
{LABELS.HOLD_UP_TIME_DAYS}: {instruction.info.holdUpTime}
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
|
|
|
@ -17,10 +17,7 @@ import { useState } from 'react';
|
|||
import { AccountFormItem } from '../../../components/AccountFormItem/accountFormItem';
|
||||
import { Governance } from '../../../models/accounts';
|
||||
import { createUpgradeInstruction } from '../../../models/sdkInstructions';
|
||||
import {
|
||||
MAX_INSTRUCTION_BASE64_LENGTH,
|
||||
serializeInstructionToBase64,
|
||||
} from '../../../models/serialisation';
|
||||
import { serializeInstructionToBase64 } from '../../../models/serialisation';
|
||||
import { formDefaults, formVerticalLayout } from '../../../tools/forms';
|
||||
|
||||
export default function InstructionInput({
|
||||
|
@ -56,7 +53,6 @@ export default function InstructionInput({
|
|||
<Input.TextArea
|
||||
value={instruction}
|
||||
onChange={e => updateInstruction(e.target.value)}
|
||||
maxLength={MAX_INSTRUCTION_BASE64_LENGTH}
|
||||
placeholder={`base64 encoded serialized Solana Instruction`}
|
||||
/>
|
||||
</Col>
|
||||
|
|
|
@ -68,18 +68,17 @@ export function NewInstructionCard({
|
|||
name="control-hooks"
|
||||
onFinish={onFinish}
|
||||
initialValues={{
|
||||
holdUpTime:
|
||||
governance.info.config.minInstructionHoldUpTime.toNumber(),
|
||||
holdUpTime: governance.info.config.minInstructionHoldUpTime,
|
||||
}}
|
||||
>
|
||||
<Form.Item
|
||||
name="holdUpTime"
|
||||
label={LABELS.HOLD_UP_TIME}
|
||||
label={LABELS.HOLD_UP_TIME_DAYS}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<InputNumber
|
||||
maxLength={64}
|
||||
min={governance.info.config.minInstructionHoldUpTime.toNumber()}
|
||||
min={governance.info.config.minInstructionHoldUpTime}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import { Col, List, Row } from 'antd';
|
||||
import { Col, List, Row, Typography } from 'antd';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useRealm } from '../../contexts/GovernanceContext';
|
||||
|
||||
import { useGovernancesByRealm } from '../../hooks/apiHooks';
|
||||
import {
|
||||
useGovernancesByRealm,
|
||||
useWalletTokenOwnerRecord,
|
||||
} from '../../hooks/apiHooks';
|
||||
import './style.less'; // Don't remove this line, it will break dark mode if you do due to weird transpiling conditions
|
||||
|
||||
import { Background } from '../../components/Background';
|
||||
|
@ -16,6 +19,9 @@ import { WithdrawGoverningTokens } from './WithdrawGoverningTokens';
|
|||
import { RealmBadge } from '../../components/RealmBadge/realmBadge';
|
||||
import { GovernanceBadge } from '../../components/GovernanceBadge/governanceBadge';
|
||||
import AccountDescription from './accountDescription';
|
||||
import { RealmDepositBadge } from '../../components/RealmDepositBadge/realmDepositBadge';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
export const RealmView = () => {
|
||||
const history = useHistory();
|
||||
|
@ -24,6 +30,16 @@ export const RealmView = () => {
|
|||
const realm = useRealm(realmKey);
|
||||
const governances = useGovernancesByRealm(realmKey);
|
||||
|
||||
const communityTokenOwnerRecord = useWalletTokenOwnerRecord(
|
||||
realm?.pubkey,
|
||||
realm?.info.communityMint,
|
||||
);
|
||||
|
||||
const councilTokenOwnerRecord = useWalletTokenOwnerRecord(
|
||||
realm?.pubkey,
|
||||
realm?.info.councilMint,
|
||||
);
|
||||
|
||||
const governanceItems = useMemo(() => {
|
||||
return governances
|
||||
.sort((g1, g2) =>
|
||||
|
@ -54,8 +70,14 @@ export const RealmView = () => {
|
|||
councilMint={realm?.info.councilMint}
|
||||
></RealmBadge>
|
||||
|
||||
<Col>
|
||||
<Col style={{ textAlign: 'left', marginLeft: 8 }}>
|
||||
<h1>{realm?.info.name}</h1>
|
||||
<Text type="secondary">
|
||||
<RealmDepositBadge
|
||||
communityTokenOwnerRecord={communityTokenOwnerRecord}
|
||||
councilTokenOwnerRecord={councilTokenOwnerRecord}
|
||||
></RealmDepositBadge>
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
|
|
|
@ -10,11 +10,10 @@ import { Redirect } from 'react-router';
|
|||
import { GovernanceType } from '../../models/enums';
|
||||
import { registerGovernance } from '../../actions/registerGovernance';
|
||||
import { GovernanceConfig } from '../../models/accounts';
|
||||
import BN from 'bn.js';
|
||||
|
||||
import { useKeyParam } from '../../hooks/useKeyParam';
|
||||
import { ModalFormAction } from '../../components/ModalFormAction/modalFormAction';
|
||||
import { formSlotInputStyle } from '../../tools/forms';
|
||||
|
||||
import { AccountFormItem } from '../../components/AccountFormItem/accountFormItem';
|
||||
|
||||
const { useWallet } = contexts.Wallet;
|
||||
|
@ -45,8 +44,8 @@ export function RegisterGovernance({
|
|||
governedAccount: new PublicKey(values.governedAccountAddress),
|
||||
yesVoteThresholdPercentage: values.yesVoteThresholdPercentage,
|
||||
minTokensToCreateProposal: values.minTokensToCreateProposal,
|
||||
minInstructionHoldUpTime: new BN(values.minInstructionHoldUpTime),
|
||||
maxVotingTime: new BN(values.maxVotingTime),
|
||||
minInstructionHoldUpTime: values.minInstructionHoldUpTime * 86400,
|
||||
maxVotingTime: values.maxVotingTime * 86400,
|
||||
});
|
||||
return await registerGovernance(
|
||||
connection,
|
||||
|
@ -137,20 +136,20 @@ export function RegisterGovernance({
|
|||
|
||||
<Form.Item
|
||||
name="minInstructionHoldUpTime"
|
||||
label={LABELS.MIN_INSTRUCTION_HOLD_UP_TIME}
|
||||
label={LABELS.MIN_INSTRUCTION_HOLD_UP_TIME_DAYS}
|
||||
rules={[{ required: true }]}
|
||||
initialValue={1}
|
||||
>
|
||||
<InputNumber min={1} style={formSlotInputStyle} />
|
||||
<InputNumber min={0} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="maxVotingTime"
|
||||
label={LABELS.MAX_VOTING_TIME}
|
||||
label={LABELS.MAX_VOTING_TIME_DAYS}
|
||||
rules={[{ required: true }]}
|
||||
initialValue={1000000}
|
||||
initialValue={3}
|
||||
>
|
||||
<InputNumber min={1} style={formSlotInputStyle} />
|
||||
<InputNumber min={1} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="yesVoteThresholdPercentage"
|
||||
|
|
Loading…
Reference in New Issue