Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: tenderly enactment simulation #134

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ CSP_REPORT_ONLY=

# api endpoint for reporting csp violations
CSP_REPORT_URI=

# tenderly credentials
TENDERLY_USER=
TENDERLY_PROJECT=
TENDERLY_ACCESS_KEY=
1 change: 1 addition & 0 deletions assets/tenderly.com.svg.react
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 281 279" fill="none"><path fill="#9573F5" d="m205.106 81.829 75.449-42.027.062 81.655-58.449 32.554c-39.867 22.209-62.84 51.338-72.125 77.205-9.282 25.857-7.917 40.686-8.215 47.149 0-41.167.135-53.478.135-88.14 0-8.541.982-17.937 2.134-22.435 0 0 9.923-57.503 61.009-85.961Z"/><path fill="#6837F1" d="m141.794 192.002.039 86.363-71.381-39.651-.031-66.903C70.4 126.178 56.118 91.938 38.03 71.246 19.947 50.563 6.33 44.313.828 40.908c35.626 19.119 45.05 24.276 75.43 40.597 7.526 4.042 17.324 11.736 20.692 14.93 0 0 44.818 37.09 44.843 95.567Z"/><path fill="#D2C3FB" d="M204.987 81.829c30.455-16.733 52.576-29.276 75.565-42.027-5.792 2.924-18.149 11.434-45.413 16.072-27.274 4.64-65.612 3.64-105.119-20.243L72.102.616.829 40.918l77.925 41.825c19.41 11.65 67.867 31.153 126.233-.914Z"/></svg>
5 changes: 5 additions & 0 deletions examples/sample.env-develop.env
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ CSP_REPORT_ONLY=

# api endpoint for reporting csp violations
CSP_REPORT_URI=

# tenderly credentials
TENDERLY_USER=
TENDERLY_PROJECT=
TENDERLY_ACCESS_KEY=
5 changes: 5 additions & 0 deletions examples/sample.env-production.env
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ CSP_REPORT_ONLY=

# api endpoint for reporting csp violations
CSP_REPORT_URI=

# tenderly credentials
TENDERLY_USER=
TENDERLY_PROJECT=
TENDERLY_ACCESS_KEY=
5 changes: 5 additions & 0 deletions examples/sample.env-staging.env
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ CSP_REPORT_ONLY=

# api endpoint for reporting csp violations
CSP_REPORT_URI=

# tenderly credentials
TENDERLY_USER=
TENDERLY_PROJECT=
TENDERLY_ACCESS_KEY=
14 changes: 4 additions & 10 deletions modules/dashboard/ui/DashboardVote/DashboardVote.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useCallback } from 'react'
import { useVotePassedCallback } from 'modules/votes/hooks/useVotePassedCallback'
import { useVoteDetailsFormatted } from 'modules/votes/hooks/useVoteDetailsFormatted'

import Link from 'next/link'
import { VoteStatusBanner } from 'modules/votes/ui/VoteStatusBanner'
Expand All @@ -17,9 +18,6 @@ import {
} from './DashboardVoteStyle'
import type { StartVoteEventObject } from 'generated/AragonVotingAbi'
import { Vote, VoteStatus } from 'modules/votes/types'
import { weiToNum } from 'modules/blockChain/utils/parseWei'
import { getVoteDetailsFormatted } from 'modules/votes/utils/getVoteDetailsFormatted'
import { formatFloatPct } from 'modules/shared/utils/formatFloatPct'
import * as urls from 'modules/network/utils/urls'

