* Feat/804: Routing and basic page setup * Feat/804: Type definition for proposals - awaiting asset docs/changes * Feat/804: New proposals lib * Feat/804: Propose form and page * Feat/804: Removing dud copied unit tests for now * Feat/804: Added types for new asset proposal * feat: handle new error types returned from wallet for proposals * chore: rename lib to governance * feat: move usage of hook into form component * feat: some adjustments and test coverage * chore: tidy up, remove tailwind config Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
parent
4c7ff15f23
commit
c40d71e1ed
@ -6,9 +6,9 @@ import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
|||||||
import { InputError } from '@vegaprotocol/ui-toolkit';
|
import { InputError } from '@vegaprotocol/ui-toolkit';
|
||||||
import {
|
import {
|
||||||
DealTicketAmount,
|
DealTicketAmount,
|
||||||
getDialogTitle,
|
getOrderDialogTitle,
|
||||||
getDialogIntent,
|
getOrderDialogIntent,
|
||||||
getDialogIcon,
|
getOrderDialogIcon,
|
||||||
MarketSelector,
|
MarketSelector,
|
||||||
} from '@vegaprotocol/deal-ticket';
|
} from '@vegaprotocol/deal-ticket';
|
||||||
import type { Order } from '@vegaprotocol/orders';
|
import type { Order } from '@vegaprotocol/orders';
|
||||||
@ -143,9 +143,9 @@ export const DealTicketSteps = ({
|
|||||||
partyData={partyData}
|
partyData={partyData}
|
||||||
/>
|
/>
|
||||||
<TransactionDialog
|
<TransactionDialog
|
||||||
title={getDialogTitle(finalizedOrder?.status)}
|
title={getOrderDialogTitle(finalizedOrder?.status)}
|
||||||
intent={getDialogIntent(finalizedOrder?.status)}
|
intent={getOrderDialogIntent(finalizedOrder?.status)}
|
||||||
icon={getDialogIcon(finalizedOrder?.status)}
|
icon={getOrderDialogIcon(finalizedOrder?.status)}
|
||||||
>
|
>
|
||||||
<OrderFeedback transaction={transaction} order={finalizedOrder} />
|
<OrderFeedback transaction={transaction} order={finalizedOrder} />
|
||||||
</TransactionDialog>
|
</TransactionDialog>
|
||||||
|
@ -157,6 +157,9 @@
|
|||||||
"Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.": "Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.",
|
"Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.": "Once unlocked they can be redeemed from the contract so that you can transfer them between wallets.",
|
||||||
"Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.": "Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.",
|
"Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.": "Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.",
|
||||||
"proposals": "Proposals",
|
"proposals": "Proposals",
|
||||||
|
"proposal": "Proposal",
|
||||||
|
"submitting": "Submitting",
|
||||||
|
"submit": "Submit",
|
||||||
"proposedEnactment": "Proposed enactment",
|
"proposedEnactment": "Proposed enactment",
|
||||||
"Enacted": "Enacted",
|
"Enacted": "Enacted",
|
||||||
"enactedOn": "Enacted on",
|
"enactedOn": "Enacted on",
|
||||||
@ -620,5 +623,7 @@
|
|||||||
"InvalidAssetDetails": "Invalid asset details",
|
"InvalidAssetDetails": "Invalid asset details",
|
||||||
"FilterProposals": "Filter proposals",
|
"FilterProposals": "Filter proposals",
|
||||||
"FilterProposalsDescription": "Filter by proposal ID or proposer ID",
|
"FilterProposalsDescription": "Filter by proposal ID or proposer ID",
|
||||||
"Freeform proposal": "Freeform proposal"
|
"Freeform proposal": "Freeform proposal",
|
||||||
|
"NewProposal": "New proposal",
|
||||||
|
"MinProposalRequirements": "You must have at least 1 VEGA to make a proposal"
|
||||||
}
|
}
|
||||||
|
1
apps/token/src/routes/governance/propose/index.tsx
Normal file
1
apps/token/src/routes/governance/propose/index.tsx
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { Propose } from './propose';
|
21
apps/token/src/routes/governance/propose/propose.tsx
Normal file
21
apps/token/src/routes/governance/propose/propose.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { ProposalForm } from '@vegaprotocol/governance';
|
||||||
|
import { Heading } from '../../../components/heading';
|
||||||
|
import { VegaWalletContainer } from '../../../components/vega-wallet-container';
|
||||||
|
|
||||||
|
export const Propose = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Heading title={t('NewProposal')} />
|
||||||
|
<VegaWalletContainer>
|
||||||
|
{() => (
|
||||||
|
<>
|
||||||
|
<p>{t('MinProposalRequirements')}</p>
|
||||||
|
<ProposalForm />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</VegaWalletContainer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ProposalContainer } from './governance/proposal';
|
import { ProposalContainer } from './governance/proposal';
|
||||||
import { ProposalsContainer } from './governance/proposals';
|
import { ProposalsContainer } from './governance/proposals';
|
||||||
|
import { Propose } from './governance/propose';
|
||||||
|
|
||||||
import Home from './home';
|
import Home from './home';
|
||||||
import NotFound from './not-found';
|
import NotFound from './not-found';
|
||||||
@ -165,6 +166,7 @@ const routerConfig = [
|
|||||||
component: LazyGovernance,
|
component: LazyGovernance,
|
||||||
children: [
|
children: [
|
||||||
{ path: ':proposalId', element: <ProposalContainer /> },
|
{ path: ':proposalId', element: <ProposalContainer /> },
|
||||||
|
{ path: 'propose', element: <Propose /> },
|
||||||
{ index: true, element: <ProposalsContainer /> },
|
{ index: true, element: <ProposalsContainer /> },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -34,9 +34,9 @@ export const DealTicketManager = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<TransactionDialog
|
<TransactionDialog
|
||||||
title={getDialogTitle(finalizedOrder?.status)}
|
title={getOrderDialogTitle(finalizedOrder?.status)}
|
||||||
intent={getDialogIntent(finalizedOrder?.status)}
|
intent={getOrderDialogIntent(finalizedOrder?.status)}
|
||||||
icon={getDialogIcon(finalizedOrder?.status)}
|
icon={getOrderDialogIcon(finalizedOrder?.status)}
|
||||||
>
|
>
|
||||||
<OrderFeedback transaction={transaction} order={finalizedOrder} />
|
<OrderFeedback transaction={transaction} order={finalizedOrder} />
|
||||||
</TransactionDialog>
|
</TransactionDialog>
|
||||||
@ -44,7 +44,9 @@ export const DealTicketManager = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDialogTitle = (status?: OrderStatus): string | undefined => {
|
export const getOrderDialogTitle = (
|
||||||
|
status?: OrderStatus
|
||||||
|
): string | undefined => {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -63,7 +65,9 @@ export const getDialogTitle = (status?: OrderStatus): string | undefined => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDialogIntent = (status?: OrderStatus): Intent | undefined => {
|
export const getOrderDialogIntent = (
|
||||||
|
status?: OrderStatus
|
||||||
|
): Intent | undefined => {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -81,7 +85,9 @@ export const getDialogIntent = (status?: OrderStatus): Intent | undefined => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDialogIcon = (status?: OrderStatus): ReactNode | undefined => {
|
export const getOrderDialogIcon = (
|
||||||
|
status?: OrderStatus
|
||||||
|
): ReactNode | undefined => {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
12
libs/governance/.babelrc
Normal file
12
libs/governance/.babelrc
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@nrwl/react/babel",
|
||||||
|
{
|
||||||
|
"runtime": "automatic",
|
||||||
|
"useBuiltIns": "usage"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"plugins": []
|
||||||
|
}
|
18
libs/governance/.eslintrc.json
Normal file
18
libs/governance/.eslintrc.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
|
||||||
|
"ignorePatterns": ["!**/*", "__generated__"],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
|
"rules": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["*.ts", "*.tsx"],
|
||||||
|
"rules": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["*.js", "*.jsx"],
|
||||||
|
"rules": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
7
libs/governance/README.md
Normal file
7
libs/governance/README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# governance
|
||||||
|
|
||||||
|
This library was generated with [Nx](https://nx.dev).
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `nx test governance` to execute the unit tests via [Jest](https://jestjs.io).
|
10
libs/governance/jest.config.js
Normal file
10
libs/governance/jest.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module.exports = {
|
||||||
|
displayName: 'governance',
|
||||||
|
preset: '../../jest.preset.js',
|
||||||
|
transform: {
|
||||||
|
'^.+\\.[tj]sx?$': 'babel-jest',
|
||||||
|
},
|
||||||
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||||
|
coverageDirectory: '../../coverage/libs/governance',
|
||||||
|
setupFilesAfterEnv: ['./src/setup-tests.ts'],
|
||||||
|
};
|
4
libs/governance/package.json
Normal file
4
libs/governance/package.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"name": "@vegaprotocol/governance",
|
||||||
|
"version": "0.0.1"
|
||||||
|
}
|
43
libs/governance/project.json
Normal file
43
libs/governance/project.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"root": "libs/governance",
|
||||||
|
"sourceRoot": "libs/governance/src",
|
||||||
|
"projectType": "library",
|
||||||
|
"tags": [],
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"executor": "@nrwl/web:rollup",
|
||||||
|
"outputs": ["{options.outputPath}"],
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/libs/governance",
|
||||||
|
"tsConfig": "libs/governance/tsconfig.lib.json",
|
||||||
|
"project": "libs/governance/package.json",
|
||||||
|
"entryFile": "libs/governance/src/index.ts",
|
||||||
|
"external": ["react/jsx-runtime"],
|
||||||
|
"rollupConfig": "@nrwl/react/plugins/bundle-rollup",
|
||||||
|
"compiler": "babel",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "libs/governance/README.md",
|
||||||
|
"input": ".",
|
||||||
|
"output": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"executor": "@nrwl/linter:eslint",
|
||||||
|
"outputs": ["{options.outputFile}"],
|
||||||
|
"options": {
|
||||||
|
"lintFilePatterns": ["libs/governance/**/*.{ts,tsx,js,jsx}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"executor": "@nrwl/jest:jest",
|
||||||
|
"outputs": ["coverage/libs/governance"],
|
||||||
|
"options": {
|
||||||
|
"jestConfig": "libs/governance/jest.config.js",
|
||||||
|
"passWithNoTests": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
libs/governance/src/index.ts
Normal file
2
libs/governance/src/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './lib';
|
||||||
|
export * from './utils';
|
2
libs/governance/src/lib/index.ts
Normal file
2
libs/governance/src/lib/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './proposals-hooks';
|
||||||
|
export * from './proposal-form';
|
175
libs/governance/src/lib/proposal-form.spec.tsx
Normal file
175
libs/governance/src/lib/proposal-form.spec.tsx
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
import { act, fireEvent, render, screen } from '@testing-library/react';
|
||||||
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||||
|
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||||
|
import {
|
||||||
|
BusEventType,
|
||||||
|
ProposalRejectionReason,
|
||||||
|
ProposalState,
|
||||||
|
} from '@vegaprotocol/types';
|
||||||
|
import { ProposalForm } from './proposal-form';
|
||||||
|
import { PROPOSAL_EVENT_SUB } from './proposals-hooks';
|
||||||
|
import type { ProposalEvent } from './proposals-hooks/__generated__/ProposalEvent';
|
||||||
|
|
||||||
|
describe('ProposalForm', () => {
|
||||||
|
const pubkey = '0x123';
|
||||||
|
const mockProposalEvent: MockedResponse<ProposalEvent> = {
|
||||||
|
request: {
|
||||||
|
query: PROPOSAL_EVENT_SUB,
|
||||||
|
variables: {
|
||||||
|
partyId: pubkey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
busEvents: [
|
||||||
|
{
|
||||||
|
__typename: 'BusEvent',
|
||||||
|
type: BusEventType.Proposal,
|
||||||
|
event: {
|
||||||
|
__typename: 'Proposal',
|
||||||
|
id: '2fca514cebf9f465ae31ecb4c5721e3a6f5f260425ded887ca50ba15b81a5d50',
|
||||||
|
reference: 'proposal-reference',
|
||||||
|
state: ProposalState.Open,
|
||||||
|
rejectionReason: ProposalRejectionReason.CloseTimeTooLate,
|
||||||
|
errorDetails: 'error-details',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
delay: 300,
|
||||||
|
};
|
||||||
|
const setup = (mockSendTx = jest.fn()) => {
|
||||||
|
return render(
|
||||||
|
<MockedProvider mocks={[mockProposalEvent]}>
|
||||||
|
<VegaWalletContext.Provider
|
||||||
|
value={
|
||||||
|
{
|
||||||
|
keypair: { pub: pubkey },
|
||||||
|
sendTx: mockSendTx,
|
||||||
|
} as unknown as VegaWalletContextShape
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ProposalForm />
|
||||||
|
</VegaWalletContext.Provider>
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles validation', async () => {
|
||||||
|
const mockSendTx = jest.fn().mockReturnValue(Promise.resolve());
|
||||||
|
setup(mockSendTx);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByTestId('proposal-submit'));
|
||||||
|
expect(mockSendTx).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
expect(await screen.findByTestId('input-error-text')).toHaveTextContent(
|
||||||
|
'Required'
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.change(screen.getByTestId('proposal-data'), {
|
||||||
|
target: { value: 'invalid' },
|
||||||
|
});
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByTestId('proposal-submit'));
|
||||||
|
expect(mockSendTx).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
expect(await screen.findByTestId('input-error-text')).toHaveTextContent(
|
||||||
|
'Must be valid JSON'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sends the transaction', async () => {
|
||||||
|
const mockSendTx = jest.fn().mockReturnValue(
|
||||||
|
new Promise((resolve) => {
|
||||||
|
setTimeout(
|
||||||
|
() =>
|
||||||
|
resolve({
|
||||||
|
txHash: 'tx-hash',
|
||||||
|
tx: {
|
||||||
|
signature: {
|
||||||
|
value:
|
||||||
|
'cfe592d169f87d0671dd447751036d0dddc165b9c4b65e5a5060e2bbadd1aa726d4cbe9d3c3b327bcb0bff4f83999592619a2493f9bbd251fae99ce7ce766909',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
100
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setup(mockSendTx);
|
||||||
|
|
||||||
|
const inputJSON = '{}';
|
||||||
|
fireEvent.change(screen.getByTestId('proposal-data'), {
|
||||||
|
target: { value: inputJSON },
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(screen.getByTestId('proposal-submit'));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockSendTx).toHaveBeenCalledWith({
|
||||||
|
propagate: true,
|
||||||
|
pubKey: pubkey,
|
||||||
|
proposalSubmission: JSON.parse(inputJSON),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('dialog-title')).toHaveTextContent(
|
||||||
|
'Confirm transaction in wallet'
|
||||||
|
);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.advanceTimersByTime(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('dialog-title')).toHaveTextContent(
|
||||||
|
'Awaiting network confirmation'
|
||||||
|
);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.advanceTimersByTime(400);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('dialog-title')).toHaveTextContent(
|
||||||
|
'Proposal submitted'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can be rejected by the user', async () => {
|
||||||
|
const mockSendTx = jest.fn().mockReturnValue(
|
||||||
|
new Promise((resolve) => {
|
||||||
|
setTimeout(() => resolve(null), 100);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setup(mockSendTx);
|
||||||
|
|
||||||
|
const inputJSON = '{}';
|
||||||
|
fireEvent.change(screen.getByTestId('proposal-data'), {
|
||||||
|
target: { value: inputJSON },
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(screen.getByTestId('proposal-submit'));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('dialog-title')).toHaveTextContent(
|
||||||
|
'Confirm transaction in wallet'
|
||||||
|
);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.advanceTimersByTime(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
81
libs/governance/src/lib/proposal-form.tsx
Normal file
81
libs/governance/src/lib/proposal-form.tsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import {
|
||||||
|
Button,
|
||||||
|
FormGroup,
|
||||||
|
InputError,
|
||||||
|
TextArea,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { useProposalSubmit } from './proposals-hooks';
|
||||||
|
import {
|
||||||
|
getProposalDialogIcon,
|
||||||
|
getProposalDialogIntent,
|
||||||
|
getProposalDialogTitle,
|
||||||
|
} from '../utils';
|
||||||
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
|
|
||||||
|
export interface FormFields {
|
||||||
|
proposalData: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProposalForm = () => {
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { isSubmitting, errors },
|
||||||
|
} = useForm<FormFields>();
|
||||||
|
const { finalizedProposal, submit, TransactionDialog } = useProposalSubmit();
|
||||||
|
|
||||||
|
const hasError = Boolean(errors.proposalData?.message);
|
||||||
|
|
||||||
|
const onSubmit = async (fields: FormFields) => {
|
||||||
|
await submit(JSON.parse(fields.proposalData));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<FormGroup
|
||||||
|
label="Make a proposal by submitting JSON"
|
||||||
|
labelFor="proposal-data"
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
id="proposal-data"
|
||||||
|
className="min-h-[200px]"
|
||||||
|
hasError={hasError}
|
||||||
|
data-testid="proposal-data"
|
||||||
|
{...register('proposalData', {
|
||||||
|
required: t('Required'),
|
||||||
|
validate: {
|
||||||
|
validateJson: (value) => {
|
||||||
|
try {
|
||||||
|
JSON.parse(value);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return t('Must be valid JSON');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
{errors.proposalData?.message && (
|
||||||
|
<InputError intent="danger" className="mt-4">
|
||||||
|
{errors.proposalData?.message}
|
||||||
|
</InputError>
|
||||||
|
)}
|
||||||
|
</FormGroup>
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
className="my-20"
|
||||||
|
data-testid="proposal-submit"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{isSubmitting ? t('Submitting') : t('Submit')} {t('Proposal')}
|
||||||
|
</Button>
|
||||||
|
<TransactionDialog
|
||||||
|
title={getProposalDialogTitle(finalizedProposal?.state)}
|
||||||
|
intent={getProposalDialogIntent(finalizedProposal?.state)}
|
||||||
|
icon={getProposalDialogIcon(finalizedProposal?.state)}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
63
libs/governance/src/lib/proposals-hooks/__generated__/ProposalEvent.ts
generated
Normal file
63
libs/governance/src/lib/proposals-hooks/__generated__/ProposalEvent.ts
generated
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { BusEventType, ProposalState, ProposalRejectionReason } from "@vegaprotocol/types";
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL subscription operation: ProposalEvent
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface ProposalEvent_busEvents_event_TimeUpdate {
|
||||||
|
__typename: "TimeUpdate" | "MarketEvent" | "TransferResponses" | "PositionResolution" | "Order" | "Trade" | "Account" | "Party" | "MarginLevels" | "Vote" | "MarketData" | "NodeSignature" | "LossSocialization" | "SettlePosition" | "Market" | "Asset" | "MarketTick" | "SettleDistressed" | "AuctionEvent" | "RiskFactor" | "Deposit" | "Withdrawal" | "OracleSpec" | "LiquidityProvision";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProposalEvent_busEvents_event_Proposal {
|
||||||
|
__typename: "Proposal";
|
||||||
|
/**
|
||||||
|
* Proposal ID that is filled by VEGA once proposal reaches the network
|
||||||
|
*/
|
||||||
|
id: string | null;
|
||||||
|
/**
|
||||||
|
* A UUID reference to aid tracking proposals on VEGA
|
||||||
|
*/
|
||||||
|
reference: string;
|
||||||
|
/**
|
||||||
|
* State of the proposal
|
||||||
|
*/
|
||||||
|
state: ProposalState;
|
||||||
|
/**
|
||||||
|
* Reason for the proposal to be rejected by the core
|
||||||
|
*/
|
||||||
|
rejectionReason: ProposalRejectionReason | null;
|
||||||
|
/**
|
||||||
|
* Error details of the rejectionReason
|
||||||
|
*/
|
||||||
|
errorDetails: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProposalEvent_busEvents_event = ProposalEvent_busEvents_event_TimeUpdate | ProposalEvent_busEvents_event_Proposal;
|
||||||
|
|
||||||
|
export interface ProposalEvent_busEvents {
|
||||||
|
__typename: "BusEvent";
|
||||||
|
/**
|
||||||
|
* the type of event we're dealing with
|
||||||
|
*/
|
||||||
|
type: BusEventType;
|
||||||
|
/**
|
||||||
|
* the payload - the wrapped event
|
||||||
|
*/
|
||||||
|
event: ProposalEvent_busEvents_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProposalEvent {
|
||||||
|
/**
|
||||||
|
* Subscribe to event data from the event bus
|
||||||
|
*/
|
||||||
|
busEvents: ProposalEvent_busEvents[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProposalEventVariables {
|
||||||
|
partyId: string;
|
||||||
|
}
|
3
libs/governance/src/lib/proposals-hooks/index.ts
Normal file
3
libs/governance/src/lib/proposals-hooks/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './__generated__/ProposalEvent';
|
||||||
|
export * from './use-proposal-event';
|
||||||
|
export * from './use-proposal-submit';
|
@ -0,0 +1,75 @@
|
|||||||
|
import { useApolloClient, gql } from '@apollo/client';
|
||||||
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
|
import type {
|
||||||
|
ProposalEvent,
|
||||||
|
ProposalEventVariables,
|
||||||
|
ProposalEvent_busEvents_event_Proposal,
|
||||||
|
} from './__generated__/ProposalEvent';
|
||||||
|
import type { Subscription } from 'zen-observable-ts';
|
||||||
|
|
||||||
|
export const PROPOSAL_EVENT_SUB = gql`
|
||||||
|
subscription ProposalEvent($partyId: ID!) {
|
||||||
|
busEvents(partyId: $partyId, batchSize: 0, types: [Proposal]) {
|
||||||
|
type
|
||||||
|
event {
|
||||||
|
... on Proposal {
|
||||||
|
id
|
||||||
|
reference
|
||||||
|
state
|
||||||
|
rejectionReason
|
||||||
|
errorDetails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const useProposalEvent = () => {
|
||||||
|
const client = useApolloClient();
|
||||||
|
const subRef = useRef<Subscription | null>(null);
|
||||||
|
|
||||||
|
const waitForProposalEvent = useCallback(
|
||||||
|
(
|
||||||
|
id: string,
|
||||||
|
partyId: string,
|
||||||
|
callback: (proposal: ProposalEvent_busEvents_event_Proposal) => void
|
||||||
|
) => {
|
||||||
|
subRef.current = client
|
||||||
|
.subscribe<ProposalEvent, ProposalEventVariables>({
|
||||||
|
query: PROPOSAL_EVENT_SUB,
|
||||||
|
variables: { partyId },
|
||||||
|
})
|
||||||
|
.subscribe(({ data }) => {
|
||||||
|
if (!data?.busEvents?.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No types available for the subscription result
|
||||||
|
const matchingProposalEvent = data.busEvents.find((e) => {
|
||||||
|
if (e.event.__typename !== 'Proposal') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.event.id === id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
matchingProposalEvent &&
|
||||||
|
matchingProposalEvent.event.__typename === 'Proposal'
|
||||||
|
) {
|
||||||
|
callback(matchingProposalEvent.event);
|
||||||
|
subRef.current?.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[client]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
subRef.current?.unsubscribe();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return waitForProposalEvent;
|
||||||
|
};
|
@ -0,0 +1,58 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import * as Sentry from '@sentry/react';
|
||||||
|
import { useVegaWallet, useVegaTransaction } from '@vegaprotocol/wallet';
|
||||||
|
import { determineId } from '@vegaprotocol/react-helpers';
|
||||||
|
import { useProposalEvent } from './use-proposal-event';
|
||||||
|
import type { ProposalSubmission } from '@vegaprotocol/wallet';
|
||||||
|
import type { ProposalEvent_busEvents_event_Proposal } from './__generated__/ProposalEvent';
|
||||||
|
|
||||||
|
export const useProposalSubmit = () => {
|
||||||
|
const { keypair } = useVegaWallet();
|
||||||
|
const waitForProposalEvent = useProposalEvent();
|
||||||
|
|
||||||
|
const { send, transaction, setComplete, TransactionDialog } =
|
||||||
|
useVegaTransaction();
|
||||||
|
|
||||||
|
const [finalizedProposal, setFinalizedProposal] =
|
||||||
|
useState<ProposalEvent_busEvents_event_Proposal | null>(null);
|
||||||
|
|
||||||
|
const submit = useCallback(
|
||||||
|
async (proposal: ProposalSubmission) => {
|
||||||
|
if (!keypair || !proposal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFinalizedProposal(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await send({
|
||||||
|
pubKey: keypair.pub,
|
||||||
|
propagate: true,
|
||||||
|
proposalSubmission: proposal,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res?.signature) {
|
||||||
|
const resId = determineId(res.signature);
|
||||||
|
if (resId) {
|
||||||
|
waitForProposalEvent(resId, keypair.pub, (p) => {
|
||||||
|
setFinalizedProposal(p);
|
||||||
|
setComplete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} catch (e) {
|
||||||
|
Sentry.captureException(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[keypair, send, setComplete, waitForProposalEvent]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
transaction,
|
||||||
|
finalizedProposal,
|
||||||
|
TransactionDialog,
|
||||||
|
submit,
|
||||||
|
};
|
||||||
|
};
|
1
libs/governance/src/setup-tests.ts
Normal file
1
libs/governance/src/setup-tests.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
import '@testing-library/jest-dom';
|
1
libs/governance/src/utils/index.ts
Normal file
1
libs/governance/src/utils/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './proposal-dialog-helpers';
|
74
libs/governance/src/utils/proposal-dialog-helpers.tsx
Normal file
74
libs/governance/src/utils/proposal-dialog-helpers.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { ProposalState } from '@vegaprotocol/types';
|
||||||
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
|
import { Icon, Intent } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
export const getProposalDialogTitle = (
|
||||||
|
status?: ProposalState
|
||||||
|
): string | undefined => {
|
||||||
|
if (!status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case ProposalState.Open:
|
||||||
|
return t('Proposal submitted');
|
||||||
|
case ProposalState.WaitingForNodeVote:
|
||||||
|
return t('Proposal waiting for node vote');
|
||||||
|
case ProposalState.Passed:
|
||||||
|
return t('Proposal passed');
|
||||||
|
case ProposalState.Enacted:
|
||||||
|
return t('Proposal enacted');
|
||||||
|
case ProposalState.Declined:
|
||||||
|
return t('Proposal declined');
|
||||||
|
case ProposalState.Rejected:
|
||||||
|
return t('Proposal rejected');
|
||||||
|
case ProposalState.Failed:
|
||||||
|
return t('Proposal failed');
|
||||||
|
default:
|
||||||
|
return t('Submission failed');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getProposalDialogIntent = (
|
||||||
|
status?: ProposalState
|
||||||
|
): Intent | undefined => {
|
||||||
|
if (!status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case ProposalState.Passed:
|
||||||
|
case ProposalState.Enacted:
|
||||||
|
return Intent.Success;
|
||||||
|
case ProposalState.Open:
|
||||||
|
case ProposalState.WaitingForNodeVote:
|
||||||
|
return Intent.None;
|
||||||
|
case ProposalState.Rejected:
|
||||||
|
case ProposalState.Failed:
|
||||||
|
case ProposalState.Declined:
|
||||||
|
return Intent.Danger;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getProposalDialogIcon = (
|
||||||
|
status?: ProposalState
|
||||||
|
): ReactNode | undefined => {
|
||||||
|
if (!status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case ProposalState.Passed:
|
||||||
|
case ProposalState.Enacted:
|
||||||
|
return <Icon name="tick" size={20} />;
|
||||||
|
case ProposalState.Rejected:
|
||||||
|
case ProposalState.Failed:
|
||||||
|
case ProposalState.Declined:
|
||||||
|
return <Icon name="error" size={20} />;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
25
libs/governance/tsconfig.json
Normal file
25
libs/governance/tsconfig.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": false,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.lib.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
26
libs/governance/tsconfig.lib.json
Normal file
26
libs/governance/tsconfig.lib.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"types": ["node"]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
|
||||||
|
"../../node_modules/@nrwl/react/typings/image.d.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.spec.tsx",
|
||||||
|
"**/*.test.tsx",
|
||||||
|
"**/*.spec.js",
|
||||||
|
"**/*.test.js",
|
||||||
|
"**/*.spec.jsx",
|
||||||
|
"**/*.test.jsx",
|
||||||
|
"**/*.stories.ts",
|
||||||
|
"**/*.stories.js",
|
||||||
|
"**/*.stories.jsx",
|
||||||
|
"**/*.stories.tsx"
|
||||||
|
],
|
||||||
|
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
|
||||||
|
}
|
19
libs/governance/tsconfig.spec.json
Normal file
19
libs/governance/tsconfig.spec.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"module": "commonjs",
|
||||||
|
"types": ["jest", "node", "@testing-library/jest-dom"]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.test.tsx",
|
||||||
|
"**/*.spec.tsx",
|
||||||
|
"**/*.test.js",
|
||||||
|
"**/*.spec.js",
|
||||||
|
"**/*.test.jsx",
|
||||||
|
"**/*.spec.jsx",
|
||||||
|
"**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
@ -219,10 +219,15 @@ export class RestConnector implements VegaConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ('errors' in err) {
|
if ('errors' in err) {
|
||||||
return err.errors['*'].join(', ');
|
const result = Object.entries(err.errors)
|
||||||
|
.map((entry) => {
|
||||||
|
return `${entry[0]}: ${entry[1].join(' | ')}`;
|
||||||
|
})
|
||||||
|
.join(', ');
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return t("Something wen't wrong");
|
return t('Something went wrong');
|
||||||
}
|
}
|
||||||
|
|
||||||
private async request(
|
private async request(
|
||||||
@ -240,9 +245,10 @@ export class RestConnector implements VegaConnector {
|
|||||||
|
|
||||||
if (!fetchResult.ok) {
|
if (!fetchResult.ok) {
|
||||||
const errorData = await fetchResult.json();
|
const errorData = await fetchResult.json();
|
||||||
|
const error = this.parseError(errorData);
|
||||||
return {
|
return {
|
||||||
status: fetchResult.status,
|
status: fetchResult.status,
|
||||||
error: this.parseError(errorData),
|
error,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +79,170 @@ export interface WithdrawSubmissionBody extends BaseTransaction {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ProposalNewMarketTerms {
|
||||||
|
newMarket: {
|
||||||
|
changes: {
|
||||||
|
decimalPlaces: string;
|
||||||
|
positionDecimalPlaces: string;
|
||||||
|
instrument: {
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
future: {
|
||||||
|
settlementAsset: string;
|
||||||
|
quoteName: string;
|
||||||
|
settlementPriceDecimals: number;
|
||||||
|
oracleSpecForSettlementPrice: OracleSpecFor;
|
||||||
|
oracleSpecForTradingTermination: OracleSpecFor;
|
||||||
|
oracleSpecBinding: OracleSpecBinding;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
metadata?: string[];
|
||||||
|
priceMonitoringParameters?: PriceMonitoringParameters;
|
||||||
|
liquidityMonitoringParameters?: {
|
||||||
|
targetStakeParameters: {
|
||||||
|
timeWindow: string;
|
||||||
|
scalingFactor: number;
|
||||||
|
};
|
||||||
|
triggeringRatio: number;
|
||||||
|
auctionExtension: string;
|
||||||
|
};
|
||||||
|
logNormal: LogNormal;
|
||||||
|
};
|
||||||
|
liquidityCommitment: {
|
||||||
|
commitmentAmount: string;
|
||||||
|
fee: string;
|
||||||
|
buys: Buy[];
|
||||||
|
sells: Buy[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
closingTimestamp: number;
|
||||||
|
enactmentTimestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProposalUpdateMarketTerms {
|
||||||
|
updateMarket: {
|
||||||
|
marketId: string;
|
||||||
|
changes: {
|
||||||
|
instrument: {
|
||||||
|
code: string;
|
||||||
|
future: {
|
||||||
|
quoteName: string;
|
||||||
|
settlementPriceDecimals: number;
|
||||||
|
oracleSpecForSettlementPrice: OracleSpecFor;
|
||||||
|
oracleSpecForTradingTermination: OracleSpecFor;
|
||||||
|
oracleSpecBinding: OracleSpecBinding;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
priceMonitoringParameters?: PriceMonitoringParameters;
|
||||||
|
logNormal: LogNormal;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
closingTimestamp: number;
|
||||||
|
enactmentTimestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProposalNetworkParameterTerms {
|
||||||
|
updateNetworkParameter: {
|
||||||
|
changes: {
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
closingTimestamp: number;
|
||||||
|
enactmentTimestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProposalFreeformTerms {
|
||||||
|
newFreeform: Record<string, never>;
|
||||||
|
closingTimestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProposalNewAssetTerms {
|
||||||
|
newAsset: {
|
||||||
|
changes: {
|
||||||
|
name: string;
|
||||||
|
symbol: string;
|
||||||
|
totalSupply: string;
|
||||||
|
decimals: string;
|
||||||
|
quantum: string;
|
||||||
|
erc20: {
|
||||||
|
contractAddress: string;
|
||||||
|
withdrawThreshold: string;
|
||||||
|
lifetimeLimit: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
closingTimestamp: number;
|
||||||
|
enactmentTimestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OracleSpecBinding {
|
||||||
|
settlementPriceProperty: string;
|
||||||
|
tradingTerminationProperty: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OracleSpecFor {
|
||||||
|
pubKeys: string[];
|
||||||
|
filters: Filter[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Filter {
|
||||||
|
key: {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
conditions?: Condition[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Condition {
|
||||||
|
operator: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LogNormal {
|
||||||
|
tau: number;
|
||||||
|
riskAversionParameter: number;
|
||||||
|
params: {
|
||||||
|
mu: number;
|
||||||
|
r: number;
|
||||||
|
sigma: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PriceMonitoringParameters {
|
||||||
|
triggers: Trigger[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Trigger {
|
||||||
|
horizon: string;
|
||||||
|
probability: string;
|
||||||
|
auctionExtension: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Buy {
|
||||||
|
offset: string;
|
||||||
|
proportion: number;
|
||||||
|
reference: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProposalSubmission {
|
||||||
|
rationale: {
|
||||||
|
description: string;
|
||||||
|
hash?: string;
|
||||||
|
url?: string;
|
||||||
|
};
|
||||||
|
terms:
|
||||||
|
| ProposalFreeformTerms
|
||||||
|
| ProposalNewMarketTerms
|
||||||
|
| ProposalUpdateMarketTerms
|
||||||
|
| ProposalNetworkParameterTerms
|
||||||
|
| ProposalNewAssetTerms;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProposalSubmissionBody extends BaseTransaction {
|
||||||
|
proposalSubmission: ProposalSubmission;
|
||||||
|
}
|
||||||
|
|
||||||
export enum VegaWalletVoteValue {
|
export enum VegaWalletVoteValue {
|
||||||
Yes = 'VALUE_YES',
|
Yes = 'VALUE_YES',
|
||||||
No = 'VALUE_NO',
|
No = 'VALUE_NO',
|
||||||
@ -111,7 +275,8 @@ export type TransactionSubmission =
|
|||||||
| VoteSubmissionBody
|
| VoteSubmissionBody
|
||||||
| DelegateSubmissionBody
|
| DelegateSubmissionBody
|
||||||
| UndelegateSubmissionBody
|
| UndelegateSubmissionBody
|
||||||
| OrderAmendmentBody;
|
| OrderAmendmentBody
|
||||||
|
| ProposalSubmissionBody;
|
||||||
|
|
||||||
export type TransactionResponse = z.infer<typeof TransactionResponseSchema>;
|
export type TransactionResponse = z.infer<typeof TransactionResponseSchema>;
|
||||||
export type GetKeysResponse = z.infer<typeof GetKeysSchema>;
|
export type GetKeysResponse = z.infer<typeof GetKeysSchema>;
|
||||||
@ -120,7 +285,7 @@ export type VegaKey = IterableElement<GetKeysResponse['keys']>;
|
|||||||
export type TransactionError =
|
export type TransactionError =
|
||||||
| {
|
| {
|
||||||
errors: {
|
errors: {
|
||||||
'*': string[];
|
[key: string]: string[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"@vegaprotocol/deposits": ["libs/deposits/src/index.ts"],
|
"@vegaprotocol/deposits": ["libs/deposits/src/index.ts"],
|
||||||
"@vegaprotocol/environment": ["libs/environment/src/index.ts"],
|
"@vegaprotocol/environment": ["libs/environment/src/index.ts"],
|
||||||
"@vegaprotocol/fills": ["libs/fills/src/index.ts"],
|
"@vegaprotocol/fills": ["libs/fills/src/index.ts"],
|
||||||
|
"@vegaprotocol/governance": ["libs/governance/src/index.ts"],
|
||||||
"@vegaprotocol/market-depth": ["libs/market-depth/src/index.ts"],
|
"@vegaprotocol/market-depth": ["libs/market-depth/src/index.ts"],
|
||||||
"@vegaprotocol/market-list": ["libs/market-list/src/index.ts"],
|
"@vegaprotocol/market-list": ["libs/market-list/src/index.ts"],
|
||||||
"@vegaprotocol/network-info": ["libs/network-info/src/index.ts"],
|
"@vegaprotocol/network-info": ["libs/network-info/src/index.ts"],
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"explorer": "apps/explorer",
|
"explorer": "apps/explorer",
|
||||||
"explorer-e2e": "apps/explorer-e2e",
|
"explorer-e2e": "apps/explorer-e2e",
|
||||||
"fills": "libs/fills",
|
"fills": "libs/fills",
|
||||||
|
"governance": "libs/governance",
|
||||||
"market-depth": "libs/market-depth",
|
"market-depth": "libs/market-depth",
|
||||||
"market-list": "libs/market-list",
|
"market-list": "libs/market-list",
|
||||||
"network-info": "libs/network-info",
|
"network-info": "libs/network-info",
|
||||||
|
Loading…
Reference in New Issue
Block a user