diff --git a/packages/protocol-dashboard/.circleci/config.yml b/packages/protocol-dashboard/.circleci/config.yml index 4e5c05e5dd8..c3b1827acc3 100644 --- a/packages/protocol-dashboard/.circleci/config.yml +++ b/packages/protocol-dashboard/.circleci/config.yml @@ -50,13 +50,12 @@ jobs: at: ./ - run: name: build - command: npm run build:staging + command: npm run build:stage - persist_to_workspace: root: ./ paths: - build - deploy-staging: working_directory: ~/protocol-dashboard docker: @@ -87,7 +86,6 @@ jobs: paths: - build - deploy-prod: working_directory: ~/protocol-dashboard docker: @@ -136,4 +134,3 @@ workflows: filters: branches: only: /^main$/ - diff --git a/packages/protocol-dashboard/.env.staging b/packages/protocol-dashboard/.env.stage similarity index 100% rename from packages/protocol-dashboard/.env.staging rename to packages/protocol-dashboard/.env.stage diff --git a/packages/protocol-dashboard/.gitignore b/packages/protocol-dashboard/.gitignore index 509652774a4..a7a4efe64ab 100644 --- a/packages/protocol-dashboard/.gitignore +++ b/packages/protocol-dashboard/.gitignore @@ -28,3 +28,5 @@ yarn-error.log* *.swp *.swo *.swn + +.vscode/** \ No newline at end of file diff --git a/packages/protocol-dashboard/.prettierrc.json b/packages/protocol-dashboard/.prettierrc.json new file mode 100644 index 00000000000..fd496a820ea --- /dev/null +++ b/packages/protocol-dashboard/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "semi": false +} diff --git a/packages/protocol-dashboard/package.json b/packages/protocol-dashboard/package.json index b3bc53c5326..feaa72b6e25 100644 --- a/packages/protocol-dashboard/package.json +++ b/packages/protocol-dashboard/package.json @@ -35,11 +35,11 @@ "publish-scripts": "./scripts/publishScripts.sh", "configure-local-env": "node ./configureLocalEnv.js", "start": "react-scripts start", - "start:development": "npm run configure-local-env && npm start", - "start:staging": "env-cmd -f .env.staging npm start", + "start:dev": "npm run configure-local-env && npm start", + "start:stage": "env-cmd -f .env.stage npm start", "start:prod": "env-cmd -f .env.prod npm start", "build": "react-scripts build", - "build:staging": "env-cmd -f .env.staging npm run build", + "build:stage": "env-cmd -f .env.stage npm run build", "build:prod": "env-cmd -f .env.prod npm run build", "test": "react-scripts test", "eject": "react-scripts eject", diff --git a/packages/protocol-dashboard/src/components/ConfirmTransactionModal/ConfirmTransactionModal.tsx b/packages/protocol-dashboard/src/components/ConfirmTransactionModal/ConfirmTransactionModal.tsx index 9579c053e29..310ffe51ee0 100644 --- a/packages/protocol-dashboard/src/components/ConfirmTransactionModal/ConfirmTransactionModal.tsx +++ b/packages/protocol-dashboard/src/components/ConfirmTransactionModal/ConfirmTransactionModal.tsx @@ -1,6 +1,7 @@ import React, { ReactNode } from 'react' import clsx from 'clsx' import SimpleBar from 'simplebar-react' +import BN from 'bn.js' import AudiusClient from 'services/Audius' import { IconArrow, ButtonType } from '@audius/stems' @@ -87,7 +88,7 @@ type OldStakeProps = { className?: string title: string oldStakeAmount: BigNumber - stakeDiff: BigNumber + stakeDiff: BigNumber | null isIncrease: boolean } export const OldStake: React.FC = props => { @@ -106,7 +107,7 @@ export const OldStake: React.FC = props => { })} > {`${props.isIncrease ? '+' : '-'} ${AudiusClient.displayAud( - props.stakeDiff + props.stakeDiff ?? new BN('0') )}`} diff --git a/packages/protocol-dashboard/src/components/Timeline/TimelineEvent.tsx b/packages/protocol-dashboard/src/components/Timeline/TimelineEvent.tsx index 3b54fc6d667..be2973b3552 100644 --- a/packages/protocol-dashboard/src/components/Timeline/TimelineEvent.tsx +++ b/packages/protocol-dashboard/src/components/Timeline/TimelineEvent.tsx @@ -1,7 +1,6 @@ import React, { ReactNode } from 'react' import clsx from 'clsx' -import { ProposalEvent, VoteEvent, Vote, Event } from 'types' import { useProposal } from 'store/cache/proposals/hooks' import Proposal from 'components/Proposal' import { useBlock } from 'store/cache/protocol/hooks' @@ -19,22 +18,33 @@ import Tooltip, { Position } from 'components/Tooltip' import desktopStyles from './TimelineEvent.module.css' import mobileStyles from './TimelineEventMobile.module.css' import { createStyles } from 'utils/mobile' -import { TimelineType } from 'store/cache/timeline/hooks' +import { + ClaimProcessedEvent, + DelegateClaimEvent, + DelegateDecreaseStakeEvent, + DelegateIncreaseStakeEvent, + GovernanceProposalEvent, + GovernanceVoteEvent, + GovernanceVoteUpdateEvent, + ServiceProviderDecreaseStakeEvent, + ServiceProviderDeregisteredEvent, + ServiceProviderIncreaseStakeEvent, + ServiceProviderRegisteredEvent, + TimelineEvent as TimelineEventType +} from 'models/TimelineEvents' const styles = createStyles({ desktopStyles, mobileStyles }) const VoteTimelineEvent = ({ className, - proposalId, - vote, - onClick + onClick, + event }: { className?: string - proposalId: number - vote: Vote onClick?: () => void + event: GovernanceVoteEvent | GovernanceVoteUpdateEvent }) => { - const { proposal } = useProposal(proposalId) + const { proposal } = useProposal(event.proposalId) const header = 'VOTED' return proposal ? ( ) : null } const ProposalTimelineEvent = ({ - proposalId, + event, className, onClick }: { - proposalId: number + event: GovernanceProposalEvent className?: string onClick?: () => void }) => { - const { proposal } = useProposal(proposalId) + const { proposal } = useProposal(event.proposalId) const header = 'PROPOSED' if (proposal) { const modified = { @@ -108,345 +118,351 @@ const GenericTimelineEvent = ({ ) } -type OwnProps = { +const DelegationIncreaseEvent: React.FC<{ + event: DelegateIncreaseStakeEvent + parentOnClick?: () => void + pushRoute: ReturnType className?: string - onClick?: () => void - event: ProposalEvent | VoteEvent | Event -} +}> = ({ event, pushRoute, className, parentOnClick }) => { + const received = event.direction === 'Received' -type TimelineEventProps = OwnProps + const onClick = () => { + if (parentOnClick) parentOnClick() + pushRoute(accountPage(received ? event.delegator : event.serviceProvider)) + } -const TimelineEvent: React.FC = ({ - onClick: parentOnClick, - className, - event -}: TimelineEventProps) => { - const pushRoute = usePushRoute() + const header = received ? 'DELEGATION' : 'DELEGATED' + const title = ( + + {received ? `Received` : `Delegated`} + + {formatAud(event.increaseAmount)} + + {`${TICKER} ${received ? 'from' : 'to'} `} + + {formatShortWallet(received ? event.delegator : event.serviceProvider)} + + + ) + return ( + + ) +} - if (!event) return null +const DelegationDecreaseEvent: React.FC<{ + event: DelegateDecreaseStakeEvent + parentOnClick?: () => void + pushRoute: ReturnType + className?: string +}> = ({ event, pushRoute, className, parentOnClick }) => { + const onClick = () => { + if (parentOnClick) parentOnClick() + const route = + event.direction === 'Sent' + ? operatorPage(event.serviceProvider) + : accountPage(event.delegator) + pushRoute(route) + } - if ('voter' in event) { + // Text looks like + // Evaluated: + // Delegator: Decreased delegation X Audio To SP Y + // SP: Delegator X decreased delegation by Y Audio + // Requested: + // Delegator: Requested to decrease delegation to SP Y by X Audio + // SP: Delegator X requested to decrease delegation by Y Audio + // Cancelled: + // Delegator: Cancelled request to decrease delegation To SP Y by X Audio' + // SP: Delegator X cancelled requested to decrease delegation by Y Audio + + const renderRequestSent = () => { return ( - + <> + {`Requested to decrease delegation to`} + + {formatShortWallet(event.serviceProvider)} + + {' by'} + + {formatAud(event.amount)} + + {TICKER} + ) } - if ('proposer' in event) { + const renderRequestReceived = () => { return ( - + <> + {`Delegator`} + + ${formatShortWallet(event.delegator)} + + + {`requested to decrease delegation by`} + + + {formatAud(event.amount)} + + {TICKER} + ) } - // Handle increase delegation events - if ( - 'delegator' in event && - 'increaseAmount' in event && - 'direction' in event - ) { - const received = event.direction === 'RECEIVED' - - const onClick = () => { - if (parentOnClick) parentOnClick() - pushRoute(accountPage(received ? event.delegator : event.serviceProvider)) - } - - const header = received ? 'DELEGATION' : 'DELEGATED' - const title = ( - - {received ? `Received` : `Delegated`} + const renderEvaluatedSent = () => { + return ( + <> + {`Decreased delegation`} - {formatAud(event.increaseAmount)} + {formatAud(event.amount)} - {`${TICKER} ${received ? 'from' : 'to'} `} + {`${TICKER} to `} - {formatShortWallet( - received ? event.delegator : event.serviceProvider - )} + {formatShortWallet(event.serviceProvider)} - + ) + } + + const renderEvaluatedReceived = () => { return ( - + <> + {`Delegator`} + + ${formatShortWallet(event.delegator)} + + + {'decreased delegation by'} + + + {formatAud(event.amount)} + + {TICKER} + ) } - // Handle decrease events - if ('decreaseDelegation' in event) { - const stage: 'cancelled' | 'requested' | 'evaluated' = event.stage - const userType: TimelineType = event.userType - - // headers indexed by stage + userType - const headersMap = { - evaluated: { - Delegator: 'UNDELEGATED', - ServiceProvider: 'UNDELEGATION' - }, - cancelled: { - Delegator: 'UNDELEGATE REQUEST CANCELLED', - ServiceProvider: 'UNDELEGATION REQUEST CANCELLED' - }, - requested: { - Delegator: 'UNDELEGATE REQUESTED', - ServiceProvider: 'UNDELEGATION REQUESTED' - } - } - - const onClick = () => { - if (parentOnClick) parentOnClick() - const route = - userType === 'Delegator' - ? operatorPage(event.serviceProvider) - : accountPage(event.delegator) - pushRoute(route) - } - - // Text looks like - // Evaluated: - // Delegator: Decreased delegation X Audio To SP Y - // SP: Delegator X decreased delegation by Y Audio - // Requested: - // Delegator: Requested to decrease delegation to SP Y by X Audio - // SP: Delegator X requested to decrease delegation by Y Audio - // Cancelled: - // Delegator: Cancelled request to decrease delegation To SP Y by X Audio' - // SP: Delegator X cancelled requested to decrease delegation by Y Audio - - const bodyMap = { - evaluated: { - Delegator: ( - <> - {`Decreased delegation`} - - {formatAud(event.decreaseAmount)} - - {`${TICKER} to `} - - {formatShortWallet(event.serviceProvider)} - - - ), - ServiceProvider: ( - <> - {`Delegator`} - - ${formatShortWallet(event.delegator)} - - - {'decreased delegation by'} - - - {formatAud(event.amount)} - - {TICKER} - - ) - }, - cancelled: { - Delegator: ( - <> - {`Cancelled request to decrease delegation to`} - - {formatShortWallet(event.serviceProvider)} - - {'by'} - - {formatAud(event.amount)} - - {TICKER} - - ), - ServiceProvider: ( - <> - {`Delegator ${formatShortWallet( - event.delegator - )} cancelled request to decrease delegation by`} - - {formatAud(event.amount)} - - {TICKER} - - ) - }, - requested: { - Delegator: ( - <> - {`Requested to decrease delegation to`} - - {formatShortWallet(event.serviceProvider)} - - {' by'} - - {formatAud(event.amount)} - - {TICKER} - - ), - ServiceProvider: ( - <> - {`Delegator`} - - ${formatShortWallet(event.delegator)} - - - {`requested to decrease delegation by`} - - - {formatAud(event.amount)} - - {TICKER} - - ) - } - } - - const header = headersMap[stage][userType] - const title = ( - {bodyMap[stage][userType]} - ) + const renderCancelledSent = () => { return ( - + <> + {`Cancelled request to decrease delegation to`} + + {formatShortWallet(event.serviceProvider)} + + {'by'} + + {formatAud(event.amount)} + + {TICKER} + ) } - if ('registrationAction' in event) { - // did it register or deregister? - const didRegister = event.registrationAction === 'register' - - // is it discovery-node or creator-node - const isDiscovery = - event.serviceType in ['discovery-node', 'discovery-provider'] - const onClick = () => { - if (parentOnClick) parentOnClick() - const route = isDiscovery - ? discoveryNodePage(event.spID) - : contentNodePage(event.spID) - pushRoute(route) - } - const header = didRegister ? 'REGISTERED SERVICE' : 'DEREGISTERED SERVICE' - const title = ( - - {`${didRegister ? 'Registered' : 'Deregistered'} ${ - event.serviceType - } at ${event.endpoint}`} - - ) + const renderCancelledReceived = () => { return ( - + <> + {`Delegator ${formatShortWallet( + event.delegator + )} cancelled request to decrease delegation by`} + + {formatAud(event.amount)} + + {TICKER} + ) } - // SPs: staking increase + decrease events - // stake actions can be - // increases, decreases requested/evaluated/(eventually cancelled) - if ('stakeAction' in event) { - const action: - | 'increase' - | 'decreaseRequested' - | 'decreaseEvaluated' - | 'decreaseCancelled' = event.stakeAction - - const onClick = () => { - if (parentOnClick) parentOnClick() - // do nothing for stake actions + const headersMap = { + Evaluated: { + Sent: 'UNDELEGATED', + Received: 'UNDELEGATION' + }, + Cancelled: { + Sent: 'UNDELEGATE REQUEST CANCELLED', + Received: 'UNDELEGATION REQUEST CANCELLED' + }, + Requested: { + Sent: 'UNDELEGATE REQUESTED', + Received: 'UNDELEGATION REQUESTED' } + } - const headerMap = { - increase: 'INCREASED STAKE', - decreaseRequested: 'REQUESTED STAKE DECREASE', - decreaseEvaluated: 'DECREASED STAKE', - decreaseCancelled: 'CANCELLED DECREASE STAKE REQUEST' - } - const header = headerMap[action] + const bodyMap = { + Requested: { Sent: renderRequestSent, Received: renderRequestReceived }, + Evaluated: { Sent: renderEvaluatedSent, Received: renderEvaluatedReceived }, + Cancelled: { Sent: renderCancelledSent, Received: renderCancelledReceived } + } - const sentenceFragmentMap1 = { - increase: 'Increased', - decreaseRequested: 'Requested to decrease', - decreaseEvaluated: 'Decreased', - decreaseCancelled: 'Cancelled request to decrease' - } - const sentenceFragment1 = sentenceFragmentMap1[action] + const header = headersMap[event.data._type][event.direction] + const body = bodyMap[event.data._type][event.direction]() + const title = {body} + return ( + + ) +} - const amount = - action === 'increase' ? event.increaseAmount : event.decreaseAmount +const RegistrationDeregistrationEvent: React.FC<{ + parentOnClick?: () => void + pushRoute: ReturnType + event: ServiceProviderRegisteredEvent | ServiceProviderDeregisteredEvent + className?: string +}> = ({ event, parentOnClick, pushRoute, className }) => { + const didRegister = event._type === 'ServiceProviderRegistered' + + // is it discovery-node or creator-node + const isDiscovery = + event.serviceType in ['discovery-node', 'discovery-provider'] + const onClick = () => { + if (parentOnClick) parentOnClick() + const route = isDiscovery + ? discoveryNodePage(event.spID) + : contentNodePage(event.spID) + pushRoute(route) + } + const header = didRegister ? 'REGISTERED SERVICE' : 'DEREGISTERED SERVICE' + const title = ( + + {`${didRegister ? 'Registered' : 'Deregistered'} ${ + event.serviceType + } at ${event.endpoint}`} + + ) + return ( + + ) +} +const ClaimEvent: React.FC<{ + parentOnClick?: () => void + event: DelegateClaimEvent | ClaimProcessedEvent + pushRoute: ReturnType + className?: string +}> = ({ event, parentOnClick, className, pushRoute }) => { + const onClick = () => { + if (parentOnClick) parentOnClick() + pushRoute(accountPage(event.claimer)) + } + const header = 'CLAIMED' + const title = ( + + + {formatShortWallet(event.claimer)} + + {` Claims`} + + {formatAud(event.rewards)} + + {` ${TICKER}`} + + ) + return ( + + ) +} - const title = ( +const ServiceProviderStakeEvent: React.FC<{ + parentOnClick?: () => void + event: ServiceProviderIncreaseStakeEvent | ServiceProviderDecreaseStakeEvent + className?: string +}> = ({ event, parentOnClick, className }) => { + const onClick = () => { + if (parentOnClick) parentOnClick() + // do nothing for stake actions + } + + const decreaseStakeHeaders = { + Requested: 'REQUESTED STAKE DECREASE', + Evaluated: 'DECREASED STAKE', + Cancelled: 'CANCELLED DECREASE STAKE REQUEST' + } + const header = + event._type === 'ServiceProviderIncreaseStake' + ? 'INCREASED STAKE' + : decreaseStakeHeaders[event.data._type] + + const sentenceFragmentMap1 = { + Requested: 'Requested to decrease', + Evaluated: 'Decreased', + Cancelled: 'Cancelled request to decrease' + } + const sentenceFragment1 = + event._type === 'ServiceProviderIncreaseStake' + ? 'Increased' + : sentenceFragmentMap1[event.data._type] + + const amount = + event._type === 'ServiceProviderIncreaseStake' + ? event.increaseAmount + : event.decreaseAmount + + const renderTitle = () => { + let newAmount = null + if (event._type === 'ServiceProviderIncreaseStake') { + newAmount = event.newStakeAmount + } else if (event.data._type === 'Evaluated') { + newAmount = event.data.newStakeAmount + } + + return ( {`${sentenceFragment1} stake by`} = ({ > {formatAud(amount)} - {action === 'increase' || action === 'decreaseEvaluated' ? ( + {newAmount ? ( <> {'to'} - {formatAud(event.newStakeAmount)} + {formatAud(newAmount)} {TICKER} @@ -476,48 +492,105 @@ const TimelineEvent: React.FC = ({ )} ) - return ( - - ) } - if ('claimer' in event && 'rewards' in event) { - const onClick = () => { - if (parentOnClick) parentOnClick() - pushRoute(accountPage(event.claimer)) - } - const header = 'CLAIMED' - const title = ( - - - {formatShortWallet(event.claimer)} - - {` Claims`} - - {formatAud(event.rewards)} - - {` ${TICKER}`} - - ) - return ( - - ) + return ( + + ) +} + +type OwnProps = { + className?: string + onClick?: () => void + event: TimelineEventType +} + +type TimelineEventProps = OwnProps + +const TimelineEvent: React.FC = ({ + onClick: parentOnClick, + className, + event +}: TimelineEventProps) => { + const pushRoute = usePushRoute() + + if (!event) return null + + switch (event._type) { + // Governance + case 'GovernanceVote': + case 'GovernanceVoteUpdate': + return ( + + ) + case 'GovernanceProposal': + return ( + + ) + + // Delegation + case 'DelegateIncreaseStake': + return ( + + ) + case 'DelegateDecreaseStake': + return ( + + ) + + // SP + case 'ServiceProviderRegistered': + case 'ServiceProviderDeregistered': + return ( + + ) + case 'ServiceProviderIncreaseStake': + case 'ServiceProviderDecreaseStake': + return ( + + ) + + // Claim + case 'DelegateClaim': + case 'ClaimProcessed': + return ( + + ) } return ( diff --git a/packages/protocol-dashboard/src/components/Timeline/TimelineModal.tsx b/packages/protocol-dashboard/src/components/Timeline/TimelineModal.tsx index 0aeacf10500..b8323c61b2c 100644 --- a/packages/protocol-dashboard/src/components/Timeline/TimelineModal.tsx +++ b/packages/protocol-dashboard/src/components/Timeline/TimelineModal.tsx @@ -5,9 +5,7 @@ import SimpleBar from 'simplebar-react' import styles from './TimelineModal.module.css' import Modal from 'components/Modal' import TimelineEvent from './TimelineEvent' -import { ProposalEvent, VoteEvent, Event } from 'types' - -type TimelineEvent = ProposalEvent | VoteEvent | Event +import { TimelineEvent as TimelineEventType } from 'models/TimelineEvents' const messages = { title: 'Timeline' @@ -17,7 +15,7 @@ type OwnProps = { className?: string isOpen: boolean onClose: () => void - events: Array + events: TimelineEventType[] } type TimelineModalProps = OwnProps diff --git a/packages/protocol-dashboard/src/components/TopAddressesTable/TopAddressesTable.tsx b/packages/protocol-dashboard/src/components/TopAddressesTable/TopAddressesTable.tsx index 37920fc14e8..5ff85acfa00 100644 --- a/packages/protocol-dashboard/src/components/TopAddressesTable/TopAddressesTable.tsx +++ b/packages/protocol-dashboard/src/components/TopAddressesTable/TopAddressesTable.tsx @@ -10,7 +10,7 @@ import Tooltip from 'components/Tooltip' import { formatShortWallet, formatWeight, formatWei } from 'utils/format' import { useUsers } from 'store/cache/user/hooks' -import { Status } from 'types' +import { Address, Status } from 'types' import { usePushRoute } from 'utils/effects' import { useIsMobile } from 'utils/hooks' import getActiveStake from 'utils/activeStake' @@ -23,9 +23,9 @@ const messages = { type TableUser = { rank: number img: string - name: string - wallet: string - staked: number + name?: string + wallet: Address + staked: BN voteWeight: number proposedVotes: number } @@ -70,7 +70,7 @@ const TopAddressesTable: React.FC = ({ return total.add(activeStake) }, new BN('0')) - const data = users + const data: TableUser[] = users .map((user, idx) => { const activeStake = getActiveStake(user) const voteWeight = Audius.getBNPercentage( diff --git a/packages/protocol-dashboard/src/components/TopOperatorsTable/TopOperatorsTable.tsx b/packages/protocol-dashboard/src/components/TopOperatorsTable/TopOperatorsTable.tsx index 0eb86c5b071..9db2c3d00e5 100644 --- a/packages/protocol-dashboard/src/components/TopOperatorsTable/TopOperatorsTable.tsx +++ b/packages/protocol-dashboard/src/components/TopOperatorsTable/TopOperatorsTable.tsx @@ -9,10 +9,11 @@ import Tooltip from 'components/Tooltip' import { formatShortWallet, formatWei } from 'utils/format' import { useUsers } from 'store/cache/user/hooks' -import { Operator, Status } from 'types' +import { Address, Operator, Status } from 'types' import { usePushRoute } from 'utils/effects' import { useIsMobile } from 'utils/hooks' import getActiveStake, { getTotalActiveDelegatedStake } from 'utils/activeStake' +import BN from 'bn.js' const messages = { topAddresses: 'Top Service Operators by Active Stake', @@ -22,9 +23,9 @@ const messages = { type TableUser = { rank: number img: string - name: string - wallet: string - staked: number + name?: string + wallet: Address + staked: BN voteWeight: number proposedVotes: number } diff --git a/packages/protocol-dashboard/src/components/ValueSlider/ValueSlider.tsx b/packages/protocol-dashboard/src/components/ValueSlider/ValueSlider.tsx index bdbd8f55f61..c272def67ae 100644 --- a/packages/protocol-dashboard/src/components/ValueSlider/ValueSlider.tsx +++ b/packages/protocol-dashboard/src/components/ValueSlider/ValueSlider.tsx @@ -49,7 +49,7 @@ const ValueSlider: React.FC = ({ const [sliderWidth, setSliderWidth] = useState(0) useEffect(() => { - if (containerRef.current) { + if (containerRef.current && min && max) { const percentage = AudiusClient.getBNPercentage( value.sub(min), max.sub(min) @@ -61,7 +61,13 @@ const ValueSlider: React.FC = ({ }, [value, containerRef, max, min, setSliderWidth]) useEffect(() => { - if (initialValue && !initialSliderWidth && containerRef.current) { + if ( + initialValue && + !initialSliderWidth && + containerRef.current && + min && + max + ) { const percentage = AudiusClient.getBNPercentage( initialValue.sub(min), max.sub(min) @@ -87,7 +93,8 @@ const ValueSlider: React.FC = ({
- > { + ): Promise { await this.aud.hasPermissions() - const info = await this.getContract().getClaimProcessedEvents({ - claimer - }) - return info + const info: GetClaimProcessedResponse[] = await this.getContract().getClaimProcessedEvents( + { + claimer + } + ) + return info.map(e => ({ + ...e, + _type: 'ClaimProcessed' + })) } } diff --git a/packages/protocol-dashboard/src/services/Audius/claim/types.ts b/packages/protocol-dashboard/src/services/Audius/claim/types.ts new file mode 100644 index 00000000000..f874d3d0c66 --- /dev/null +++ b/packages/protocol-dashboard/src/services/Audius/claim/types.ts @@ -0,0 +1,10 @@ +import { Address } from 'types' +import BN from 'bn.js' + +export type GetClaimProcessedResponse = { + blockNumber: number + claimer: Address + rewards: BN + oldTotal: BN + newTotal: BN +} diff --git a/packages/protocol-dashboard/src/services/Audius/delegate.ts b/packages/protocol-dashboard/src/services/Audius/delegate/delegate.ts similarity index 63% rename from packages/protocol-dashboard/src/services/Audius/delegate.ts rename to packages/protocol-dashboard/src/services/Audius/delegate/delegate.ts index 432e63828c4..d52493349bf 100644 --- a/packages/protocol-dashboard/src/services/Audius/delegate.ts +++ b/packages/protocol-dashboard/src/services/Audius/delegate/delegate.ts @@ -1,54 +1,33 @@ -import { AudiusClient } from './AudiusClient' +import { AudiusClient } from '../AudiusClient' import BN from 'bn.js' +import { Address, Amount, BlockNumber, TxReceipt, Permission } from 'types' import { - Address, - Amount, - BlockNumber, - TxReceipt, - Permission, - BigNumber -} from 'types' + DelegateClaimEvent, + DelegateDecreaseStakeEvent, + DelegateIncreaseStakeEvent, + DelegateRemovedEvent, + DelegateSlashEvent +} from 'models/TimelineEvents' +import { + GetClaimEventsResponse, + GetDelegatorRemovedEventsResponse, + GetDelegatorsListResponse, + GetSlashEventsResponse, + GetDecreaseDelegateStakeCancelledEventsResponse, + GetDecreaseDelegateStakeEvaluatedResponse, + GetDecreaseDelegateStakeRequestedResponse, + GetIncreaseDelegateStakeEventsResponse, + GetPendingUndelegateRequestResponse, + UndelegateStakeResponse, + RemoveDelegatorResponse +} from './types' export type DelegateStakeResponse = { txReceipt: TxReceipt tokenApproveReceipt: { txReceipt: TxReceipt } delegator: Address serviceProvider: Address - increaseAmount: BigNumber -} - -export type UndelegateStakeResponse = { - delegator: Address - serviceProvider: Address - decreaseAmount: BigNumber -} - -export type RemoveDelegatorResponse = { - delegator: Address - serviceProvider: Address - unstakedAmount: BigNumber -} - -export type GetDelegatorsListResponse = Array
- -export type GetPendingUndelegateRequestResponse = { - amount: BigNumber - lockupExpiryBlock: BlockNumber - target: Address -} - -export type IncreaseDelegateStakeEvent = { - blockNumber: number - delegator: Address increaseAmount: BN - serviceProvider: Address -} - -export type DecreaseDelegateStakeEvent = { - blockNumber: number - delegator: Address - decreaseAmount: BN - serviceProvider: Address } export default class Delegate { @@ -74,7 +53,7 @@ export default class Delegate { async getTotalDelegatedToServiceProvider( serviceProvider: Address - ): Promise { + ): Promise { await this.aud.hasPermissions() const info = await this.getContract().getTotalDelegatedToServiceProvider( serviceProvider @@ -82,7 +61,7 @@ export default class Delegate { return info } - async getTotalDelegatorStake(delegator: Address): Promise { + async getTotalDelegatorStake(delegator: Address): Promise { await this.aud.hasPermissions() const info = await this.getContract().getTotalDelegatorStake(delegator) return info @@ -90,7 +69,7 @@ export default class Delegate { async getTotalLockedDelegationForServiceProvider( serviceProvider: Address - ): Promise { + ): Promise { await this.aud.hasPermissions() const info = await this.getContract().getTotalLockedDelegationForServiceProvider( serviceProvider @@ -101,7 +80,7 @@ export default class Delegate { async getDelegatorStakeForServiceProvider( delegator: Address, serviceProvider: Address - ): Promise { + ): Promise { await this.aud.hasPermissions() const info = await this.getContract().getDelegatorStakeForServiceProvider( delegator, @@ -142,7 +121,7 @@ export default class Delegate { return info } - async getMinDelegationAmount(): Promise { + async getMinDelegationAmount(): Promise { await this.aud.hasPermissions() const info = await this.getContract().getMinDelegationAmount() return info @@ -178,46 +157,52 @@ export default class Delegate { return info } - async getIncreaseDelegateStakeEvents( - delegator: Address - ): Promise> { - await this.aud.hasPermissions() - const info = await this.getContract().getIncreaseDelegateStakeEvents({ - delegator - }) - return info.map((i: any) => ({ ...i, direction: 'SENT' })) - } - - async getReceiveDelegationIncreaseEvents( - serviceProvider: Address - ): Promise> { + async getIncreaseDelegateStakeEvents({ + delegator, + serviceProvider + }: { + delegator?: Address + serviceProvider?: Address + }): Promise { await this.aud.hasPermissions() - const info = await this.getContract().getIncreaseDelegateStakeEvents({ - serviceProvider - }) - return info.map((i: any) => ({ ...i, direction: 'RECEIVED' })) + const info: GetIncreaseDelegateStakeEventsResponse[] = await this.getContract().getIncreaseDelegateStakeEvents( + { + delegator, + serviceProvider + } + ) + return info.map(event => ({ + ...event, + _type: 'DelegateIncreaseStake', + direction: delegator ? 'Sent' : 'Received' + })) } /* Can filter either by delegator or SP */ - async getDecreaseDelegateStakeEvents({ + async getDecreaseDelegateStakeEvaluatedEvents({ delegator, serviceProvider }: { delegator?: Address serviceProvider?: Address - }) { + }): Promise { await this.aud.hasPermissions() - const info: DecreaseDelegateStakeEvent[] = await this.getContract().getDecreaseDelegateStakeEvents( + const info: GetDecreaseDelegateStakeEvaluatedResponse[] = await this.getContract().getDecreaseDelegateStakeEvents( { delegator, serviceProvider } ) - return info.map((event: any) => ({ - ...event, - decreaseDelegation: true, - stage: 'evaluated', - userType: delegator ? 'Delegator' : 'ServiceProvider' + return info.map(event => ({ + _type: 'DelegateDecreaseStake', + direction: delegator ? 'Sent' : 'Received', + blockNumber: event.blockNumber, + delegator: event.delegator, + amount: event.amount, + serviceProvider: event.serviceProvider, + data: { + _type: 'Evaluated' + } })) } @@ -228,17 +213,25 @@ export default class Delegate { }: { serviceProvider?: Address delegator?: Address - }): Promise> { + }): Promise { await this.aud.hasPermissions() - const info = await this.getContract().getUndelegateStakeRequestedEvents({ - serviceProvider, - delegator - }) - return info.map((event: any) => ({ - ...event, - decreaseDelegation: true, - stage: 'requested', - userType: delegator ? 'Delegator' : 'ServiceProvider' + const info: GetDecreaseDelegateStakeRequestedResponse[] = await this.getContract().getUndelegateStakeRequestedEvents( + { + serviceProvider, + delegator + } + ) + return info.map(event => ({ + _type: 'DelegateDecreaseStake', + direction: delegator ? 'Sent' : 'Received', + blockNumber: event.blockNumber, + delegator: event.delegator, + amount: event.amount, + serviceProvider: event.serviceProvider, + data: { + _type: 'Requested', + lockupExpiryBlock: event.lockupExpiryBlock + } })) } @@ -249,69 +242,66 @@ export default class Delegate { }: { serviceProvider?: Address delegator?: Address - }): Promise> { + }): Promise { await this.aud.hasPermissions() - const info = await this.getContract().getUndelegateStakeCancelledEvents({ - serviceProvider, - delegator - }) - return info.map((event: any) => ({ - ...event, - decreaseDelegation: true, - stage: 'cancelled', - userType: delegator ? 'Delegator' : 'ServiceProvider' + const info: GetDecreaseDelegateStakeCancelledEventsResponse[] = await this.getContract().getUndelegateStakeCancelledEvents( + { + serviceProvider, + delegator + } + ) + return info.map(event => ({ + _type: 'DelegateDecreaseStake', + direction: delegator ? 'Sent' : 'Received', + blockNumber: event.blockNumber, + delegator: event.delegator, + amount: event.amount, + serviceProvider: event.serviceProvider, + data: { + _type: 'Cancelled' + } })) } - async getClaimEvents( - claimer: Address - ): Promise< - Array<{ - blockNumber: number - claimer: Address - rewards: BN - newTotal: BN - }> - > { + async getClaimEvents(claimer: Address): Promise { await this.aud.hasPermissions() - const info = await this.getContract().getClaimEvents({ - claimer - }) - return info + const info: GetClaimEventsResponse[] = await this.getContract().getClaimEvents( + { + claimer + } + ) + return info.map(event => ({ + ...event, + _type: 'DelegateClaim' + })) } - async getSlashEvents( - target: Address - ): Promise< - Array<{ - blockNumber: number - target: Address - amount: BN - newTotal: BN - }> - > { + async getSlashEvents(target: Address): Promise { await this.aud.hasPermissions() - const info = await this.getContract().getSlashEvents({ - target - }) - return info + const info: GetSlashEventsResponse[] = await this.getContract().getSlashEvents( + { + target + } + ) + return info.map(event => ({ + ...event, + _type: 'DelegateSlash' + })) } async getDelegatorRemovedEvents( delegator: Address - ): Promise< - Array<{ - blockNumber: number - serviceProvider: Address - delegator: Address - unstakedAmount: BN - }> - > { + ): Promise { await this.aud.hasPermissions() - const info = await this.getContract().getDecreaseDelegateStakeEvents({ - delegator - }) - return info + const info: GetDelegatorRemovedEventsResponse[] = await this.getContract().getDecreaseDelegateStakeEvents( + { + delegator + } + ) + return info.map(e => ({ + ...e, + _type: 'DelegateRemoved' + })) } /* -------------------- Delegate Manager Client Write -------------------- */ diff --git a/packages/protocol-dashboard/src/services/Audius/delegate/types.ts b/packages/protocol-dashboard/src/services/Audius/delegate/types.ts new file mode 100644 index 00000000000..56eab0a2fbe --- /dev/null +++ b/packages/protocol-dashboard/src/services/Audius/delegate/types.ts @@ -0,0 +1,74 @@ +import BN from 'bn.js' +import { Address, BlockNumber } from 'types' + +export type UndelegateStakeResponse = { + delegator: Address + serviceProvider: Address + decreaseAmount: BN +} + +export type RemoveDelegatorResponse = { + delegator: Address + serviceProvider: Address + unstakedAmount: BN +} + +export type GetDelegatorsListResponse = Array
+ +export type GetPendingUndelegateRequestResponse = { + amount: BN + lockupExpiryBlock: BlockNumber + target: Address +} + +export type GetIncreaseDelegateStakeEventsResponse = { + blockNumber: number + delegator: Address + increaseAmount: BN + serviceProvider: Address +} + +export type GetDecreaseDelegateStakeEvaluatedResponse = { + blockNumber: number + delegator: Address + amount: BN + serviceProvider: Address +} + +export type GetDecreaseDelegateStakeRequestedResponse = { + blockNumber: number + lockupExpiryBlock: number + delegator: Address + amount: BN + serviceProvider: Address +} + +export type GetDecreaseDelegateStakeCancelledEventsResponse = { + blockNumber: number + delegator: Address + amount: BN + serviceProvider: Address +} + +// Events + +export type GetClaimEventsResponse = { + blockNumber: number + claimer: Address + rewards: BN + newTotal: BN +} + +export type GetSlashEventsResponse = { + blockNumber: number + target: Address + amount: BN + newTotal: BN +} + +export type GetDelegatorRemovedEventsResponse = { + blockNumber: number + serviceProvider: Address + delegator: Address + unstakedAmount: BN +} diff --git a/packages/protocol-dashboard/src/services/Audius/governance.ts b/packages/protocol-dashboard/src/services/Audius/governance/governance.ts similarity index 87% rename from packages/protocol-dashboard/src/services/Audius/governance.ts rename to packages/protocol-dashboard/src/services/Audius/governance/governance.ts index b257f243e29..26b78bf1c29 100644 --- a/packages/protocol-dashboard/src/services/Audius/governance.ts +++ b/packages/protocol-dashboard/src/services/Audius/governance/governance.ts @@ -1,4 +1,4 @@ -import { AudiusClient } from './AudiusClient' +import { AudiusClient } from '../AudiusClient' import BN from 'bn.js' @@ -11,24 +11,16 @@ import { VoteEvent, Permission, ProposalEvent -} from '../../types' +} from '../../../types' +import { + GovernanceProposalEvent, + GovernanceVoteEvent, + GovernanceVoteUpdateEvent +} from 'models/TimelineEvents' +import { RawProposal, RawVoteEvent } from './types' /* Types */ -/** - * Raw unformatted Proposal returned over the wire. - */ -export type RawProposal = Omit & { - outcome: number -} - -/** - * Raw unformatted VoteEvent returned over the wire. - */ -export type RawVoteEvent = Omit & { - vote: 1 | 2 -} - export default class Governance { public aud: AudiusClient @@ -148,6 +140,17 @@ export default class Governance { return votes.map(formatVoteEvent).filter(Boolean) as VoteEvent[] } + async getVoteEventsByAddress( + addresses: Address[], + queryStartBlock?: number + ): Promise { + const votes = await this.getVotesByAddress(addresses, queryStartBlock) + return votes.map(v => ({ + ...v, + _type: 'GovernanceVote' + })) + } + /** Gets all vote update events on any proposal by addresses */ async getVoteUpdatesByAddress( addresses: Address[], @@ -160,6 +163,17 @@ export default class Governance { return votes.map(formatVoteEvent).filter(Boolean) as VoteEvent[] } + async getVoteUpdateEventsByAddress( + addresses: Address[], + queryStartBlock?: number + ): Promise { + const votes = await this.getVoteUpdatesByAddress(addresses, queryStartBlock) + return votes.map(v => ({ + ...v, + _type: 'GovernanceVoteUpdate' + })) + } + async getProposals() { await this.aud.hasPermissions() const proposals = await this.getContract().getProposals() @@ -175,13 +189,16 @@ export default class Governance { async getProposalsForAddresses( addresses: Address[], queryStartBlock?: number - ) { + ): Promise { await this.aud.hasPermissions() - const proposals = await this.getContract().getProposalsForAddresses( + const proposals: ProposalEvent[] = await this.getContract().getProposalsForAddresses( addresses, queryStartBlock ) - return proposals + return proposals.map(p => ({ + ...p, + _type: 'GovernanceProposal' + })) } /* -------------------- Governance Write -------------------- */ diff --git a/packages/protocol-dashboard/src/services/Audius/governance/types.ts b/packages/protocol-dashboard/src/services/Audius/governance/types.ts new file mode 100644 index 00000000000..0b0f450d400 --- /dev/null +++ b/packages/protocol-dashboard/src/services/Audius/governance/types.ts @@ -0,0 +1,15 @@ +import { Proposal, VoteEvent } from 'types' + +/** + * Raw unformatted Proposal returned over the wire. + */ +export type RawProposal = Omit & { + outcome: number +} + +/** + * Raw unformatted VoteEvent returned over the wire. + */ +export type RawVoteEvent = Omit & { + vote: 1 | 2 +} diff --git a/packages/protocol-dashboard/src/services/Audius/helpers.ts b/packages/protocol-dashboard/src/services/Audius/helpers.ts index f0a29a63719..2c15034f89e 100644 --- a/packages/protocol-dashboard/src/services/Audius/helpers.ts +++ b/packages/protocol-dashboard/src/services/Audius/helpers.ts @@ -3,6 +3,7 @@ import { formatNumber, formatAudString } from 'utils/format' import AudiusClient from './AudiusClient' import { Permission, BigNumber } from 'types' import { fetchWithTimeout } from 'utils/fetch' +import BN from 'bn.js' // Helpers export async function hasPermissions( @@ -87,7 +88,7 @@ export function getBNPercentage(n1: BigNumber, n2: BigNumber): number { } export function displayShortAud(amount: BigNumber) { - return formatNumber(amount.div(Utils.toBN('1000000000000000000'))) + return formatNumber(amount.div(Utils.toBN('1000000000000000000') as BN)) } export function displayAud(amount: BigNumber) { diff --git a/packages/protocol-dashboard/src/services/Audius/serviceProviderClient.ts b/packages/protocol-dashboard/src/services/Audius/service-provider/serviceProviderClient.ts similarity index 71% rename from packages/protocol-dashboard/src/services/Audius/serviceProviderClient.ts rename to packages/protocol-dashboard/src/services/Audius/service-provider/serviceProviderClient.ts index 8377fbddf16..a600c42dde7 100644 --- a/packages/protocol-dashboard/src/services/Audius/serviceProviderClient.ts +++ b/packages/protocol-dashboard/src/services/Audius/service-provider/serviceProviderClient.ts @@ -1,5 +1,4 @@ -import { AudiusClient } from './AudiusClient' -import BN from 'bn.js' +import { AudiusClient } from '../AudiusClient' import { ServiceType, @@ -8,41 +7,33 @@ import { BlockNumber, ServiceProvider, TxReceipt, - TokenApproveReceipt, Node, Permission, Wallet } from 'types' - -export type NodeList = Array -export type GetServiceProviderIdsFromAddressResponse = Array -export type GetPendingDecreaseStakeRequestResponse = { - lockupExpiryBlock: BlockNumber - amount: BN -} -export type GetServiceEndpointInfoFromAddressResponse = NodeList -export type GetServiceProviderListResponse = NodeList -export type DeregisterResponse = { - txReceipt: TxReceipt - spID: number - serviceType: ServiceType - owner: Address - endpoint: string -} -export type RegisterResponse = { - txReceipt: TxReceipt - spID: number - serviceType: ServiceType - owner: Address - endpoint: string - tokenApproveReceipt: any -} -export type RegisterWithDelegateResponse = RegisterResponse -export type IncreaseStakeResponse = { - txReceipt: TxReceipt - tokenApproveReceipt: TokenApproveReceipt -} -export type DecreaseStakeResponse = { txReceipt: TxReceipt } +import { + GetDecreasedStakeCancelledEventsResponse, + GetDecreasedStakeEvaluatedEventsResponse, + GetDecreasedStakeRequestedEventsResponse, + GetIncreasedStakeEventResponse, + GetDeregisteredServiceProviderEventsResponse, + GetPendingDecreaseStakeRequestResponse, + GetRegisteredServiceProviderEventsResponse, + GetServiceEndpointInfoFromAddressResponse, + GetServiceProviderIdsFromAddressResponse, + GetServiceProviderListResponse, + RegisterWithDelegateResponse, + RegisterResponse, + IncreaseStakeResponse, + DecreaseStakeResponse, + DeregisterResponse +} from './types' +import { + ServiceProviderDecreaseStakeEvent, + ServiceProviderDeregisteredEvent, + ServiceProviderIncreaseStakeEvent, + ServiceProviderRegisteredEvent +} from '../../../models/TimelineEvents' export default class ServiceProviderClient { aud: AudiusClient @@ -208,71 +199,109 @@ export default class ServiceProviderClient { return info } - async getRegisteredServiceProviderEvents(wallet: Address): Promise { + async getRegisteredServiceProviderEvents( + wallet: Address + ): Promise { await this.aud.hasPermissions() - const events = await this.getContract().getRegisteredServiceProviderEvents({ - owner: wallet - }) - return events.map((event: any) => ({ + const events: GetRegisteredServiceProviderEventsResponse[] = await this.getContract().getRegisteredServiceProviderEvents( + { + owner: wallet + } + ) + return events.map(event => ({ ...event, - registrationAction: 'register' + _type: 'ServiceProviderRegistered' })) } - async getDeregisteredServiceProviderEvents(wallet: Address): Promise { + async getDeregisteredServiceProviderEvents( + wallet: Address + ): Promise { await this.aud.hasPermissions() - const events = await this.getContract().getDeregisteredServiceProviderEvents( + const events: GetDeregisteredServiceProviderEventsResponse[] = await this.getContract().getDeregisteredServiceProviderEvents( { owner: wallet } ) - return events.map((event: any) => ({ + return events.map(event => ({ ...event, - registrationAction: 'deregister' + _type: 'ServiceProviderDeregistered' })) } - async getIncreasedStakeEvents(wallet: Address): Promise { + async getIncreasedStakeEvents( + wallet: Address + ): Promise { await this.aud.hasPermissions() - const events = await this.getContract().getIncreasedStakeEvents({ - owner: wallet - }) - return events.map((event: any) => ({ + const events: GetIncreasedStakeEventResponse[] = await this.getContract().getIncreasedStakeEvents( + { + owner: wallet + } + ) + return events.map(event => ({ ...event, - stakeAction: 'increase' + _type: 'ServiceProviderIncreaseStake' })) } - async getDecreasedStakeEvaluatedEvents(wallet: Address): Promise { + async getDecreasedStakeEvaluatedEvents( + wallet: Address + ): Promise { await this.aud.hasPermissions() - const events = await this.getContract().getDecreasedStakeEvaluatedEvents({ - owner: wallet - }) - return events.map((event: any) => ({ - ...event, - stakeAction: 'decreaseEvaluated' + const events: GetDecreasedStakeEvaluatedEventsResponse[] = await this.getContract().getDecreasedStakeEvaluatedEvents( + { + owner: wallet + } + ) + return events.map(event => ({ + _type: 'ServiceProviderDecreaseStake', + blockNumber: event.blockNumber, + owner: event.owner, + decreaseAmount: event.decreaseAmount, + data: { + newStakeAmount: event.newStakeAmount, + _type: 'Evaluated' + } })) } - async getDecreasedStakeRequestedEvents(wallet: Address): Promise { + async getDecreasedStakeRequestedEvents( + wallet: Address + ): Promise { await this.aud.hasPermissions() - const events = await this.getContract().getDecreasedStakeRequestedEvents({ - owner: wallet - }) - return events.map((event: any) => ({ - ...event, - stakeAction: 'decreaseRequested' + const events: GetDecreasedStakeRequestedEventsResponse[] = await this.getContract().getDecreasedStakeRequestedEvents( + { + owner: wallet + } + ) + return events.map(event => ({ + _type: 'ServiceProviderDecreaseStake', + blockNumber: event.blockNumber, + owner: event.owner, + decreaseAmount: event.decreaseAmount, + data: { + lockupExpiryBlock: event.lockupExpiryBlock, + _type: 'Requested' + } })) } async getDecreasedStakeCancelledEvents(wallet: Address): Promise { await this.aud.hasPermissions() - const events = await this.getContract().getDecreasedStakeCancelledEvents({ - owner: wallet - }) - return events.map((event: any) => ({ - ...event, - stakeAction: 'decreaseCancelled' + const events: GetDecreasedStakeCancelledEventsResponse[] = await this.getContract().getDecreasedStakeCancelledEvents( + { + owner: wallet + } + ) + return events.map(event => ({ + _type: 'ServiceProviderDecreaseStake', + blockNumber: event.blockNumber, + owner: event.owner, + decreaseAmount: event.decreaseAmount, + data: { + lockupExpiryBlock: event.lockupExpiryBlock, + _type: 'Cancelled' + } })) } diff --git a/packages/protocol-dashboard/src/services/Audius/service-provider/types.ts b/packages/protocol-dashboard/src/services/Audius/service-provider/types.ts new file mode 100644 index 00000000000..bf0ef3ae6c2 --- /dev/null +++ b/packages/protocol-dashboard/src/services/Audius/service-provider/types.ts @@ -0,0 +1,87 @@ +import { + Address, + BlockNumber, + Node, + ServiceType, + TokenApproveReceipt, + TxReceipt +} from 'types' +import BN from 'bn.js' + +export type NodeList = Array +export type GetServiceProviderIdsFromAddressResponse = Array +export type GetPendingDecreaseStakeRequestResponse = { + lockupExpiryBlock: BlockNumber + amount: BN +} +export type GetServiceEndpointInfoFromAddressResponse = NodeList +export type GetServiceProviderListResponse = NodeList +export type DeregisterResponse = { + txReceipt: TxReceipt + spID: number + serviceType: ServiceType + owner: Address + endpoint: string +} +export type RegisterResponse = { + txReceipt: TxReceipt + spID: number + serviceType: ServiceType + owner: Address + endpoint: string + tokenApproveReceipt: any +} +export type RegisterWithDelegateResponse = RegisterResponse +export type IncreaseStakeResponse = { + txReceipt: TxReceipt + tokenApproveReceipt: TokenApproveReceipt +} +export type DecreaseStakeResponse = { txReceipt: TxReceipt } + +/* Event Types */ + +export type GetRegisteredServiceProviderEventsResponse = { + blockNumber: number + spID: number + serviceType: string + owner: Address + endpoint: string + stakeAmount: BN +} + +export type GetDeregisteredServiceProviderEventsResponse = { + blockNumber: number + spID: number + serviceType: string + owner: Address + endpoint: string + stakeAmount: BN +} + +export type GetIncreasedStakeEventResponse = { + blockNumber: number + owner: Address + increaseAmount: BN + newStakeAmount: BN +} + +export type GetDecreasedStakeEvaluatedEventsResponse = { + blockNumber: number + owner: Address + decreaseAmount: BN + newStakeAmount: BN +} + +export type GetDecreasedStakeRequestedEventsResponse = { + blockNumber: number + owner: Address + decreaseAmount: BN + lockupExpiryBlock: number +} + +export type GetDecreasedStakeCancelledEventsResponse = { + blockNumber: number + owner: Address + decreaseAmount: BN + lockupExpiryBlock: number +} diff --git a/packages/protocol-dashboard/src/services/Audius/staking.ts b/packages/protocol-dashboard/src/services/Audius/staking/staking.ts similarity index 97% rename from packages/protocol-dashboard/src/services/Audius/staking.ts rename to packages/protocol-dashboard/src/services/Audius/staking/staking.ts index c5af69da6da..0ccc11f3669 100644 --- a/packages/protocol-dashboard/src/services/Audius/staking.ts +++ b/packages/protocol-dashboard/src/services/Audius/staking/staking.ts @@ -1,5 +1,5 @@ import BN from 'bn.js' -import { AudiusClient } from './AudiusClient' +import { AudiusClient } from '../AudiusClient' import { Address, BlockNumber } from 'types' diff --git a/packages/protocol-dashboard/src/services/Audius/audiusToken.ts b/packages/protocol-dashboard/src/services/Audius/token/audiusToken.ts similarity index 89% rename from packages/protocol-dashboard/src/services/Audius/audiusToken.ts rename to packages/protocol-dashboard/src/services/Audius/token/audiusToken.ts index 7bcd50f941f..73372604b9d 100644 --- a/packages/protocol-dashboard/src/services/Audius/audiusToken.ts +++ b/packages/protocol-dashboard/src/services/Audius/token/audiusToken.ts @@ -1,4 +1,4 @@ -import { AudiusClient } from './AudiusClient' +import { AudiusClient } from '../AudiusClient' import { Address, BigNumber } from 'types' diff --git a/packages/protocol-dashboard/src/services/Audius/wrappers.ts b/packages/protocol-dashboard/src/services/Audius/wrappers.ts index 28ca5040839..2f3e703ae93 100644 --- a/packages/protocol-dashboard/src/services/Audius/wrappers.ts +++ b/packages/protocol-dashboard/src/services/Audius/wrappers.ts @@ -17,7 +17,9 @@ export async function getUserDelegates(this: AudiusClient, delegator: Address) { await this.hasPermissions() const delegates = [] const increaseDelegateStakeEvents = await this.Delegate.getIncreaseDelegateStakeEvents( - delegator + { + delegator + } ) const pendingUndelegateRequest = await this.Delegate.getPendingUndelegateRequest( delegator diff --git a/packages/protocol-dashboard/src/store/cache/timeline/hooks.ts b/packages/protocol-dashboard/src/store/cache/timeline/hooks.ts index 1f76ef6f8b1..642ca6e404c 100644 --- a/packages/protocol-dashboard/src/store/cache/timeline/hooks.ts +++ b/packages/protocol-dashboard/src/store/cache/timeline/hooks.ts @@ -8,8 +8,9 @@ import { useEffect } from 'react' import { setTimeline } from './slice' import { Address } from 'types' import { useDispatchBasedOnBlockNumber } from '../protocol/hooks' +import { TimelineEvent } from 'models/TimelineEvents' -const getFirstEvent = (...events: Array<{ blockNumber: number }>) => { +const getFirstEvent = (...events: TimelineEvent[]) => { let min = Number.MAX_SAFE_INTEGER let firstEvent = null let index = 0 @@ -21,13 +22,13 @@ const getFirstEvent = (...events: Array<{ blockNumber: number }>) => { index = i } } - return { firstEvent, index } + // TS thinks firstEvent can be null because it doesn't + // understand the algorithm, so cast + return { firstEvent: firstEvent as TimelineEvent, index } } -const combineEvents = ( - ...eventLists: Array> -) => { - const combined = [] +const combineEvents = (...eventLists: TimelineEvent[][]) => { + const combined: TimelineEvent[] = [] let i = 0 const combinedLength = eventLists.reduce((acc, cur) => acc + cur.length, 0) while (i < combinedLength) { @@ -53,7 +54,7 @@ export function fetchTimeline( wallet: Address, timelineType: TimelineType ): ThunkAction> { - return async (dispatch, getState, aud) => { + return async (dispatch, _, aud) => { // Some delegation methods allow you to either filter // by delegator or service provider const filter = @@ -61,21 +62,25 @@ export function fetchTimeline( ? { delegator: wallet } : { serviceProvider: wallet } - const events = await Promise.all([ - aud.Governance.getVotesByAddress([wallet]), - aud.Governance.getVoteUpdatesByAddress([wallet]), + /* Define the events outside Promise.all because Promise.all TS bindings + * only supports ten elements + * https://github.com/microsoft/TypeScript/issues/39788 + */ + const rawEvents: Promise[] = [ + aud.Governance.getVoteEventsByAddress([wallet]), + aud.Governance.getVoteUpdateEventsByAddress([wallet]), aud.Governance.getProposalsForAddresses([wallet]), - aud.Delegate.getIncreaseDelegateStakeEvents(wallet), aud.Claim.getClaimProcessedEvents(wallet), - aud.Delegate.getReceiveDelegationIncreaseEvents(wallet), aud.ServiceProviderClient.getRegisteredServiceProviderEvents(wallet), aud.ServiceProviderClient.getDeregisteredServiceProviderEvents(wallet), aud.ServiceProviderClient.getIncreasedStakeEvents(wallet), aud.ServiceProviderClient.getDecreasedStakeRequestedEvents(wallet), - aud.Delegate.getDecreaseDelegateStakeEvents(filter), + aud.Delegate.getIncreaseDelegateStakeEvents(filter), + aud.Delegate.getDecreaseDelegateStakeEvaluatedEvents(filter), aud.Delegate.getUndelegateStakeRequestedEvents(filter), aud.Delegate.getUndelegateStakeCancelledEvents(filter) - ]) + ] + const events = await Promise.all(rawEvents) const timeline = combineEvents(...events).reverse() dispatch(setTimeline({ wallet, timeline })) diff --git a/packages/protocol-dashboard/src/store/cache/timeline/slice.ts b/packages/protocol-dashboard/src/store/cache/timeline/slice.ts index 85846f9c578..9e54799689a 100644 --- a/packages/protocol-dashboard/src/store/cache/timeline/slice.ts +++ b/packages/protocol-dashboard/src/store/cache/timeline/slice.ts @@ -1,9 +1,10 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' -import { Address, Event } from 'types' +import { TimelineEvent } from 'models/TimelineEvents' +import { Address } from 'types' export type State = { // Timeline events keyed by wallet - timelines: { [wallet: string]: Event[] } + timelines: { [wallet: string]: TimelineEvent[] } } export const initialState: State = { @@ -12,7 +13,7 @@ export const initialState: State = { type SetTimeline = { wallet: Address - timeline: Event[] + timeline: TimelineEvent[] } const slice = createSlice({ diff --git a/packages/protocol-dashboard/src/store/cache/user/hooks.ts b/packages/protocol-dashboard/src/store/cache/user/hooks.ts index 38ce8444587..0ad961373ce 100644 --- a/packages/protocol-dashboard/src/store/cache/user/hooks.ts +++ b/packages/protocol-dashboard/src/store/cache/user/hooks.ts @@ -29,7 +29,7 @@ import { fetchContentNodes } from '../contentNode/hooks' import { useAccountUser } from 'store/account/hooks' -import { GetPendingDecreaseStakeRequestResponse } from 'services/Audius/serviceProviderClient' +import { GetPendingDecreaseStakeRequestResponse } from 'services/Audius/service-provider/types' import getActiveStake from 'utils/activeStake' type UseUsersProp = { diff --git a/packages/protocol-dashboard/src/types.ts b/packages/protocol-dashboard/src/types.ts index dc2fd67203f..ee570812892 100644 --- a/packages/protocol-dashboard/src/types.ts +++ b/packages/protocol-dashboard/src/types.ts @@ -1,9 +1,6 @@ import BN from 'bn.js' -import { GetPendingUndelegateRequestResponse } from 'services/Audius/delegate' -import { GetPendingDecreaseStakeRequestResponse } from 'services/Audius/serviceProviderClient' - -// TODO: Type BigNumber -export type BigNumber = any // BN +import { GetPendingUndelegateRequestResponse } from 'services/Audius/delegate/types' +import { GetPendingDecreaseStakeRequestResponse } from 'services/Audius/service-provider/types' export type Version = string export type Address = string @@ -12,7 +9,8 @@ export type Wallet = string export type NodeId = number export type BlockNumber = number export type Block = any -export type Amount = BigNumber +export type Amount = BN +export type BigNumber = BN export enum ServiceType { DiscoveryProvider = 'discovery-node', @@ -66,8 +64,6 @@ export type Delegate = { type EventID = string -export type Event = any - export type User = { wallet: Address name?: string diff --git a/packages/protocol-dashboard/src/utils/activeStake.ts b/packages/protocol-dashboard/src/utils/activeStake.ts index 2367e09bb5f..ff62cc69918 100644 --- a/packages/protocol-dashboard/src/utils/activeStake.ts +++ b/packages/protocol-dashboard/src/utils/activeStake.ts @@ -1,5 +1,6 @@ import { Utils } from '@audius/libs' import { Operator, User } from 'types' +import BN from 'bn.js' /** * Calculates and returns active stake for address @@ -12,8 +13,8 @@ import { Operator, User } from 'types' */ export const getActiveStake = (user: User | Operator) => { - let activeDeployerStake = Utils.toBN('0') - let activeDelegatorStake = Utils.toBN('0') + let activeDeployerStake: BN = Utils.toBN('0') + let activeDelegatorStake: BN = Utils.toBN('0') if ('serviceProvider' in user) { const { deployerStake } = user.serviceProvider const { @@ -38,7 +39,7 @@ export const getActiveStake = (user: User | Operator) => { } export const getTotalActiveDelegatedStake = (user: User | Operator) => { - let total = Utils.toBN('0') + let total: BN = Utils.toBN('0') if ('delegators' in user) { for (const delegator of user.delegators) { total = total.add(delegator.activeAmount) diff --git a/packages/protocol-dashboard/src/utils/format.ts b/packages/protocol-dashboard/src/utils/format.ts index b2fad28f92f..e0822362382 100644 --- a/packages/protocol-dashboard/src/utils/format.ts +++ b/packages/protocol-dashboard/src/utils/format.ts @@ -5,6 +5,7 @@ import { Utils } from '@audius/libs' import { Address, BigNumber } from 'types' import AudiusClient from 'services/Audius' import { TICKER } from './consts' +import BN from 'bn.js' dayjs.extend(duration) @@ -23,7 +24,7 @@ export const formatWeight = (weight: number) => { } // Format a number with commas -export const formatNumber = (num: number) => { +export const formatNumber = (num: number | BN) => { const parts = num.toString().split('.') parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',') return parts.join('.') @@ -60,16 +61,18 @@ export const formatShortWallet = (wallet: Address) => { * Format a BN to the shortened $audio currency * @param num BN */ -export const formatAud = (amount: BigNumber) => { +export const formatAud = (amount: BigNumber | null) => { if (!Utils.isBN(amount)) return '' - let aud = amount.div(Utils.toBN('1000000000000000000')).toString() + let aud = (amount as BigNumber) + .div(Utils.toBN('1000000000000000000')) + .toString() aud = numeral(aud).format('0,0') return aud } -export const formatWei = (amount: BigNumber) => { +export const formatWei = (amount: BigNumber | null) => { if (!Utils.isBN(amount)) return '' - let aud = formatNumberCommas(AudiusClient.getAud(amount)) + let aud = formatNumberCommas(AudiusClient.getAud(amount as BigNumber)) return `${aud} ${TICKER}` } @@ -89,7 +92,7 @@ export const leftPadZero = (number: number, desiredLength: number) => { return number.toString().padStart(desiredLength, '0') } -export const formatShortAud = (amount: BigNumber) => { +export const formatShortAud = (amount: BigNumber | null) => { if (!amount) return '' let aud = amount.div(Utils.toBN('1000000000000000000')).toNumber() if (aud >= 1000) {