Skip to content

Commit

Permalink
feat(#1601): add support for protocol parameter change governance action
Browse files Browse the repository at this point in the history
  • Loading branch information
MSzalowski committed Aug 22, 2024
1 parent 4112253 commit 7d7c1d6
Show file tree
Hide file tree
Showing 20 changed files with 10,061 additions and 15,700 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ changes.

### Added

-
- Add support for displaying protocol parameters governance actions [Issue 1600](https://github.com/IntersectMBO/govtool/issues/1600)

### Fixed

Expand Down
23 changes: 18 additions & 5 deletions govtool/backend/sql/list-proposals.sql
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,30 @@ SELECT
creator_block.epoch_no,
voting_anchor.url,
encode(voting_anchor.data_hash, 'hex'),
ROW_TO_JSON(proposal_params),
off_chain_vote_gov_action_data.title,
off_chain_vote_gov_action_data.abstract,
off_chain_vote_gov_action_data.motivation,
off_chain_vote_gov_action_data.rationale,
coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'Yes'), 0) +(
coalesce(Sum(ldd_drep.amount) FILTER (WHERE voting_procedure.vote::text = 'Yes'), 0) +(
CASE WHEN gov_action_proposal.type = 'NoConfidence' THEN
always_no_confidence_voting_power.amount
ELSE
0
END) "yes_votes",
coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'No'), 0) +(
coalesce(Sum(ldd_drep.amount) FILTER (WHERE voting_procedure.vote::text = 'No'), 0) +(
CASE WHEN gov_action_proposal.type = 'NoConfidence' THEN
0
ELSE
always_no_confidence_voting_power.amount
END) "no_votes",
coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'Abstain'), 0) + always_abstain_voting_power.amount "abstain_votes"
coalesce(Sum(ldd_drep.amount) FILTER (WHERE voting_procedure.vote::text = 'Abstain'), 0) + always_abstain_voting_power.amount "abstain_votes",
coalesce(Sum(ldd_pool.amount) FILTER (WHERE voting_procedure.vote::text = 'Yes'), 0),
coalesce(Sum(ldd_pool.amount) FILTER (WHERE voting_procedure.vote::text = 'No'), 0),
coalesce(Sum(ldd_pool.amount) FILTER (WHERE voting_procedure.vote::text = 'Abstain'), 0),
coalesce(Sum(ldd_cc.amount) FILTER (WHERE voting_procedure.vote::text = 'Yes'), 0),
coalesce(Sum(ldd_cc.amount) FILTER (WHERE voting_procedure.vote::text = 'No'), 0),
coalesce(Sum(ldd_cc.amount) FILTER (WHERE voting_procedure.vote::text = 'Abstain'), 0)
FROM
gov_action_proposal
LEFT JOIN treasury_withdrawal
Expand All @@ -83,11 +90,16 @@ FROM
JOIN tx AS creator_tx ON creator_tx.id = gov_action_proposal.tx_id
JOIN block AS creator_block ON creator_block.id = creator_tx.block_id
LEFT JOIN voting_anchor ON voting_anchor.id = gov_action_proposal.voting_anchor_id
LEFT JOIN param_proposal as proposal_params ON gov_action_proposal.param_proposal = proposal_params.id
LEFT JOIN off_chain_vote_data ON off_chain_vote_data.voting_anchor_id = voting_anchor.id
LEFT JOIN off_chain_vote_gov_action_data ON off_chain_vote_gov_action_data.off_chain_vote_data_id = off_chain_vote_data.id
LEFT JOIN voting_procedure ON voting_procedure.gov_action_proposal_id = gov_action_proposal.id
LEFT JOIN LatestDrepDistr ldd ON ldd.hash_id = voting_procedure.drep_voter
AND ldd.rn = 1
LEFT JOIN LatestDrepDistr ldd_drep ON ldd_drep.hash_id = voting_procedure.drep_voter
AND ldd_drep.rn = 1
LEFT JOIN LatestDrepDistr ldd_pool ON ldd_pool.hash_id = voting_procedure.pool_voter
AND ldd_pool.rn = 1
LEFT JOIN LatestDrepDistr ldd_cc ON ldd_cc.hash_id = voting_procedure.committee_voter
AND ldd_cc.rn = 1
WHERE (NOT ?
OR (concat(encode(creator_tx.hash, 'hex'), '#', gov_action_proposal.index) IN ?))
AND gov_action_proposal.expiration >(
Expand All @@ -114,6 +126,7 @@ GROUP BY
epoch_utils.epoch_duration,
epoch_utils.last_epoch_no,
epoch_utils.last_epoch_end_time,
proposal_params,
voting_anchor.url,
voting_anchor.data_hash,
always_no_confidence_voting_power.amount,
Expand Down
37 changes: 27 additions & 10 deletions govtool/backend/src/VVA/API.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Data.Ord (Down (..))
import Data.Text hiding (any, drop, elem, filter, length, map, null, take)
import qualified Data.Text as Text
import qualified Data.Vector as V
import Data.Time.LocalTime (TimeZone, getCurrentTimeZone)


import Numeric.Natural (Natural)
Expand All @@ -44,6 +45,7 @@ import qualified VVA.Types as Types
import VVA.Types (App, AppEnv (..),
AppError (CriticalError, InternalError, ValidationError),
CacheEnv (..))
import Data.Time (TimeZone, localTimeToUTC)

type VVAApi =
"drep" :> "list"
Expand Down Expand Up @@ -179,27 +181,34 @@ getVotingPower (unHexText -> dRepId) = do
CacheEnv {dRepVotingPowerCache} <- asks vvaCache
cacheRequest dRepVotingPowerCache dRepId $ DRep.getVotingPower dRepId

proposalToResponse :: Types.Proposal -> ProposalResponse
proposalToResponse Types.Proposal {..} =
proposalToResponse :: TimeZone -> Types.Proposal -> ProposalResponse
proposalToResponse timeZone Types.Proposal {..} =
ProposalResponse
{ proposalResponseId = pack $ show proposalId,
proposalResponseTxHash = HexText proposalTxHash,
proposalResponseIndex = proposalIndex,
proposalResponseType = fromMaybe InfoAction $ readMaybe $ unpack proposalType,
proposalResponseDetails = GovernanceActionDetails <$> proposalDetails,
proposalResponseExpiryDate = proposalExpiryDate,
proposalResponseExpiryDate = localTimeToUTC timeZone <$> proposalExpiryDate,
proposalResponseExpiryEpochNo = proposalExpiryEpochNo,
proposalResponseCreatedDate = proposalCreatedDate,
proposalResponseCreatedDate = localTimeToUTC timeZone proposalCreatedDate,
proposalResponseCreatedEpochNo = proposalCreatedEpochNo,
proposalResponseUrl = proposalUrl,
proposalResponseMetadataHash = HexText proposalDocHash,
proposalResponseProtocolParams = ProtocolParams <$> proposalProtocolParams,
proposalResponseTitle = proposalTitle,
proposalResponseAbstract = proposalAbstract,
proposalResponseMotivation = proposalMotivation,
proposalResponseRationale = proposalRationale,
proposalResponseYesVotes = proposalYesVotes,
proposalResponseNoVotes = proposalNoVotes,
proposalResponseAbstainVotes = proposalAbstainVotes
proposalResponseDRepYesVotes = proposalDRepYesVotes,
proposalResponseDRepNoVotes = proposalDRepNoVotes,
proposalResponseDRepAbstainVotes = proposalDRepAbstainVotes,
proposalResponsePoolYesVotes = proposalPoolYesVotes,
proposalResponsePoolNoVotes = proposalPoolNoVotes,
proposalResponsePoolAbstainVotes = proposalPoolAbstainVotes,
proposalResponseCcYesVotes = proposalCcYesVotes,
proposalResponseCcNoVotes = proposalCcNoVotes,
proposalResponseCcAbstainVotes = proposalCcAbstainVotes
}

voteToResponse :: Types.Vote -> VoteParams
Expand All @@ -222,7 +231,9 @@ mapSortAndFilterProposals
-> [Types.Proposal]
-> m [ProposalResponse]
mapSortAndFilterProposals selectedTypes sortMode proposals = do
let mappedProposals = map proposalToResponse proposals
timeZone <- liftIO getCurrentTimeZone

let mappedProposals = map (proposalToResponse timeZone) proposals
let filteredProposals =
if null selectedTypes
then mappedProposals
Expand All @@ -232,11 +243,14 @@ mapSortAndFilterProposals selectedTypes sortMode proposals = do
proposalResponseType `elem` selectedTypes
)
mappedProposals

