diff --git a/frontend/src/store/features/gov/govService.ts b/frontend/src/store/features/gov/govService.ts new file mode 100644 index 000000000..bab0c3d44 --- /dev/null +++ b/frontend/src/store/features/gov/govService.ts @@ -0,0 +1,77 @@ +import Axios, { AxiosResponse } from 'axios'; +import { convertPaginationToParams, cleanURL } from '../../../utils/util'; +import { + GetProposalsInVotingResponse, + GovProposal, + ProposalVote, +} from '@/types/gov'; + +const proposalsURL = '/cosmos/gov/v1beta1/proposals'; +const proposalTallyURL = (id: number): string => + `/cosmos/gov/v1beta1/proposals/${id}/tally`; + +const voterVoteURL = (id: number, voter: string): string => + `/cosmos/gov/v1beta1/proposals/${id}/votes/${voter}`; + +const depositParamsURL = `/cosmos/gov/v1beta1/params/deposit`; + +const fetchProposals = ( + baseURL: string, + key: string | undefined, + limit: number | undefined, + status: number +): Promise> => { + let uri = `${cleanURL(baseURL)}${proposalsURL}`; + uri += `?proposal_status=${status}`; + + const params = convertPaginationToParams({ + key: key, + limit: limit, + }); + + if (params !== '') uri += `&${params}`; + return Axios.get(uri); +}; + +const fetchProposalTally = ( + baseURL: string, + proposalId: number +): Promise => { + const uri = `${cleanURL(baseURL)}${proposalTallyURL(proposalId)}`; + return Axios.get(uri); +}; + +const fetchVoterVote = ( + baseURL: string, + proposalId: number, + voter: string, + key: string | undefined, + limit: number | undefined +): Promise> => { + let uri = `${cleanURL(baseURL)}${voterVoteURL(proposalId, voter)}`; + const params = convertPaginationToParams({ + key: key, + limit: limit, + }); + if (params !== '') uri += `?${params}`; + return Axios.get(uri); +}; + +const fetchProposal = ( + baseURL: string, + proposalId: number +): Promise> => + Axios.get(`${cleanURL(baseURL)}${proposalsURL}/${proposalId}`); + +const fetchDepositParams = (baseURL: string): Promise => + Axios.get(`${cleanURL(baseURL)}${depositParamsURL}`); + +const result = { + proposals: fetchProposals, + tally: fetchProposalTally, + votes: fetchVoterVote, + proposal: fetchProposal, + depositParams: fetchDepositParams, +}; + +export default result; diff --git a/frontend/src/store/features/gov/govSlice.ts b/frontend/src/store/features/gov/govSlice.ts new file mode 100644 index 000000000..f0a0d9f70 --- /dev/null +++ b/frontend/src/store/features/gov/govSlice.ts @@ -0,0 +1,668 @@ +'use client'; + +import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit'; +import govService from './govService'; +import { cloneDeep } from 'lodash'; +import { AxiosError } from 'axios'; +import { ERR_UNKNOWN } from '@/utils/errors'; +import { TxStatus } from '@/types/enums'; +import { + GovProposal, + GetProposalTallyInputs, + GetProposalsInDepositInputs, + GetProposalsInVotingInputs, + GetVotesInputs, + ProposalTallyData, + VotesData, + DepositParams, + GetDepositParamsInputs, + GetProposalInputs, + TxVoteInputs, + TxDepositInputs, +} from '@/types/gov'; +import { GAS_FEE, PROPOSAL_STATUS_VOTING_PERIOD } from '@/utils/constants'; +import { signAndBroadcast } from '@/utils/signing'; +import { setError, setTxHash } from '../common/commonSlice'; +import { GovDepositMsg, GovVoteMsg } from '@/txns/gov'; + +const PROPSAL_STATUS_DEPOSIT = 1; +const PROPOSAL_STATUS_ACTIVE = 2; + +interface Chain { + active: { + status: TxStatus; + errMsg: string; + proposals: GovProposal[]; + pagination?: Pagination; + }; + deposit: { + status: TxStatus; + errMsg: string; + proposals: GovProposal[]; + pagination?: Pagination; + }; + depositParams: { + status: TxStatus; + errMsg: string; + params: DepositParams; + }; + votes: VotesData; + tally: ProposalTallyData; + tx: { + status: TxStatus; + txHash: string; + }; +} + +interface Chains { + [key: string]: Chain; +} + +interface GovState { + chains: Chains; + defaultState: Chain; + proposalInfo: { + status: TxStatus; + errMsg: string; + }; + activeProposalsLoading: number; + depositProposalsLoading: number; +} + +const EMPTY_PAGINATION = { + next_key: '', + total: '', +}; + +const initialState: GovState = { + chains: {}, + activeProposalsLoading: 0, + depositProposalsLoading: 0, + defaultState: { + active: { + status: TxStatus.INIT, + errMsg: '', + proposals: [], + pagination: { + next_key: '', + total: '', + }, + }, + deposit: { + status: TxStatus.INIT, + errMsg: '', + proposals: [], + pagination: { + next_key: '', + total: '', + }, + }, + depositParams: { + status: TxStatus.INIT, + errMsg: '', + params: { + min_deposit: [ + { + denom: '', + amount: '', + }, + ], + max_deposit_period: '', + }, + }, + votes: { + status: TxStatus.INIT, + errMsg: '', + proposals: {}, + }, + tally: { + status: TxStatus.INIT, + errMsg: '', + proposalTally: {}, + }, + tx: { + status: TxStatus.INIT, + txHash: '', + }, + }, + proposalInfo: { + status: TxStatus.INIT, + errMsg: '', + }, +}; + +export const getProposal = createAsyncThunk( + 'gov/proposal-info', + async (data: GetProposalInputs, { rejectWithValue }) => { + try { + const response = await govService.proposal(data.baseURL, data.proposalId); + return { + chainID: data.chainID, + data: response.data, + }; + } catch (error) { + if (error instanceof AxiosError) + return rejectWithValue({ message: error.message }); + return rejectWithValue({ message: ERR_UNKNOWN }); + } + } +); + +export const getProposalsInDeposit = createAsyncThunk( + 'gov/deposit-proposals', + async (data: GetProposalsInDepositInputs, { rejectWithValue, dispatch }) => { + try { + const response = await govService.proposals( + data.baseURL, + data?.key, + data?.limit, + PROPSAL_STATUS_DEPOSIT + ); + + if (response?.data?.proposals?.length && data?.chainID?.length) { + dispatch( + getDepositParams({ + baseURL: data.baseURL, + chainID: data.chainID, + }) + ); + } + + return { + chainID: data.chainID, + data: response.data, + }; + } catch (error) { + if (error instanceof AxiosError) + return rejectWithValue({ message: error.message }); + return rejectWithValue({ message: ERR_UNKNOWN }); + } + } +); + +export const getDepositParams = createAsyncThunk( + 'gov/deposit-params', + async (data: GetDepositParamsInputs, { rejectWithValue }) => { + try { + const response = await govService.depositParams(data.baseURL); + + return { + chainID: data.chainID, + data: response.data, + }; + } catch (error) { + if (error instanceof AxiosError) + return rejectWithValue({ message: error.message }); + return rejectWithValue({ message: ERR_UNKNOWN }); + } + } +); + +export const getProposalsInVoting = createAsyncThunk( + 'gov/active-proposals', + async (data: GetProposalsInVotingInputs, { rejectWithValue, dispatch }) => { + try { + const response = await govService.proposals( + data.baseURL, + data.key, + data.limit, + PROPOSAL_STATUS_ACTIVE + ); + + const { data: responseData } = response || {}; + const proposals = responseData?.proposals || []; + proposals.forEach((proposal) => { + const proposalId = Number(proposal.proposal_id); + dispatch( + getProposalTally({ + baseURL: data?.baseURL, + proposalId, + chainID: data?.chainID, + }) + ); + dispatch( + getVotes({ + baseURL: data?.baseURL, + proposalId, + voter: data?.voter, + chainID: data?.chainID, + }) + ); + }); + + return { + chainID: data.chainID, + data: responseData, + }; + } catch (error) { + if (error instanceof AxiosError) + return rejectWithValue({ message: error.message }); + return rejectWithValue({ message: ERR_UNKNOWN }); + } + } +); + +export const getVotes = createAsyncThunk( + 'gov/voter-votes', + async (data: GetVotesInputs, { rejectWithValue }) => { + try { + const response = await govService.votes( + data.baseURL, + data.proposalId, + data.voter, + data.key, + data.limit + ); + + response.data.vote.proposal_id = data.proposalId; + + return { + chainID: data.chainID, + data: response.data, + }; + } catch (error) { + if (error instanceof AxiosError) + return rejectWithValue({ message: error.message }); + return rejectWithValue({ message: ERR_UNKNOWN }); + } + } +); + +export const getProposalTally = createAsyncThunk( + 'gov/proposal-tally', + async (data: GetProposalTallyInputs, { rejectWithValue }) => { + try { + const response = await govService.tally(data.baseURL, data.proposalId); + + response.data.tally.proposal_id = data.proposalId; + + return { + chainID: data.chainID, + data: response.data, + }; + } catch (error) { + if (error instanceof AxiosError) + return rejectWithValue({ message: error.message }); + return rejectWithValue({ message: ERR_UNKNOWN }); + } + } +); + +export const txVote = createAsyncThunk( + 'gov/tx-vote', + async ( + data: TxVoteInputs, + { rejectWithValue, fulfillWithValue, dispatch } + ) => { + try { + const msg = GovVoteMsg(data.proposalId, data.voter, data.option); + const result = await signAndBroadcast( + data.chainID, + data.aminoConfig, + data.prefix, + [msg], + GAS_FEE, + data?.justification || '', + `${data.feeAmount}${data.denom}`, + data.rest, + data.feegranter?.length > 0 ? data.feegranter : undefined + ); + if (result?.code === 0) { + dispatch( + setTxHash({ + hash: result?.transactionHash, + }) + ); + + return fulfillWithValue({ txHash: result?.transactionHash }); + } else { + dispatch( + setError({ + type: 'error', + message: result?.rawLog || '', + }) + ); + return rejectWithValue(result?.rawLog); + } + } catch (error) { + if (error instanceof AxiosError) { + dispatch( + setError({ + type: 'error', + message: error.message, + }) + ); + return rejectWithValue(error.response); + } + dispatch( + setError({ + type: 'error', + message: ERR_UNKNOWN, + }) + ); + return rejectWithValue(ERR_UNKNOWN); + } + } +); + +export const txDeposit = createAsyncThunk( + 'gov/tx-deposit', + async ( + data: TxDepositInputs, + { rejectWithValue, fulfillWithValue, dispatch } + ) => { + try { + const msg = GovDepositMsg( + data.proposalId, + data.depositer, + data.amount, + data.denom + ); + const result = await signAndBroadcast( + data.chainID, + data.aminoConfig, + data.prefix, + [msg], + 860000, + data?.justification || '', + `${data.feeAmount}${data.denom}`, + data.rest, + data.feegranter?.length > 0 ? data.feegranter : undefined + ); + const { code, transactionHash, rawLog } = result || {}; + + if (code === 0) { + dispatch(setTxHash({ hash: transactionHash })); + return fulfillWithValue({ txHash: transactionHash }); + } else { + dispatch(setError({ type: 'error', message: rawLog || '' })); + return rejectWithValue(rawLog); + } + } catch (error) { + if (error instanceof AxiosError) { + dispatch( + setError({ + type: 'error', + message: error.message, + }) + ); + return rejectWithValue(error.response); + } + dispatch( + setError({ + type: 'error', + message: ERR_UNKNOWN, + }) + ); + return rejectWithValue(ERR_UNKNOWN); + } + } +); + +export const govSlice = createSlice({ + name: 'gov', + initialState, + reducers: { + resetTx: (state, action: PayloadAction<{ chainID: string }>) => { + const chainID = action.payload.chainID; + state.chains[chainID].tx = { + status: TxStatus.INIT, + txHash: '', + }; + }, + resetState: (state, action: PayloadAction<{ chainID: string }>) => { + const { chainID } = action.payload; + state.chains[chainID] = cloneDeep(initialState.defaultState); + }, + resetDefaultState: (state, action: PayloadAction) => { + const chainsMap: Chains = {}; + const chains = action.payload; + chains.map((chainID) => { + chainsMap[chainID] = cloneDeep(initialState.defaultState); + }); + state.chains = chainsMap; + }, + }, + extraReducers: (builder) => { + // active proposals + builder + .addCase(getProposalsInVoting.pending, (state, action) => { + const chainID = action.meta?.arg?.chainID; + if (!state.chains[chainID]) + state.chains[chainID] = cloneDeep(initialState.defaultState); + const chainProposals = state.chains[chainID].active.proposals || {}; + const result = { + status: TxStatus.PENDING, + errMsg: '', + proposals: chainProposals, + pagination: EMPTY_PAGINATION, + }; + state.chains[chainID].active = result; + state.activeProposalsLoading++; + }) + .addCase(getProposalsInVoting.fulfilled, (state, action) => { + const chainID = action.payload?.chainID || ''; + if (chainID.length) { + const result = { + status: TxStatus.IDLE, + errMsg: '', + proposals: action.payload?.data?.proposals, + pagination: action.payload?.data?.pagination, + }; + state.chains[chainID].active = result; + state.activeProposalsLoading--; + } + }) + .addCase(getProposalsInVoting.rejected, (state, action) => { + const chainID = action.meta?.arg?.chainID; + const payload = action.payload as { message: string }; + const chainProposals = state.chains[chainID].active.proposals || {}; + const result = { + status: TxStatus.REJECTED, + errMsg: payload.message || '', + proposals: chainProposals, + pagination: EMPTY_PAGINATION, + }; + state.chains[chainID].active = result; + state.activeProposalsLoading--; + }); + + //proposals in deposit period + builder + .addCase(getProposalsInDeposit.pending, (state, action) => { + const chainID = action.meta?.arg?.chainID; + if (!state.chains[chainID]) + state.chains[chainID] = cloneDeep(initialState.defaultState); + const chainProposals = state.chains[chainID].deposit.proposals || {}; + const result = { + status: TxStatus.PENDING, + errMsg: '', + proposals: chainProposals, + pagination: EMPTY_PAGINATION, + }; + state.chains[chainID].deposit = result; + state.depositProposalsLoading++; + }) + .addCase(getProposalsInDeposit.fulfilled, (state, action) => { + const chainID = action.payload?.chainID || ''; + if (chainID.length) { + const result = { + status: TxStatus.IDLE, + errMsg: '', + proposals: action.payload?.data?.proposals, + pagination: action.payload?.data?.pagination, + }; + state.chains[chainID].deposit = result; + state.depositProposalsLoading--; + } + }) + .addCase(getProposalsInDeposit.rejected, (state, action) => { + const chainID = action.meta?.arg?.chainID; + const payload = action.payload as { message: string }; + const chainProposals = state.chains[chainID].deposit.proposals || {}; + const result = { + status: TxStatus.REJECTED, + errMsg: payload.message || '', + proposals: chainProposals, + pagination: EMPTY_PAGINATION, + }; + state.chains[chainID].deposit = result; + state.depositProposalsLoading--; + }); + + // votes + builder + .addCase(getVotes.pending, (state, action) => { + const chainID = action.meta?.arg?.chainID; + state.chains[chainID].votes.status = TxStatus.PENDING; + }) + .addCase(getVotes.fulfilled, (state, action) => { + const chainID = action.payload.chainID; + const result: VotesData = { + status: TxStatus.IDLE, + errMsg: '', + proposals: state.chains[chainID].votes?.proposals || {}, + }; + + result.proposals[action.payload?.data?.vote?.proposal_id] = + action.payload.data; + + state.chains[chainID].votes = result; + }) + .addCase(getVotes.rejected, (state, action) => { + const chainID = action.meta?.arg?.chainID; + const payload = action.payload as { message: string }; + state.chains[chainID].votes.status = TxStatus.REJECTED; + state.chains[chainID].votes.errMsg = payload.message || ''; + }); + + // tally + builder + .addCase(getProposalTally.pending, (state, action) => { + const chainID = action.meta?.arg?.chainID; + state.chains[chainID].tally.status = TxStatus.PENDING; + }) + .addCase(getProposalTally.fulfilled, (state, action) => { + const chainID = action.payload.chainID; + const result = { + status: TxStatus.IDLE, + errMsg: '', + proposalTally: state.chains[chainID].tally?.proposalTally || {}, + }; + + result.proposalTally[action.payload?.data?.tally?.proposal_id] = + action.payload?.data.tally; + state.chains[chainID].tally = result; + }) + .addCase(getProposalTally.rejected, (state, action) => { + const chainID = action.meta?.arg?.chainID; + const payload = action.payload as { message: string }; + state.chains[chainID].tally.status = TxStatus.REJECTED; + state.chains[chainID].tally.errMsg = payload.message || ''; + }); + + //deposit params + builder + .addCase(getDepositParams.pending, (state, action) => { + const chainID = action.meta?.arg?.chainID; + state.chains[chainID].depositParams.status = TxStatus.PENDING; + }) + .addCase(getDepositParams.fulfilled, (state, action) => { + const chainID = action.payload?.chainID || ''; + if (chainID.length) { + const result = { + status: TxStatus.IDLE, + errMsg: '', + params: action.payload?.data?.deposit_params, + }; + state.chains[chainID].depositParams = result; + } + }) + .addCase(getDepositParams.rejected, (state, action) => { + const chainID = action.meta?.arg?.chainID; + const payload = action.payload as { message: string }; + state.chains[chainID].depositParams.status = TxStatus.REJECTED; + state.chains[chainID].depositParams.errMsg = payload.message || ''; + }); + + // get one proposal + builder + .addCase(getProposal.pending, (state, action) => { + const chainID = action.meta?.arg?.chainID; + if (!state.chains[chainID]) + state.chains[chainID] = cloneDeep(initialState.defaultState); + state.proposalInfo.status = TxStatus.PENDING; + }) + .addCase(getProposal.fulfilled, (state, action) => { + const chainID = action.meta.arg?.chainID || ''; + if ( + action.payload.data?.proposal.status === PROPOSAL_STATUS_VOTING_PERIOD + ) { + const currentProposalsState = state.chains[chainID].active.proposals; + if (!currentProposalsState.length) { + const result = { + status: TxStatus.IDLE, + errMsg: '', + proposals: [action.payload.data.proposal], + }; + state.chains[chainID].active = result; + } + } else { + const currentProposalsState = state.chains[chainID].deposit.proposals; + if (!currentProposalsState.length) { + const result = { + status: TxStatus.IDLE, + errMsg: '', + proposals: [action.payload.data.proposal], + }; + state.chains[chainID].deposit = result; + } + } + state.proposalInfo.status = TxStatus.IDLE; + state.proposalInfo.errMsg = ''; + }) + .addCase(getProposal.rejected, (state, action) => { + state.proposalInfo.status = TxStatus.REJECTED; + const payload = action.payload as { message: string }; + state.proposalInfo.errMsg = payload.message || ''; + }); + + // tx-vote + builder + .addCase(txVote.pending, (state, action) => { + const chainID = action.meta?.arg?.chainID; + state.chains[chainID].tx.status = TxStatus.PENDING; + state.chains[chainID].tx.txHash = ''; + }) + .addCase(txVote.fulfilled, (state, action) => { + const chainID = action.meta?.arg?.chainID; + state.chains[chainID].tx.status = TxStatus.IDLE; + state.chains[chainID].tx.txHash = action.payload.txHash; + }) + .addCase(txVote.rejected, (state, action) => { + const chainID = action.meta?.arg?.chainID; + state.chains[chainID].tx.status = TxStatus.REJECTED; + state.chains[chainID].tx.txHash = ''; + }); + + builder + .addCase(txDeposit.pending, (state, action) => { + const chainID = action.meta?.arg?.chainID; + state.chains[chainID].tx.status = TxStatus.PENDING; + state.chains[chainID].tx.txHash = ''; + }) + .addCase(txDeposit.fulfilled, (state, action) => { + const chainID = action.meta?.arg?.chainID; + state.chains[chainID].tx.status = TxStatus.IDLE; + state.chains[chainID].tx.txHash = action.payload.txHash; + }) + .addCase(txDeposit.rejected, (state, action) => { + const chainID = action.meta?.arg?.chainID; + state.chains[chainID].tx.status = TxStatus.REJECTED; + state.chains[chainID].tx.txHash = ''; + }); + }, +}); + +export const { resetTx, resetState, resetDefaultState } = govSlice.actions; +export default govSlice.reducer; diff --git a/frontend/src/store/store.ts b/frontend/src/store/store.ts index 86385af66..06061f865 100644 --- a/frontend/src/store/store.ts +++ b/frontend/src/store/store.ts @@ -8,6 +8,7 @@ import stakeSlice from './features/staking/stakeSlice'; import bankSlice from './features/bank/bankSlice'; import distributionSlice from './features/distribution/distributionSlice'; import authSlice from './features/auth/authSlice'; +import govSlice from './features/gov/govSlice'; export const store = configureStore({ reducer: { @@ -18,6 +19,7 @@ export const store = configureStore({ bank: bankSlice, auth: authSlice, distribution: distributionSlice, + gov: govSlice, }, }); diff --git a/frontend/src/txns/gov/deposit.ts b/frontend/src/txns/gov/deposit.ts new file mode 100644 index 000000000..b10b10d34 --- /dev/null +++ b/frontend/src/txns/gov/deposit.ts @@ -0,0 +1,24 @@ +import { MsgDeposit } from 'cosmjs-types/cosmos/gov/v1beta1/tx'; + +const msgDeposit = '/cosmos.gov.v1beta1.MsgDeposit'; + +export function GovDepositMsg( + proposalId: number, + depositer: string, + amount: number, + denom: string +): Msg { + return { + typeUrl: msgDeposit, + value: MsgDeposit.fromPartial({ + depositor: depositer, + proposalId: BigInt(proposalId), + amount: [ + { + denom: denom, + amount: String(amount), + }, + ], + }), + }; +} diff --git a/frontend/src/txns/gov/index.ts b/frontend/src/txns/gov/index.ts new file mode 100644 index 000000000..347312c7b --- /dev/null +++ b/frontend/src/txns/gov/index.ts @@ -0,0 +1,2 @@ +export { GovVoteMsg } from './vote'; +export { GovDepositMsg } from './deposit'; diff --git a/frontend/src/txns/gov/vote.ts b/frontend/src/txns/gov/vote.ts new file mode 100644 index 000000000..ef35a50a7 --- /dev/null +++ b/frontend/src/txns/gov/vote.ts @@ -0,0 +1,19 @@ +import { VoteOption } from 'cosmjs-types/cosmos/gov/v1beta1/gov'; +import { MsgVote } from 'cosmjs-types/cosmos/gov/v1beta1/tx'; + +const msgVote = '/cosmos.gov.v1beta1.MsgVote'; + +export function GovVoteMsg( + proposalId: number, + voter: string, + option: VoteOption +): Msg { + return { + typeUrl: msgVote, + value: MsgVote.fromPartial({ + voter: voter, + option: option, + proposalId: BigInt(proposalId), + }), + }; +} diff --git a/frontend/src/types/gov.d.ts b/frontend/src/types/gov.d.ts new file mode 100644 index 000000000..398b5a906 --- /dev/null +++ b/frontend/src/types/gov.d.ts @@ -0,0 +1,174 @@ +import { TxStatus } from './enums'; + +interface GovProposal { + proposal_id: string; + content?: { + '@type': string; + title: string; + description: string; + }; + status: string; + final_tally_result: { + yes: string; + abstain: string; + no: string; + no_with_veto: string; + }; + submit_time: string; + deposit_end_time: string; + total_deposit: { + denom: string; + amount: string; + }[]; + voting_start_time: string; + voting_end_time: string; +} + +interface GetProposalsInVotingResponse { + proposals: GovProposal[]; + pagination: GovPagination; +} + +interface VoteOption { + option: string; + weight: string; +} + +interface Vote { + proposal_id: number; + voter: string; + option: string; + options: VoteOption[]; +} + +interface ProposalVote { + vote: Vote; +} + +interface VotesData { + status: TxStatus; + errMsg: string; + proposals: { + [key: string]: ProposalVote; + }; +} + +interface ProposalTally { + [key: string]: { + yes: string; + abstain: string; + no: string; + no_with_veto: string; + proposal_id: string; + }; +} + +interface GetProposalTallyResponse { + [key: string]: { + yes: string; + abstain: string; + no: string; + no_with_veto: string; + }; +} + +interface ProposalTallyData { + status: TxStatus; + errMsg: string; + proposalTally: ProposalTally; +} + +interface DepositParams { + min_deposit: { + denom: string; + amount: string; + }[]; + max_deposit_period: string; +} + +interface TallyParams { + quorum: string; + threshold: string; + vote_threshold: string; +} + +interface VotingParams { + voting_period: string; +} + +interface GovParamsResponse { + voting_params: VotingParams; + deposit_params: DepositParams; + tally_params: TallyParams; +} + +interface GetProposalsInVotingInputs { + baseURL: string; + chainID: string; + voter: string; + key?: string; + limit?: number; +} + +interface GetProposalsInDepositInputs { + baseURL: string; + chainID: string; + key?: string; + limit?: number; +} + +interface GetVotesInputs { + baseURL: string; + proposalId: number; + voter: string; + chainID: string; + key?: string; + limit?: number; +} + +interface GetProposalTallyInputs { + baseURL: string; + proposalId: number; + chainID: string; +} + +interface GetDepositParamsInputs { + baseURL: string; + chainID: string; +} + +interface GetProposalInputs { + baseURL: string; + proposalId: number; + chainID: string; +} + +interface TxVoteInputs { + voter: string; + proposalId: number; + option: number; + denom: string; + chainID: string; + rpc: string; + rest: string; + aminoConfig: AminoConfig; + prefix: string; + feeAmount: number; + feegranter: string; + justification?: string; +} + +interface TxDepositInputs { + depositer: string; + proposalId: number; + amount: number; + denom: string; + chainID: string; + rpc: string; + rest: string; + aminoConfig: AminoConfig; + prefix: string; + feeAmount: number; + feegranter: string; + justification?: string; +} diff --git a/frontend/src/types/types.d.ts b/frontend/src/types/types.d.ts index 6498d8b6f..b12c44159 100644 --- a/frontend/src/types/types.d.ts +++ b/frontend/src/types/types.d.ts @@ -8,3 +8,8 @@ type KeyLimitPagination = { key?: string; limit?: number; } + +interface Pagination { + next_key?: string; + total: string; +} \ No newline at end of file diff --git a/frontend/src/utils/constants.ts b/frontend/src/utils/constants.ts index 2df07f54a..dd1c11a9d 100644 --- a/frontend/src/utils/constants.ts +++ b/frontend/src/utils/constants.ts @@ -1,80 +1,4 @@ export const GAS_FEE = 860000; // TODO: Add template url export const ADD_NETWORK_TEMPLATE_URL = ""; -export const NETWORK_CONFIG_EMPTY = { - enableModules: { - authz: false, - feegrant: false, - group: false, - }, - aminoConfig: { - authz: false, - feegrant: false, - group: false, - }, - showAirdrop: false, - logos: { - menu: '', - toolbar: '', - }, - keplrExperimental: false, - leapExperimental: false, - isTestnet: false, - explorerTxHashEndpoint: '', - config: { - chainId: '', - chainName: '', - rest: '', - rpc: '', - currencies: [ - { - coinDenom: '', - coinMinimalDenom: '', - coinDecimals: 0, - }, - ], - bech32Config: { - bech32PrefixAccAddr: '', - bech32PrefixAccPub: '', - bech32PrefixValAddr: '', - bech32PrefixValPub: '', - bech32PrefixConsAddr: '', - bech32PrefixConsPub: '', - }, - feeCurrencies: [ - { - coinDenom: '', - coinMinimalDenom: '', - coinDecimals: 0, - gasPriceStep: { - low: 0, - average: 0, - high: 0, - }, - }, - { - coinDenom: '', - coinMinimalDenom: '', - coinDecimals: 0, - gasPriceStep: { - low: 0, - average: 0, - high: 0, - }, - }, - ], - bip44: { - coinType: 0, - }, - stakeCurrency: { - coinDenom: '', - coinMinimalDenom: '', - coinDecimals: 0, - }, - image: '', - theme: { - primaryColor: '', - gradient: '', - }, - }, -}; +export const PROPOSAL_STATUS_VOTING_PERIOD = 'PROPOSAL_STATUS_VOTING_PERIOD';