type Props = {
Expand All @@ -44,12 +42,13 @@ export function DashboardVote({
const {
nayPct,
yeaPct,
yeaPctOfTotalSupply,
nayPctOfTotalSupplyFormatted,
yeaPctOfTotalSupplyFormatted,
neededToQuorum,
neededToQuorumFormatted,
startDate,
endDate,
} = getVoteDetailsFormatted({ vote, voteTime })
} = useVoteDetailsFormatted({ vote, voteTime })! // we are sure that we have non-undefined `vote` and `voteTime` here

const handlePass = useCallback(() => {
// TODO:
Expand All @@ -72,11 +71,6 @@ export function DashboardVote({
onPass: handlePass,
})

const neededToQuorum = weiToNum(vote.minAcceptQuorum) - yeaPctOfTotalSupply
const neededToQuorumFormatted = formatFloatPct(neededToQuorum, {
floor: true,
}).toFixed(2)

const isEnded =
status === VoteStatus.Rejected || status === VoteStatus.Executed

Expand Down
7 changes: 6 additions & 1 deletion modules/shared/metrics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { buildInfo } from './buildInfo'
import { chainInfo } from './chainInfo'
import { METRICS_PREFIX } from './constants'
import { contractInfo } from './contractInfo'
import { rpcResponseTime, etherscanResponseTime } from './responseTime'
import {
rpcResponseTime,
etherscanResponseTime,
tenderlyResponseTime,
} from './responseTime'

const registry = new Registry()

Expand All @@ -13,6 +17,7 @@ if (process.env.NODE_ENV === 'production') {
registry.registerMetric(contractInfo)
registry.registerMetric(rpcResponseTime)
registry.registerMetric(etherscanResponseTime)
registry.registerMetric(tenderlyResponseTime)

collectDefaultMetrics({ prefix: METRICS_PREFIX, register: registry })
}
Expand Down
8 changes: 8 additions & 0 deletions modules/shared/metrics/responseTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,11 @@ export const etherscanResponseTime = new Histogram({
labelNames: ['chainId'],
registers: [],
})

export const tenderlyResponseTime = new Histogram({
name: METRICS_PREFIX + 'tenderly_response',
help: 'Tenderly response times',
labelNames: [],
buckets: [0.1, 0.2, 0.3, 0.6, 1, 1.5, 2, 5],
registers: [],
})
14 changes: 14 additions & 0 deletions modules/votes/hooks/useVoteDetailsFormatted.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useMemo } from 'react'
import { getVoteDetailsFormatted } from '../utils/getVoteDetailsFormatted'

type Args = Partial<Parameters<typeof getVoteDetailsFormatted>[0]>

export const useVoteDetailsFormatted = ({ vote, voteTime }: Args) => {
return useMemo(
() =>
vote && voteTime
? getVoteDetailsFormatted({ vote, voteTime })
: undefined,
[vote, voteTime],
)
}
6 changes: 4 additions & 2 deletions modules/votes/ui/VoteDetails/VoteDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { VoteDescription } from '../VoteDescription'
import { Vote, VoteStatus } from 'modules/votes/types'
import { weiToNum } from 'modules/blockChain/utils/parseWei'
import { formatNumber } from 'modules/shared/utils/formatNumber'
import { getVoteDetailsFormatted } from 'modules/votes/utils/getVoteDetailsFormatted'
import type { getVoteDetailsFormatted } from 'modules/votes/utils/getVoteDetailsFormatted'

type Props = {
vote: Vote
Expand All @@ -32,6 +32,7 @@ type Props = {
metadata?: string
isEnded: boolean
executedTxHash?: string
voteDetailsFormatted: ReturnType<typeof getVoteDetailsFormatted>
}

export function VoteDetails({
Expand All @@ -44,6 +45,7 @@ export function VoteDetails({
metadata = '',
isEnded,
executedTxHash,
voteDetailsFormatted,
}: Props) {
const {
totalSupplyFormatted,
Expand All @@ -55,7 +57,7 @@ export function VoteDetails({
yeaPctOfTotalSupplyFormatted,
startDate,
endDate,
} = getVoteDetailsFormatted({ vote, voteTime })
} = voteDetailsFormatted

return (
<>
Expand Down
42 changes: 37 additions & 5 deletions modules/votes/ui/VoteForm/VoteForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ import { VoteFormVoterState } from '../VoteFormVoterState'
import { VoteVotersList } from '../VoteVotersList'
import { Desc, ClearButton } from './VoteFormStyle'
import { FetchErrorBanner } from 'modules/shared/ui/Common/FetchErrorBanner'
import { VoteSimulation } from '../VoteSimulation'
import { DetailsBoxWrap } from '../VoteDetails/VoteDetailsStyle'

import { VoteStatus } from 'modules/votes/types'
import { isVoteEnactable } from 'modules/votes/utils/isVoteEnactable'

type Props = {
voteId?: string
Expand All @@ -39,14 +42,21 @@ export function VoteForm({ voteId }: Props) {
eventsVoted,
eventExecuteVote,
status,
voteDetailsFormatted,
} = useFormVoteInfo({ voteId })
const { clearVoteId } = useVotePrompt()

const { txVote, txEnact, handleVote, handleEnact, isSubmitting } =
useFormVoteSubmit({
voteId,
onFinish: doRevalidate,
})
const {
txVote,
txEnact,
handleVote,
populateEnact,
handleEnact,
isSubmitting,
} = useFormVoteSubmit({
voteId,
onFinish: doRevalidate,
})

useVotePassedCallback({
startDate,
Expand All @@ -67,6 +77,15 @@ export function VoteForm({ voteId }: Props) {
const isEmpty = !voteId
const isNotFound = swrVote.error?.reason === 'VOTING_NO_VOTE'
const isFound = !isEmpty && !isNotFound && !isLoading && vote && status
const isEnactmentStillPossible =
vote &&
voteDetailsFormatted &&
isVoteEnactable(vote) &&
!isEnded &&
!(
status !== VoteStatus.ActiveMain &&
voteDetailsFormatted.neededToQuorum > 0
)

return (
<Container as="main" size="tight" key={voteId}>
Expand Down Expand Up @@ -118,8 +137,21 @@ export function VoteForm({ voteId }: Props) {
creator={eventStart?.creator}
metadata={eventStart?.metadata}
executedTxHash={eventExecuteVote?.event.transactionHash}
voteDetailsFormatted={voteDetailsFormatted!}
/>

{isEnactmentStillPossible && (
<DetailsBoxWrap>
<VoteSimulation
voteId={voteId}
vote={vote}
voteTime={voteTime}
objectionPhaseTime={objectionPhaseTime}
populateEnact={populateEnact}
/>
</DetailsBoxWrap>
)}

{!isWalletConnected && <VoteFormMustConnect />}

{isWalletConnected && (
Expand Down
7 changes: 7 additions & 0 deletions modules/votes/ui/VoteForm/useFormVoteInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useCallback, useEffect } from 'react'
import { useSWR } from 'modules/network/hooks/useSwr'
import { useWeb3 } from 'modules/blockChain/hooks/useWeb3'
import { useConfig } from 'modules/config/hooks/useConfig'
import { useVoteDetailsFormatted } from 'modules/votes/hooks/useVoteDetailsFormatted'

import {
ContractVoting,
Expand Down Expand Up @@ -125,6 +126,11 @@ export function useFormVoteInfo({ voteId }: Args) {
}
}, [doRevalidate, contractVoting, voteId])

const voteDetailsFormatted = useVoteDetailsFormatted({
vote,
voteTime,
})

return {
swrVote,
vote,
Expand All @@ -142,5 +148,6 @@ export function useFormVoteInfo({ voteId }: Args) {
eventsVoted: swrVote.data?.eventsVoted,
eventExecuteVote: swrVote.data?.eventExecuteVote,
status: swrVote.data?.status,
voteDetailsFormatted,
}
}
28 changes: 13 additions & 15 deletions modules/votes/ui/VoteForm/useFormVoteSubmit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,17 @@ export function useFormVoteSubmit({ voteId, onFinish }: Args) {
[voteId, txVote],
)

const populateEnact = useCallback(
async (args: { voteId: string }) => {
const gasLimit = await estimateGasFallback(
contractVoting.estimateGas.executeVote(args.voteId),
2000000,
)
const tx = await contractVoting.populateTransaction.executeVote(
args.voteId,
{ gasLimit },
)
return tx
},
[contractVoting],
)
const populateEnact = useCallback(async () => {
if (!voteId) throw new Error('voteId is required')
const gasLimit = await estimateGasFallback(
contractVoting.estimateGas.executeVote(voteId),
2000000,
)
const tx = await contractVoting.populateTransaction.executeVote(voteId, {
gasLimit,
})
return tx
}, [voteId, contractVoting])
const txEnact = useTransactionSender(populateEnact, {
onError: handleError,
onFinish: handleFinish,
Expand All @@ -91,7 +88,7 @@ export function useFormVoteSubmit({ voteId, onFinish }: Args) {
if (!voteId) return
try {
setSubmitting('enact')
await txEnact.send({ voteId })
await txEnact.send()
} catch (err) {
console.error(err)
setSubmitting(false)
Expand All @@ -104,5 +101,6 @@ export function useFormVoteSubmit({ voteId, onFinish }: Args) {
handleVote,
handleEnact,
isSubmitting,
populateEnact,
}
}
Loading