Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions govtool/backend/app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ startApp vvaConfig sentryService = do
networkInfoCache <- newCache
networkTotalStakeCache <- newCache
dRepVotingPowerListCache <- newCache
accountInfoCache <- newCache
return $ CacheEnv
{ proposalListCache
, getProposalCache
Expand All @@ -139,6 +140,7 @@ startApp vvaConfig sentryService = do
, networkInfoCache
, networkTotalStakeCache
, dRepVotingPowerListCache
, accountInfoCache
}

let connectionString = encodeUtf8 (dbSyncConnectionString $ getter vvaConfig)
Expand Down
23 changes: 23 additions & 0 deletions govtool/backend/sql/get-account-info.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
SELECT
sa.id,
sa.view,
CASE
WHEN sa.script_hash IS NOT NULL THEN true
ELSE false
END AS is_script_based,
CASE
WHEN (
SELECT COALESCE(MAX(epoch_no), 0)
FROM stake_registration sr
WHERE sr.addr_id = sa.id
) > (
SELECT COALESCE(MAX(epoch_no), 0)
FROM stake_deregistration sd
WHERE sd.addr_id = sa.id
) THEN true
ELSE false
END AS is_registered
FROM
stake_address sa
WHERE
sa.hash_raw = decode(?, 'hex');
14 changes: 14 additions & 0 deletions govtool/backend/src/VVA/API.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import VVA.Config
import qualified VVA.DRep as DRep
import qualified VVA.Epoch as Epoch
import VVA.Network as Network
import VVA.Account as Account
import qualified VVA.Proposal as Proposal
import qualified VVA.Transaction as Transaction
import qualified VVA.Types as Types
Expand Down Expand Up @@ -85,6 +86,7 @@ type VVAApi =
:<|> "network" :> "metrics" :> Get '[JSON] GetNetworkMetricsResponse
:<|> "network" :> "info" :> Get '[JSON] GetNetworkInfoResponse
:<|> "network" :> "total-stake" :> Get '[JSON] GetNetworkTotalStakeResponse
:<|> "account" :> Capture "stakeKey" HexText :> Get '[JSON] GetAccountInfoResponse

server :: App m => ServerT VVAApi m
server = drepList
Expand All @@ -103,6 +105,7 @@ server = drepList
:<|> getNetworkMetrics
:<|> getNetworkInfo
:<|> getNetworkTotalStake
:<|> getAccountInfo

mapDRepType :: Types.DRepType -> DRepType
mapDRepType Types.DRep = NormalDRep
Expand Down Expand Up @@ -527,3 +530,14 @@ getNetworkMetrics = do
, getNetworkMetricsResponseQuorumNumerator = networkMetricsQuorumNumerator
, getNetworkMetricsResponseQuorumDenominator = networkMetricsQuorumDenominator
}

getAccountInfo :: App m => HexText -> m GetAccountInfoResponse
getAccountInfo (unHexText -> stakeKey) = do
CacheEnv {accountInfoCache} <- asks vvaCache
Types.AccountInfo {..} <- Account.accountInfo stakeKey
return $ GetAccountInfoResponse
{ getAccountInfoResponseId = accountInfoId
, getAccountInfoResponseView = accountInfoView
, getAccountInfoResponseIsRegistered = accountInfoIsRegistered
, getAccountInfoResponseIsScriptBased = accountInfoIsScriptBased
}
23 changes: 23 additions & 0 deletions govtool/backend/src/VVA/API/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1032,3 +1032,26 @@ instance ToSchema GetNetworkMetricsResponse where
& description ?~ "GetNetworkMetricsResponse"
& example
?~ toJSON exampleGetNetworkMetricsResponse

data GetAccountInfoResponse
= GetAccountInfoResponse
{ getAccountInfoResponseId :: Integer
, getAccountInfoResponseView :: Text
, getAccountInfoResponseIsRegistered :: Bool
, getAccountInfoResponseIsScriptBased :: Bool
}
deriving (Generic, Show)
deriveJSON (jsonOptions "getAccountInfoResponse") ''GetAccountInfoResponse
exampleGetAccountInfoResponse :: Text
exampleGetAccountInfoResponse =
"{\"stakeKey\": \"stake1u9\","
<> " \"id\": \"1\","
<> "\"view\": \"stake_test1uzapf83wydusjln97rqr7fen6vgrz5087yqdxm0akqdqkgstj2345\","
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that change needed? 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was a real view there, so I modified it slightly to not use real data.

<> "\"isRegistered\": false,"
<> "\"isScriptBased\": false}"
instance ToSchema GetAccountInfoResponse where
declareNamedSchema _ = pure $ NamedSchema (Just "GetAccountInfoResponse") $ mempty
& type_ ?~ OpenApiObject
& description ?~ "GetAccountInfoResponse"
& example
?~ toJSON exampleGetAccountInfoResponse
35 changes: 35 additions & 0 deletions govtool/backend/src/VVA/Account.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}

module VVA.Account where

import Control.Monad.Except (MonadError, throwError)
import Control.Monad.Reader (MonadIO, MonadReader, liftIO)
import Data.ByteString (ByteString)
import Data.FileEmbed (embedFile)
import Data.String (fromString)
import qualified Database.PostgreSQL.Simple as SQL
import VVA.Types (AppError(..), AccountInfo(..))
import Data.Text (Text, unpack)
import qualified Data.Text.Encoding as Text
import qualified Data.Text.IO as Text
import Data.Has (Has)
import VVA.Pool (ConnectionPool, withPool)