let totalYesVotes (ProposalResponse{..}) = proposalResponseDRepYesVotes + proposalResponsePoolYesVotes + proposalResponseCcYesVotes

let sortedProposals = case sortMode of
Nothing -> filteredProposals
Just NewestCreated -> sortOn (Down . proposalResponseCreatedDate) filteredProposals
Just SoonestToExpire -> sortOn proposalResponseExpiryDate filteredProposals
Just MostYesVotes -> sortOn (Down . proposalResponseYesVotes) filteredProposals
Just MostYesVotes -> sortOn (Down . totalYesVotes) filteredProposals
return sortedProposals

getVotes :: App m => HexText -> [GovernanceActionType] -> Maybe GovernanceActionSortMode -> Maybe Text -> m [VoteResponse]
Expand Down Expand Up @@ -346,7 +360,10 @@ getProposal g@(GovActionId govActionTxHash govActionIndex) mDrepId' = do
let mDrepId = unHexText <$> mDrepId'
CacheEnv {getProposalCache} <- asks vvaCache
proposal@Types.Proposal {proposalUrl, proposalDocHash} <- cacheRequest getProposalCache (unHexText govActionTxHash, govActionIndex) (Proposal.getProposal (unHexText govActionTxHash) govActionIndex)
let proposalResponse = proposalToResponse proposal

