mirror of https://github.com/certusone/oyster.git
Fix some counting bugs, add functionality for defeated and executed states
This commit is contained in:
parent
9c580bccd7
commit
0227b5f655
|
@ -74,9 +74,9 @@ export const PROGRAM_IDS = [
|
|||
name: 'testnet',
|
||||
timelock: () => ({
|
||||
programAccountId: new PublicKey(
|
||||
'32siiZ12jH2i7BM2wtNuTDw2Hs5nBjVQuBh4P8cTSH3i',
|
||||
'7CxEuz8Qtius9aCyJqGnWZyBNvf6WTTNmA8G26BdMTSF',
|
||||
),
|
||||
programId: new PublicKey('5KrVJvesyjdMy6Vq5wfuPSMdw7vWuUvtbHG98wBsEkX6'),
|
||||
programId: new PublicKey('8DevpkpN6CsdczP6rQ64CHraApXFrq96oGm4VjSNCs4q'),
|
||||
}),
|
||||
wormhole: () => ({
|
||||
pubkey: new PublicKey('5gQf5AUhAgWYgUCt9ouShm9H7dzzXUsLdssYwe5krKhg'),
|
||||
|
@ -95,9 +95,9 @@ export const PROGRAM_IDS = [
|
|||
name: 'devnet',
|
||||
timelock: () => ({
|
||||
programAccountId: new PublicKey(
|
||||
'Gc6ktQPgHDxf9GpN6CdLEnkkqj5NfGYJeLDWFLoN3wNb',
|
||||
'8KkpkoDAQaQqjnkCtNXAyk2A8GLmsmWPjBLK7jmahhxZ',
|
||||
),
|
||||
programId: new PublicKey('FmxAXMEKaj7BvgH9zdRNMZZYdAk4mBeRdSQwUoM3QYYw'),
|
||||
programId: new PublicKey('7SH5hE7uBecnfMpGjdPyJupgBhFHaXcNMCEgJbmoVV7t'),
|
||||
}),
|
||||
wormhole: () => ({
|
||||
pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'),
|
||||
|
|
|
@ -89,6 +89,7 @@ export const addCustomSingleSignerTransaction = async (
|
|||
proposal.pubkey,
|
||||
sigAccount,
|
||||
proposal.info.signatoryValidation,
|
||||
proposal.info.config,
|
||||
transferAuthority.publicKey,
|
||||
authority,
|
||||
slot,
|
||||
|
|
|
@ -111,6 +111,7 @@ export const registerProgramGovernance = async (
|
|||
TimelockType.CustomSingleSignerV1,
|
||||
uninitializedTimelockConfig.votingEntryRule || VotingEntryRule.Anytime,
|
||||
uninitializedTimelockConfig.minimumSlotWaitingPeriod || new BN(0),
|
||||
uninitializedTimelockConfig.timeLimit || new BN(0),
|
||||
uninitializedTimelockConfig.name || '',
|
||||
),
|
||||
);
|
||||
|
|
|
@ -11,6 +11,7 @@ import { Card, Spin } from 'antd';
|
|||
import Meta from 'antd/lib/card/Meta';
|
||||
import React, { useState } from 'react';
|
||||
import { execute } from '../../actions/execute';
|
||||
import { LABELS } from '../../constants';
|
||||
import {
|
||||
TimelockSet,
|
||||
TimelockStateStatus,
|
||||
|
@ -47,7 +48,9 @@ export function InstructionCard({
|
|||
description={
|
||||
<>
|
||||
<p>Instruction: TODO</p>
|
||||
<p>Slot: {instruction.info.slot.toNumber()}</p>
|
||||
<p>
|
||||
{LABELS.DELAY}: {instruction.info.slot.toNumber()}
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
@ -108,7 +111,8 @@ function PlayStatusButton({
|
|||
};
|
||||
|
||||
if (proposal.info.state.status != TimelockStateStatus.Executing) return null;
|
||||
if (currSlot < instruction.info.slot.toNumber()) return null;
|
||||
const elapsedTime = currSlot - proposal.info.state.votingEndedAt.toNumber();
|
||||
if (elapsedTime < instruction.info.slot.toNumber()) return null;
|
||||
|
||||
if (playing === Playstate.Unplayed)
|
||||
return (
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Card, Progress, Spin } from 'antd';
|
||||
import { Form, Input } from 'antd';
|
||||
import { INSTRUCTION_LIMIT, TimelockSet } from '../../models/timelock';
|
||||
import {
|
||||
INSTRUCTION_LIMIT,
|
||||
TimelockConfig,
|
||||
TimelockSet,
|
||||
} from '../../models/timelock';
|
||||
import { contexts, ParsedAccount, hooks, utils } from '@oyster/common';
|
||||
import { addCustomSingleSignerTransaction } from '../../actions/addCustomSingleSignerTransaction';
|
||||
import { SaveOutlined } from '@ant-design/icons';
|
||||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import { LABELS } from '../../constants';
|
||||
|
||||
const { useWallet } = contexts.Wallet;
|
||||
const { useConnection } = contexts.Connection;
|
||||
|
@ -25,8 +30,10 @@ enum UploadType {
|
|||
export function NewInstructionCard({
|
||||
proposal,
|
||||
position,
|
||||
config,
|
||||
}: {
|
||||
proposal: ParsedAccount<TimelockSet>;
|
||||
config: ParsedAccount<TimelockConfig>;
|
||||
position: number;
|
||||
}) {
|
||||
const [form] = Form.useForm();
|
||||
|
@ -41,7 +48,19 @@ export function NewInstructionCard({
|
|||
}) => {
|
||||
if (!values.slot.match(/^\d*$/)) {
|
||||
notify({
|
||||
message: 'Slot can only be numeric',
|
||||
message: LABELS.SLOT_MUST_BE_NUMERIC,
|
||||
type: 'error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
parseInt(values.slot) < config.info.minimumSlotWaitingPeriod.toNumber()
|
||||
) {
|
||||
notify({
|
||||
message:
|
||||
LABELS.SLOT_MUST_BE_GREATER_THAN +
|
||||
config.info.minimumSlotWaitingPeriod.toString(),
|
||||
type: 'error',
|
||||
});
|
||||
return;
|
||||
|
@ -69,7 +88,11 @@ export function NewInstructionCard({
|
|||
actions={[<SaveOutlined key="save" onClick={form.submit} />]}
|
||||
>
|
||||
<Form {...layout} form={form} name="control-hooks" onFinish={onFinish}>
|
||||
<Form.Item name="slot" label="Slot" rules={[{ required: true }]}>
|
||||
<Form.Item
|
||||
name="slot"
|
||||
label={LABELS.DELAY}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input maxLength={64} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
|
|
|
@ -92,4 +92,10 @@ export const LABELS = {
|
|||
LEAVE_BLANK_IF_YOU_WANT_ONE: 'Leave blank if you want one made for you',
|
||||
ADDITIONAL_VOTING_MSG:
|
||||
' Please note that during voting, you cannot withdraw tokens you have used to vote. You must wait for the vote to complete.',
|
||||
SLOT_MUST_BE_NUMERIC: 'Slot can only be numeric',
|
||||
SLOT_MUST_BE_GREATER_THAN: 'Slot must be greater than or equal to ',
|
||||
DELAY: 'Slot Delay',
|
||||
MIN_SLOT_MUST_BE_NUMERIC: 'Minimum Slot Waiting Period can only be numeric',
|
||||
TIME_LIMIT_MUST_BE_NUMERIC: 'Time Limit can only be numeric',
|
||||
TIME_LIMIT: 'Voting Time Limit',
|
||||
};
|
||||
|
|
|
@ -19,14 +19,17 @@ import BN from 'bn.js';
|
|||
/// 1. `[writable]` Timelock set account.
|
||||
/// 2. `[writable]` Signatory account
|
||||
/// 3. `[writable]` Signatory validation account.
|
||||
/// 4. `[]` Transfer authority
|
||||
/// 5. `[]` Timelock program account.
|
||||
/// 6. `[]` Token program account.
|
||||
/// 4. `[]` Timelock Config account.
|
||||
/// 5. `[]` Transfer authority
|
||||
/// 6. `[]` Timelock mint authority
|
||||
/// 7. `[]` Timelock program account.
|
||||
/// 8. `[]` Token program account.
|
||||
export const addCustomSingleSignerTransactionInstruction = (
|
||||
timelockTransactionAccount: PublicKey,
|
||||
timelockSetAccount: PublicKey,
|
||||
signatoryAccount: PublicKey,
|
||||
signatoryValidationAccount: PublicKey,
|
||||
timelockConfigAccount: PublicKey,
|
||||
transferAuthority: PublicKey,
|
||||
authority: PublicKey,
|
||||
slot: string,
|
||||
|
@ -85,6 +88,7 @@ export const addCustomSingleSignerTransactionInstruction = (
|
|||
{ pubkey: timelockSetAccount, isSigner: false, isWritable: true },
|
||||
{ pubkey: signatoryAccount, isSigner: false, isWritable: true },
|
||||
{ pubkey: signatoryValidationAccount, isSigner: false, isWritable: true },
|
||||
{ pubkey: timelockConfigAccount, isSigner: false, isWritable: false },
|
||||
{ pubkey: transferAuthority, isSigner: true, isWritable: false },
|
||||
{ pubkey: authority, isSigner: false, isWritable: false },
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ export const initTimelockConfigInstruction = (
|
|||
timelockType: number,
|
||||
votingEntryRule: number,
|
||||
minimumSlotWaitingPeriod: BN,
|
||||
timeLimit: BN,
|
||||
name: string,
|
||||
): TransactionInstruction => {
|
||||
const PROGRAM_IDS = utils.programIds();
|
||||
|
@ -39,6 +40,7 @@ export const initTimelockConfigInstruction = (
|
|||
BufferLayout.u8('timelockType'),
|
||||
BufferLayout.u8('votingEntryRule'),
|
||||
Layout.uint64('minimumSlotWaitingPeriod'),
|
||||
Layout.uint64('timeLimit'),
|
||||
BufferLayout.seq(BufferLayout.u8(), CONFIG_NAME_LENGTH, 'name'),
|
||||
]);
|
||||
|
||||
|
@ -57,6 +59,7 @@ export const initTimelockConfigInstruction = (
|
|||
timelockType,
|
||||
votingEntryRule,
|
||||
minimumSlotWaitingPeriod,
|
||||
timeLimit,
|
||||
name: nameAsBytes,
|
||||
},
|
||||
data,
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import { PublicKey, TransactionInstruction } from '@solana/web3.js';
|
||||
import {
|
||||
PublicKey,
|
||||
SYSVAR_CLOCK_PUBKEY,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js';
|
||||
import { utils } from '@oyster/common';
|
||||
import * as BufferLayout from 'buffer-layout';
|
||||
import { TimelockInstruction } from './timelock';
|
||||
|
@ -14,6 +18,7 @@ import { TimelockInstruction } from './timelock';
|
|||
/// 4. `[]` Timelock mint authority
|
||||
/// 5. `[]` Timelock program account pub key.
|
||||
/// 6. `[]` Token program account.
|
||||
/// 7. `[]` Clock sysvar.
|
||||
export const signInstruction = (
|
||||
timelockSetAccount: PublicKey,
|
||||
signatoryAccount: PublicKey,
|
||||
|
@ -46,6 +51,7 @@ export const signInstruction = (
|
|||
isWritable: false,
|
||||
},
|
||||
{ pubkey: PROGRAM_IDS.token, isSigner: false, isWritable: false },
|
||||
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
|
||||
];
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
|
|
|
@ -8,7 +8,7 @@ export const DESC_SIZE = 200;
|
|||
export const NAME_SIZE = 32;
|
||||
export const CONFIG_NAME_LENGTH = 32;
|
||||
export const INSTRUCTION_LIMIT = 450;
|
||||
export const TRANSACTION_SLOTS = 5;
|
||||
export const TRANSACTION_SLOTS = 4;
|
||||
export const TEMP_FILE_TXN_SIZE = 1000;
|
||||
|
||||
export enum TimelockInstruction {
|
||||
|
@ -43,6 +43,8 @@ export interface TimelockConfig {
|
|||
governanceMint: PublicKey;
|
||||
/// Program ID that is tied to this config (optional)
|
||||
program: PublicKey;
|
||||
/// Time limit in slots for proposal to be open to voting
|
||||
timeLimit: BN;
|
||||
/// Optional name
|
||||
name: string;
|
||||
}
|
||||
|
@ -57,6 +59,7 @@ export const TimelockConfigLayout: typeof BufferLayout.Structure = BufferLayout.
|
|||
Layout.uint64('minimumSlotWaitingPeriod'),
|
||||
Layout.publicKey('governanceMint'),
|
||||
Layout.publicKey('program'),
|
||||
Layout.uint64('timeLimit'),
|
||||
BufferLayout.seq(BufferLayout.u8(), CONFIG_NAME_LENGTH, 'name'),
|
||||
],
|
||||
);
|
||||
|
@ -95,6 +98,9 @@ export enum TimelockStateStatus {
|
|||
|
||||
/// Deleted
|
||||
Deleted = 4,
|
||||
|
||||
/// Defeated
|
||||
Defeated = 5,
|
||||
}
|
||||
|
||||
export const STATE_COLOR: Record<string, string> = {
|
||||
|
@ -103,6 +109,7 @@ export const STATE_COLOR: Record<string, string> = {
|
|||
[TimelockStateStatus.Executing]: 'green',
|
||||
[TimelockStateStatus.Completed]: 'purple',
|
||||
[TimelockStateStatus.Deleted]: 'gray',
|
||||
[TimelockStateStatus.Defeated]: 'red',
|
||||
};
|
||||
|
||||
export interface TimelockState {
|
||||
|
@ -111,6 +118,10 @@ export interface TimelockState {
|
|||
timelockTransactions: PublicKey[];
|
||||
name: string;
|
||||
descLink: string;
|
||||
votingEndedAt: BN;
|
||||
votingBeganAt: BN;
|
||||
executions: number;
|
||||
usedTxnSlots: number;
|
||||
}
|
||||
|
||||
const timelockTxns = [];
|
||||
|
@ -137,6 +148,10 @@ export const TimelockSetLayout: typeof BufferLayout.Structure = BufferLayout.str
|
|||
Layout.uint64('totalSigningTokensMinted'),
|
||||
BufferLayout.seq(BufferLayout.u8(), DESC_SIZE, 'descLink'),
|
||||
BufferLayout.seq(BufferLayout.u8(), NAME_SIZE, 'name'),
|
||||
Layout.uint64('votingEndedAt'),
|
||||
Layout.uint64('votingBeganAt'),
|
||||
BufferLayout.u8('executions'),
|
||||
BufferLayout.u8('usedTxnSlots'),
|
||||
...timelockTxns,
|
||||
],
|
||||
);
|
||||
|
@ -248,6 +263,10 @@ export const TimelockSetParser = (
|
|||
descLink: utils.fromUTF8Array(data.descLink).replaceAll('\u0000', ''),
|
||||
name: utils.fromUTF8Array(data.name).replaceAll('\u0000', ''),
|
||||
timelockTransactions: timelockTxns,
|
||||
votingEndedAt: data.votingEndedAt,
|
||||
votingBeganAt: data.votingBeganAt,
|
||||
executions: data.executions,
|
||||
usedTxnSlots: data.usedTxnSlots,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -298,9 +317,10 @@ export const TimelockConfigParser = (
|
|||
executionType: data.executionType,
|
||||
timelockType: data.timelockType,
|
||||
votingEntryRule: data.votingEntryRule,
|
||||
minimimSlotWaitingPeriod: data.minimimSlotWaitingPeriod,
|
||||
minimumSlotWaitingPeriod: data.minimumSlotWaitingPeriod,
|
||||
governanceMint: data.governanceMint,
|
||||
program: data.program,
|
||||
timeLimit: data.timeLimit,
|
||||
name: utils.fromUTF8Array(data.name).replaceAll('\u0000', ''),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import { PublicKey, TransactionInstruction } from '@solana/web3.js';
|
||||
import {
|
||||
PublicKey,
|
||||
SYSVAR_CLOCK_PUBKEY,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js';
|
||||
import { utils } from '@oyster/common';
|
||||
import * as Layout from '../utils/layout';
|
||||
|
||||
|
@ -23,6 +27,7 @@ import BN from 'bn.js';
|
|||
/// 10. `[]` Timelock program mint authority
|
||||
/// 11. `[]` Timelock program account pub key.
|
||||
/// 12. `[]` Token program account.
|
||||
/// 13. `[]` Clock sysvar.
|
||||
export const voteInstruction = (
|
||||
timelockSetAccount: PublicKey,
|
||||
votingAccount: PublicKey,
|
||||
|
@ -75,6 +80,7 @@ export const voteInstruction = (
|
|||
isWritable: false,
|
||||
},
|
||||
{ pubkey: PROGRAM_IDS.token, isSigner: false, isWritable: false },
|
||||
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
|
||||
];
|
||||
|
||||
return new TransactionInstruction({
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
import { PublicKey } from '@solana/web3.js';
|
||||
import { Table } from 'antd';
|
||||
import MintGovernanceTokens from '../../components/Proposal/MintGovernanceTokens';
|
||||
import BN from 'bn.js';
|
||||
const { useUserAccounts } = hooks;
|
||||
const columns = [
|
||||
{
|
||||
|
@ -47,14 +48,21 @@ const columns = [
|
|||
},
|
||||
{
|
||||
title: LABELS.VOTING_ENTRY_RULES,
|
||||
dataIndex: 'votingEntryRules',
|
||||
key: 'votingEntryRules',
|
||||
dataIndex: 'votingEntryRule',
|
||||
key: 'votingEntryRule',
|
||||
render: (number: number) => <span>{VotingEntryRule[number]}</span>,
|
||||
},
|
||||
{
|
||||
title: LABELS.MINIMUM_SLOT_WAITING_PERIOD,
|
||||
dataIndex: 'minimumSlotWaitingPeriod',
|
||||
key: 'minimumSlotWaitingPeriod',
|
||||
render: (number: BN) => <span>{number.toNumber()}</span>,
|
||||
},
|
||||
{
|
||||
title: LABELS.TIME_LIMIT,
|
||||
dataIndex: 'timeLimit',
|
||||
key: 'timeLimit',
|
||||
render: (number: BN) => <span>{number.toNumber()}</span>,
|
||||
},
|
||||
{
|
||||
title: LABELS.GOVERNANCE_MINT,
|
||||
|
|
|
@ -79,18 +79,25 @@ export function NewForm({
|
|||
consensusAlgorithm: ConsensusAlgorithm;
|
||||
votingEntryRule: VotingEntryRule;
|
||||
minimumSlotWaitingPeriod: string;
|
||||
timeLimit: string;
|
||||
governanceMint: string;
|
||||
program: string;
|
||||
name: string;
|
||||
}) => {
|
||||
if (!values.minimumSlotWaitingPeriod.match(/^\d*$/)) {
|
||||
notify({
|
||||
message: 'Minimum Slot Waiting Period can only be numeric',
|
||||
message: LABELS.MIN_SLOT_MUST_BE_NUMERIC,
|
||||
type: 'error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!values.timeLimit.match(/^\d*$/)) {
|
||||
notify({
|
||||
message: LABELS.TIME_LIMIT_MUST_BE_NUMERIC,
|
||||
type: 'error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const uninitializedConfig = {
|
||||
timelockType: values.timelockType,
|
||||
executionType: values.executionType,
|
||||
|
@ -102,6 +109,7 @@ export function NewForm({
|
|||
: undefined,
|
||||
program: new PublicKey(values.program),
|
||||
name: values.name,
|
||||
timeLimit: new BN(values.timeLimit),
|
||||
};
|
||||
|
||||
const newConfig = await registerProgramGovernance(
|
||||
|
@ -143,6 +151,13 @@ export function NewForm({
|
|||
>
|
||||
<Input maxLength={64} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="timeLimit"
|
||||
label={LABELS.TIME_LIMIT}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input maxLength={64} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="consensusAlgorithm"
|
||||
label={LABELS.CONSENSUS_ALGORITHM}
|
||||
|
|
|
@ -257,6 +257,7 @@ function InnerProposalView({
|
|||
<Col xs={24} sm={24} md={12} lg={8}>
|
||||
<NewInstructionCard
|
||||
proposal={proposal}
|
||||
config={timelockConfig}
|
||||
position={instructionsForProposal.length}
|
||||
/>
|
||||
</Col>
|
||||
|
|
Loading…
Reference in New Issue