sqlFrom :: ByteString -> SQL.Query
sqlFrom = fromString . unpack . Text.decodeUtf8

accountInfoSql :: SQL.Query
accountInfoSql = sqlFrom $(embedFile "sql/get-account-info.sql")

accountInfo ::
(Has ConnectionPool r, MonadReader r m, MonadIO m, MonadError AppError m) =>
Text ->
m AccountInfo
accountInfo stakeKey = withPool $ \conn -> do
result <- liftIO $ SQL.query conn accountInfoSql (SQL.Only stakeKey)
case result of
[(id, view, is_registered, is_script_based)] ->
return $ AccountInfo id view is_registered is_script_based
_ -> throwError $ CriticalError "Could not query the account info."
9 changes: 9 additions & 0 deletions govtool/backend/src/VVA/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ data CacheEnv
, networkInfoCache :: Cache.Cache () NetworkInfo
, networkTotalStakeCache :: Cache.Cache () NetworkTotalStake
, dRepVotingPowerListCache :: Cache.Cache Text [DRepVotingPowerList]
, accountInfoCache :: Cache.Cache Text AccountInfo
}

data NetworkInfo
Expand Down Expand Up @@ -302,3 +303,11 @@ data Delegation
, delegationIsDRepScriptBased :: Bool
, delegationTxHash :: Text
}

data AccountInfo
= AccountInfo
{ accountInfoId :: Integer
, accountInfoView :: Text
, accountInfoIsRegistered :: Bool
, accountInfoIsScriptBased :: Bool
}
2 changes: 2 additions & 0 deletions govtool/backend/vva-be.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ extra-source-files:
sql/get-dreps-voting-power-list.sql
sql/get-filtered-dreps-voting-power.sql
sql/get-previous-enacted-governance-action-proposal-details.sql
sql/get-account-info.sql
executable vva-be
main-is: Main.hs

Expand Down Expand Up @@ -124,4 +125,5 @@ library
, VVA.Pool
, VVA.Types
, VVA.Network
, VVA.Account
ghc-options: -threaded
7 changes: 7 additions & 0 deletions govtool/frontend/src/models/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,10 @@ type DRepVotingPower = {
};

export type DRepVotingPowerListResponse = DRepVotingPower[];

export type Account = {
id: number,
view: string,
isRegistered: boolean,
isScriptBased: boolean
}
3 changes: 2 additions & 1 deletion govtool/frontend/src/pages/ProposalDiscussion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useValidateMutation } from "@/hooks/mutations";
import { useScreenDimension } from "@/hooks/useScreenDimension";
import { Footer, TopNav } from "@/components/organisms";
import { useGetDRepVotingPowerList, useGetVoterInfo } from "@/hooks";
import { getAdaHolderVotingPower } from "@/services";
import { getAdaHolderVotingPower, getAccount } from "@/services";

const ProposalDiscussion = React.lazy(
() => import("@intersect.mbo/pdf-ui/cjs"),
Expand Down Expand Up @@ -81,6 +81,7 @@ export const ProposalDiscussionPillar = () => {
setUsername={setUsername}
epochParams={epochParams}
getAdaHolderVotingPower={getAdaHolderVotingPower}
getAccount={getAccount}
{...snackbarContext}
/>
</Suspense>
Expand Down
8 changes: 8 additions & 0 deletions govtool/frontend/src/services/requests/getAccount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Account } from "@/models";
import { API } from "../API";

export const getAccount = async ({ stakeKey }: { stakeKey?: string }) => {
const response = await API.get<Account>(`/account/${stakeKey || ""}`);

return response.data;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ export const getAdaHolderVotingPower = async ({
stakeKey,
}: {
stakeKey?: string;
}): Promise<number> => {
const response = await API.get(`/ada-holder/get-voting-power/${stakeKey}`);
}) => {
const response = await API.get<number>(
`/ada-holder/get-voting-power/${stakeKey}`,
);

return response.data;
};
1 change: 1 addition & 0 deletions govtool/frontend/src/services/requests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * from "./postDRepRemoveVote";
export * from "./postDRepRetire";
export * from "./postDRepVote";
export * from "./getDRepVotingPowerList";
export * from "./getAccount";
7 changes: 6 additions & 1 deletion govtool/frontend/src/types/@intersect.mbo.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ enum MetadataValidationStatus {
INCORRECT_FORMAT = "INCORRECT_FORMAT",
}
declare module "@intersect.mbo/pdf-ui/cjs" {
import { EpochParams } from "@/models";
import { EpochParams, Account } from "@/models";

type ProposalDiscussionProps = {
pdfApiUrl: string;
Expand Down Expand Up @@ -37,6 +37,11 @@ declare module "@intersect.mbo/pdf-ui/cjs" {
}: {
stakeKey?: string;
}) => Promise<number>;
getAccount: ({
stakeKey,
}: {
stakeKey?: string;
}) => Promise<Account>;
};

type GovernanceActionsOutcomesProps = {
Expand Down