timeZone <- liftIO getCurrentTimeZone

let proposalResponse = proposalToResponse timeZone proposal
voteResponse <- case mDrepId of
Nothing -> return Nothing
Just drepId -> do
Expand Down
120 changes: 74 additions & 46 deletions govtool/backend/src/VVA/API/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,45 @@ instance ToSchema GovernanceActionMetadata where
?~ toJSON
("{\"some_key\": \"some value\", \"some_key2\": [1,2,3]}" :: Text)

newtype GetCurrentEpochParamsResponse
= GetCurrentEpochParamsResponse { getCurrentEpochParamsResponse :: Maybe Value }
deriving newtype (Show)

instance FromJSON GetCurrentEpochParamsResponse where
parseJSON = pure . GetCurrentEpochParamsResponse . Just

instance ToJSON GetCurrentEpochParamsResponse where
toJSON (GetCurrentEpochParamsResponse Nothing) = Null
toJSON (GetCurrentEpochParamsResponse (Just params)) = toJSON params

exampleGetCurrentEpochParamsResponse :: Text
exampleGetCurrentEpochParamsResponse =
"{ \"id\":90,\"epoch_no\":90,\"min_fee_a\":44,\"min_fee_b\":155381,\"max_block_size\":90112,\"max_tx_size\":16384,\"max_bh_size\":1100,\"key_deposit\":2000000,\"pool_deposit\":500000000,\"max_epoch\":18,\"optimal_pool_count\":5\r\n00,\"influence\":0.3,\"monetary_expand_rate\":0.003,\"treasury_growth_rate\":0.2,\"decentralisation\":0,\"protocol_major\":8,\"protocol_minor\":0,\"min_utxo_value\":0,\"min_pool_cost\":340000000,\"nonce\":\"\\\\x664c2d0eedc1c\r\n9ee7fc8b4f242c8d13ba17fd31454c84357fa8f1ac62f682cf9\",\"cost_model_id\":2,\"price_mem\":0.0577,\"price_step\":7.21e-05,\"max_tx_ex_mem\":14000000,\"max_tx_ex_steps\":10000000000,\"max_block_ex_mem\":62000000,\"max_bloc\r\nk_ex_steps\":20000000000,\"max_val_size\":5000,\"collateral_percent\":150,\"max_collateral_inputs\":3,\"block_id\":387943,\"extra_entropy\":null,\"coins_per_utxo_size\":4310}"

instance ToSchema GetCurrentEpochParamsResponse where
declareNamedSchema _ = pure $ NamedSchema (Just "GetCurrentEpochParamsResponse") $ mempty
& type_ ?~ OpenApiObject
& description ?~ "Protocol parameters encoded as JSON"
& example
?~ toJSON exampleGetCurrentEpochParamsResponse


newtype ProtocolParams
= ProtocolParams { getProtocolParams :: Value }
deriving newtype (Show)

instance FromJSON ProtocolParams where
parseJSON = pure . ProtocolParams

instance ToJSON ProtocolParams where
toJSON (ProtocolParams params) = toJSON params

instance ToSchema ProtocolParams where
declareNamedSchema _ = pure $ NamedSchema (Just "ProtocolParams") $ mempty
& type_ ?~ OpenApiObject
& description ?~ "Protocol parameters encoded as JSON"
& example
?~ toJSON exampleGetCurrentEpochParamsResponse


newtype GovernanceActionReferences
Expand All @@ -435,28 +474,33 @@ instance ToSchema GovernanceActionReferences where
?~ toJSON
("[{\"uri\": \"google.com\", \"@type\": \"Other\", \"label\": \"example label\"}]" :: Text)



data ProposalResponse
= ProposalResponse
{ proposalResponseId :: Text
, proposalResponseTxHash :: HexText
, proposalResponseIndex :: Integer
, proposalResponseType :: GovernanceActionType
, proposalResponseDetails :: Maybe GovernanceActionDetails
, proposalResponseExpiryDate :: Maybe UTCTime
, proposalResponseExpiryEpochNo :: Maybe Integer
, proposalResponseCreatedDate :: UTCTime
, proposalResponseCreatedEpochNo :: Integer
, proposalResponseUrl :: Text
, proposalResponseMetadataHash :: HexText
, proposalResponseTitle :: Maybe Text
, proposalResponseAbstract :: Maybe Text
, proposalResponseMotivation :: Maybe Text
, proposalResponseRationale :: Maybe Text
, proposalResponseYesVotes :: Integer
, proposalResponseNoVotes :: Integer
, proposalResponseAbstainVotes :: Integer
{ proposalResponseId :: Text
, proposalResponseTxHash :: HexText
, proposalResponseIndex :: Integer
, proposalResponseType :: GovernanceActionType
, proposalResponseDetails :: Maybe GovernanceActionDetails
, proposalResponseExpiryDate :: Maybe UTCTime
, proposalResponseExpiryEpochNo :: Maybe Integer
, proposalResponseCreatedDate :: UTCTime
, proposalResponseCreatedEpochNo :: Integer
, proposalResponseUrl :: Text
, proposalResponseMetadataHash :: HexText
, proposalResponseProtocolParams :: Maybe ProtocolParams
, proposalResponseTitle :: Maybe Text
, proposalResponseAbstract :: Maybe Text
, proposalResponseMotivation :: Maybe Text
, proposalResponseRationale :: Maybe Text
, proposalResponseDRepYesVotes :: Integer
, proposalResponseDRepNoVotes :: Integer
, proposalResponseDRepAbstainVotes :: Integer
, proposalResponsePoolYesVotes :: Integer
, proposalResponsePoolNoVotes :: Integer
, proposalResponsePoolAbstainVotes :: Integer
, proposalResponseCcYesVotes :: Integer
, proposalResponseCcNoVotes :: Integer
, proposalResponseCcAbstainVotes :: Integer
}
deriving (Generic, Show)

Expand All @@ -474,13 +518,20 @@ exampleProposalResponse = "{ \"id\": \"proposalId123\","
<> "\"createdEpochNo\": 0,"
<> "\"url\": \"https://proposal.metadata.xyz\","
<> "\"metadataHash\": \"9af10e89979e51b8cdc827c963124a1ef4920d1253eef34a1d5cfe76438e3f11\","
<> "\"protocolParams\": " <> exampleGetCurrentEpochParamsResponse <> ","
<> "\"title\": \"Proposal Title\","
<> "\"abstract\": \"Proposal About\","
<> "\"motivation\": \"Proposal Motivation\","
<> "\"rationale\": \"Proposal Rationale\","
<> "\"yesVotes\": 0,"
<> "\"noVotes\": 0,"
<> "\"abstainVotes\": 0}"
<> "\"dRepYesVotes\": 0,"
<> "\"dRepNoVotes\": 0,"
<> "\"dRepAbstainVotes\": 0,"
<> "\"poolYesVotes\": 0,"
<> "\"poolNoVotes\": 0,"
<> "\"poolAbstainVotes\": 0,"
<> "\"cCYesVotes\": 0,"
<> "\"cCNoVotes\": 0,"
<> "\"cCAbstainVotes\": 0}"

instance ToSchema ProposalResponse where
declareNamedSchema proxy = do
Expand Down Expand Up @@ -679,29 +730,6 @@ instance ToSchema GetProposalResponse where
& example
?~ toJSON exampleGetProposalResponse


newtype GetCurrentEpochParamsResponse
= GetCurrentEpochParamsResponse { getCurrentEpochParamsResponse :: Maybe Value }
deriving newtype (Show)

instance FromJSON GetCurrentEpochParamsResponse where
parseJSON = pure . GetCurrentEpochParamsResponse . Just

instance ToJSON GetCurrentEpochParamsResponse where
toJSON (GetCurrentEpochParamsResponse Nothing) = Null
toJSON (GetCurrentEpochParamsResponse (Just params)) = toJSON params

exampleGetCurrentEpochParamsResponse :: Text
exampleGetCurrentEpochParamsResponse =
"{ \"id\":90,\"epoch_no\":90,\"min_fee_a\":44,\"min_fee_b\":155381,\"max_block_size\":90112,\"max_tx_size\":16384,\"max_bh_size\":1100,\"key_deposit\":2000000,\"pool_deposit\":500000000,\"max_epoch\":18,\"optimal_pool_count\":5\r\n00,\"influence\":0.3,\"monetary_expand_rate\":0.003,\"treasury_growth_rate\":0.2,\"decentralisation\":0,\"protocol_major\":8,\"protocol_minor\":0,\"min_utxo_value\":0,\"min_pool_cost\":340000000,\"nonce\":\"\\\\x664c2d0eedc1c\r\n9ee7fc8b4f242c8d13ba17fd31454c84357fa8f1ac62f682cf9\",\"cost_model_id\":2,\"price_mem\":0.0577,\"price_step\":7.21e-05,\"max_tx_ex_mem\":14000000,\"max_tx_ex_steps\":10000000000,\"max_block_ex_mem\":62000000,\"max_bloc\r\nk_ex_steps\":20000000000,\"max_val_size\":5000,\"collateral_percent\":150,\"max_collateral_inputs\":3,\"block_id\":387943,\"extra_entropy\":null,\"coins_per_utxo_size\":4310}"

instance ToSchema GetCurrentEpochParamsResponse where
declareNamedSchema _ = pure $ NamedSchema (Just "GetCurrentEpochParamsResponse") $ mempty
& type_ ?~ OpenApiObject
& description ?~ "Protocol parameters encoded as JSON"
& example
?~ toJSON exampleGetCurrentEpochParamsResponse

newtype GetTransactionStatusResponse
= GetTransactionStatusResponse { getTransactionstatusResponseTransactionConfirmed :: Bool }
deriving (Generic, Show)
Expand Down
50 changes: 2 additions & 48 deletions govtool/backend/src/VVA/Proposal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -64,53 +64,7 @@ getProposals ::
(Has ConnectionPool r, Has VVAConfig r, MonadReader r m, MonadIO m, MonadFail m, MonadError AppError m) =>
Maybe [Text] ->
m [Proposal]
getProposals mProposalIds = withPool $ \conn -> do
proposalResults <- liftIO $ case mProposalIds of
getProposals mProposalIds = withPool $ \conn ->
liftIO $ case mProposalIds of
Nothing -> SQL.query @(Bool, SQL.In [Text]) conn listProposalsSql (False, SQL.In [])
Just proposalIds -> SQL.query conn listProposalsSql (True, SQL.In proposalIds)

timeZone <- liftIO getCurrentTimeZone
return $ map
( \( id'
, txHash'
, index'
, type'
, details'
, expiryDate'
, expiryEpochNo'
, createdDate'
, createdEpochNo'
, url'
, docHash'
, title'
, about'
, motivation'
, rationale'
, yesVotes'
, noVotes'
, abstainVotes'
) ->
let eDate = localTimeToUTC timeZone <$> expiryDate'
cDate = localTimeToUTC timeZone createdDate'
in
Proposal
id'
txHash'
(floor @Scientific index')
type'
details'
eDate
expiryEpochNo'
cDate
createdEpochNo'
url'
docHash'
title'
about'
motivation'
rationale'
(floor @Scientific yesVotes')
(floor @Scientific noVotes')
(floor @Scientific abstainVotes')
)
proposalResults
Loading

0 comments on commit 7d7c1d6

Please sign in to comment.