@@ -2,7 +2,7 @@ import { prisma } from '../config/db'
22import { Prisma } from '@prisma/client'
33import { combineArraysWithSameObjectKey , formatResult } from '../helpers/formatter'
44import { DrepSortType , DrepStatusType } from '../types/drep'
5- import { isHexValue } from '../helpers/validator'
5+ import { fromHex , isHexValue } from '../helpers/validator'
66
77export const fetchDrepList = async ( page = 1 , size = 10 , search = '' , status ?: DrepStatusType , sort ?: DrepSortType ) => {
88 const result = ( await prisma . $queryRaw `
@@ -352,6 +352,7 @@ export const fetchDrepVoteDetails = async (dRepId: string) => {
352352 return result [ 0 ] . votes
353353}
354354
355+ // drep delegation historty
355356export const fetchDrepDelegationDetails = async ( dRepId : string ) => {
356357 const delegateDetails = prisma . $queryRaw `
357358 with delegator as (select *, ROW_NUMBER() OVER (PARTITION BY addr_id order by tx_id desc) AS rn
@@ -459,77 +460,71 @@ export const fetchDrepRegistrationDetails = async (dRepId: string) => {
459460
460461export const fetchDrepActiveDelegation = async ( drepId : string ) => {
461462 const result = ( await prisma . $queryRaw `
462- WITH latest AS (
463+ WITH liveRecord AS (WITH latest AS (
464+ WITH stakes AS (
465+ SELECT DISTINCT sa.id AS id, sa.view AS stakeAddress
466+ FROM delegation_vote dv
467+ JOIN drep_hash dh ON dh.id = dv.drep_hash_id
468+ JOIN stake_address sa ON sa.id = dv.addr_id
469+ WHERE dh.raw = DECODE(${ drepId } , 'hex')
470+ )
463471 SELECT
464- sa.view AS stake_view,
465- dh.view AS dh_view,
466- sa.id AS stake_addr_id,
467- dh.raw,
468- dh.id,
469- ROW_NUMBER() OVER (PARTITION BY sa.id ORDER BY dv.tx_id DESC) AS rn
470- FROM stake_address sa
471- JOIN delegation_vote dv ON sa.id = dv.addr_id
472- JOIN drep_hash dh ON dh.id = dv.drep_hash_id
473- ORDER BY dv.tx_id DESC
472+ stakes.stakeAddress,
473+ stakes.id
474+ FROM stakes
475+ JOIN LATERAL (
476+ SELECT
477+ ENCODE(tx.hash, 'hex') AS tx_id,
478+ b.epoch_no,
479+ b.time,
480+ dh.raw AS raw_check
481+ FROM delegation_vote dv
482+ JOIN drep_hash dh ON dh.id = dv.drep_hash_id
483+ JOIN tx ON tx.id = dv.tx_id
484+ JOIN block b ON b.id = tx.block_id
485+ WHERE dv.addr_id = stakes.id
486+ ORDER BY dv.tx_id DESC
487+ LIMIT 1
488+ ) AS subquery ON subquery.raw_check = DECODE(${ drepId } , 'hex')
489+ GROUP BY stakes.stakeAddress, stakes.id
490+ ORDER BY stakes.id
474491 )
475492 SELECT
476- dh.view,
477- latest.stake_view,
478- SUM(uv.value) AS total_value,
479- ( SELECT SUM(amount)
493+ COUNT(DISTINCT(latest.stakeAddress)) AS activeDelegators,
494+ COALESCE(SUM(uv.value), 0) +
495+ COALESCE((
496+ SELECT SUM(amount)
480497 FROM reward r
481- WHERE r.addr_id = latest.stake_addr_id
498+ WHERE r.addr_id = latest.id
482499 AND r.earned_epoch >
483500 (SELECT blka.epoch_no
484501 FROM withdrawal w
485502 JOIN tx txa ON txa.id = w.tx_id
486503 JOIN block blka ON blka.id = txa.block_id
487- WHERE w.addr_id = latest.stake_addr_id
504+ WHERE w.addr_id = latest.id
488505 ORDER BY w.tx_id DESC
489- LIMIT 1)) AS rewardBalance,
490- (SELECT SUM(amount)
506+ LIMIT 1)
507+ ), 0) +
508+ COALESCE((
509+ SELECT SUM(amount)
491510 FROM reward_rest r
492- WHERE r.addr_id = latest.stake_addr_id
493- AND r.earned_epoch >
494- (SELECT blka.epoch_no
495- FROM withdrawal w
496- JOIN tx txa ON txa.id = w.tx_id
497- JOIN block blka ON blka.id = txa.block_id
498- WHERE w.addr_id = latest.stake_addr_id
499- ORDER BY w.tx_id DESC
500- LIMIT 1)) AS rewardRestBalance
501- FROM drep_hash dh
502- JOIN latest ON dh.id = latest.id
503- JOIN utxo_view uv ON uv.stake_address_id = latest.stake_addr_id
504- WHERE latest.rn = 1
505- AND (dh.view != 'drep_always_no_confidence'
506- OR dh.view != 'drep_always_abstain')
507- AND dh.raw = decode(${ drepId } , 'hex')
508- GROUP BY latest.stake_addr_id, dh.view, latest.stake_view;
511+ WHERE r.addr_id = latest.id
512+ AND r.earned_epoch >
513+ (SELECT blka.epoch_no
514+ FROM withdrawal w
515+ JOIN tx txa ON txa.id = w.tx_id
516+ JOIN block blka ON blka.id = txa.block_id
517+ WHERE w.addr_id = latest.id
518+ ORDER BY w.tx_id DESC
519+ LIMIT 1)
520+ ), 0) AS liveVotingPower
521+ FROM latest
522+ LEFT JOIN utxo_view uv ON uv.stake_address_id = latest.id
523+ GROUP BY latest.stakeAddress, latest.id)
524+ SELECT SUM(activedelegators) as activeDelegators, SUM(livevotingpower) as liveVotingPower
525+ FROM liveRecord
509526 ` ) as Record < string , any > [ ]
510527
511- const response : Record < string , any > = { }
512-
513- for ( const row of result ) {
514- const { view : drepId , stake_view : stakeView , total_value, rewardbalance, rewardrestbalance } = row
515-
516- const totalRewardBalance : BigInt =
517- ( rewardbalance != null ? BigInt ( rewardbalance ) : BigInt ( 0 ) ) +
518- ( rewardrestbalance != null ? BigInt ( rewardrestbalance ) : BigInt ( 0 ) )
519-
520- if ( ! response [ drepId ] ) {
521- response [ drepId ] = {
522- delegators : [ ] ,
523- }
524- }
525-
526- response [ drepId ] . delegators . push ( {
527- [ stakeView ] : {
528- utxoBalance : BigInt ( total_value ) . toString ( ) ,
529- rewardBalance : totalRewardBalance . toString ( ) ,
530- } ,
531- } )
532- }
533528 const latestEpoch = await prisma . epoch . findFirst ( {
534529 orderBy : {
535530 start_time : 'desc' ,
@@ -546,25 +541,173 @@ export const fetchDrepActiveDelegation = async (drepId: string) => {
546541 epoch_no : latestEpoch ? ( latestEpoch . no as number ) : 0 ,
547542 } ,
548543 } )
544+ const totalVotingPower = drepDistr . _sum . amount as bigint
545+ const decimalInfluence = Number ( result [ 0 ] . livevotingpower ) / Number ( totalVotingPower )
546+ const influence = ( decimalInfluence * 100 ) . toFixed ( 4 ) + '%'
547+ const response = {
548+ liveDelegators : result [ 0 ] . activedelegators ? parseInt ( result [ 0 ] . activedelegators ) : 0 ,
549+ liveVotingPower : result [ 0 ] . livevotingpower ? result [ 0 ] . livevotingpower . toString ( ) : '0' ,
550+ influence : influence ,
551+ }
552+ return response
553+ }
554+
555+ export const fetchDrepActiveDelegators = async ( dRepId : string ) => {
556+ const result = ( await prisma . $queryRaw `
557+ WITH latest AS (
558+ WITH stakes AS (
559+ SELECT DISTINCT sa.id AS id, sa.view AS stakeAddress
560+ FROM delegation_vote dv
561+ JOIN drep_hash dh ON dh.id = dv.drep_hash_id
562+ JOIN stake_address sa ON sa.id = dv.addr_id
563+ WHERE dh.raw = DECODE(${ dRepId } , 'hex')
564+ )
565+ SELECT
566+ stakes.stakeAddress,
567+ stakes.id,
568+ JSON_AGG(
569+ JSON_BUILD_OBJECT(
570+ 'txId', subquery.tx_id,
571+ 'epoch', subquery.epoch_no,
572+ 'time', subquery.time
573+ )
574+ ) AS delegations
575+ FROM stakes
576+ JOIN LATERAL (
577+ SELECT
578+ ENCODE(tx.hash, 'hex') AS tx_id,
579+ b.epoch_no,
580+ b.time,
581+ dh.raw AS raw_check
582+ FROM delegation_vote dv
583+ JOIN drep_hash dh ON dh.id = dv.drep_hash_id
584+ JOIN tx ON tx.id = dv.tx_id
585+ JOIN block b ON b.id = tx.block_id
586+ WHERE dv.addr_id = stakes.id
587+ ORDER BY dv.tx_id DESC
588+ LIMIT 1
589+ ) AS subquery ON subquery.raw_check = DECODE(${ dRepId } , 'hex')
590+ GROUP BY stakes.stakeAddress, stakes.id
591+ ORDER BY stakes.id
592+ )
593+ SELECT
594+ latest.stakeAddress,
595+ latest.delegations::text,
596+ COALESCE(SUM(uv.value), 0) AS utxo,
597+ (SELECT SUM(amount)
598+ FROM reward r
599+ WHERE r.addr_id = latest.id
600+ AND r.earned_epoch >
601+ (SELECT blka.epoch_no
602+ FROM withdrawal w
603+ JOIN tx txa ON txa.id = w.tx_id
604+ JOIN block blka ON blka.id = txa.block_id
605+ WHERE w.addr_id = latest.id
606+ ORDER BY w.tx_id DESC
607+ LIMIT 1)) AS rewardBalance,
608+ (SELECT SUM(amount)
609+ FROM reward_rest r
610+ WHERE r.addr_id = latest.id
611+ AND r.earned_epoch >
612+ (SELECT blka.epoch_no
613+ FROM withdrawal w
614+ JOIN tx txa ON txa.id = w.tx_id
615+ JOIN block blka ON blka.id = txa.block_id
616+ WHERE w.addr_id = latest.id
617+ ORDER BY w.tx_id DESC
618+ LIMIT 1)) AS rewardRestBalance
619+ FROM latest
620+ LEFT JOIN utxo_view uv ON uv.stake_address_id = latest.id
621+ GROUP BY latest.stakeAddress, latest.id, latest.delegations::text;
622+ ` ) as Record < string , any > [ ]
623+ const parsedResult = ( ) => {
624+ return result . map ( ( item ) => ( {
625+ stakeAddress : item . stakeaddress ,
626+ delegatedAt : JSON . parse ( item . delegations ) [ 0 ] ,
627+ balance : {
628+ utxo : item . utxo . toString ( ) ,
629+ reward : item . rewardbalance ? item . rewardbalance . toString ( ) : '0' ,
630+ rewardRest : item . rewardrestbalance ? item . rewardrestbalance . toString ( ) : '0' ,
631+ } ,
632+ } ) )
633+ }
634+ return parsedResult ( )
635+ }
549636
550- const calculateSum = ( data : Record < string , any > ) : string => {
551- let totalSum = BigInt ( 0 )
552- for ( const drepId in data ) {
553- const delegators = data [ drepId ] . delegators
554- for ( const delegator of delegators ) {
555- for ( const stakeView in delegator ) {
556- const { utxoBalance, rewardBalance } = delegator [ stakeView ]
557- totalSum += BigInt ( utxoBalance ) + BigInt ( rewardBalance )
637+ export const fetchDrepDelegationHistory = async ( dRepId : string ) => {
638+ const result = ( await prisma . $queryRaw `
639+ WITH stakes AS (
640+ SELECT DISTINCT sa.id AS id, sa.view AS stake
641+ FROM delegation_vote dv
642+ JOIN drep_hash dh ON dh.id = dv.drep_hash_id
643+ JOIN stake_address sa ON sa.id = dv.addr_id
644+ WHERE dh.raw = DECODE(${ dRepId } , 'hex')
645+ )
646+ SELECT
647+ stakes.stake,
648+ JSON_AGG(
649+ JSON_BUILD_OBJECT(
650+ 'drep', dh.view,
651+ 'tx_id', ENCODE(tx.hash, 'hex'),
652+ 'epoch_no', b.epoch_no,
653+ 'time', b.time
654+ ) ORDER BY dv.tx_id DESC
655+ ) AS delegations
656+ FROM delegation_vote dv
657+ JOIN stakes ON dv.addr_id = stakes.id
658+ JOIN drep_hash dh ON dh.id = dv.drep_hash_id
659+ JOIN tx ON tx.id = dv.tx_id
660+ JOIN block b ON b.id = tx.block_id
661+ GROUP BY stakes.stake
662+ ORDER BY stakes.stake;
663+ ` ) as Record < string , any > [ ]
664+
665+ const processDelegations = ( data : any [ ] , bech32Drep : string ) => {
666+ type DelegationInfo = { tx_id : string ; epoch_no : number ; time : string }
667+ type DelegationHistory = { joined ?: DelegationInfo ; left ?: DelegationInfo }
668+ type Result = {
669+ stakeAddress : string
670+ delegation : DelegationHistory [ ]
671+ }
672+
673+ const result = [ ]
674+
675+ for ( const stakeData of data ) {
676+ const stakeAddress = stakeData . stake
677+ const delegations = stakeData . delegations
678+
679+ let partialResult : Result = {
680+ stakeAddress : stakeAddress ,
681+ delegation : [ ] ,
682+ }
683+
684+ let joinedFound = false
685+ let delegationHistory : DelegationHistory = { joined : undefined , left : undefined }
686+ let stakeDelegationHistory : DelegationHistory [ ] = [ ]
687+
688+ for ( let i = delegations . length - 1 ; i >= 0 ; i -- ) {
689+ const delegation = delegations [ i ]
690+ const { drep, tx_id, epoch_no, time } = delegation
691+
692+ if ( drep === bech32Drep ) {
693+ delegationHistory . joined = { tx_id, epoch_no, time }
694+ joinedFound = true
695+ } else if ( joinedFound ) {
696+ delegationHistory . left = { tx_id, epoch_no, time }
697+ stakeDelegationHistory . push ( delegationHistory )
698+ delegationHistory = { joined : undefined , left : undefined }
699+ joinedFound = false
558700 }
559701 }
702+ if ( delegationHistory . joined || delegationHistory . left ) {
703+ stakeDelegationHistory . push ( delegationHistory )
704+ }
705+ partialResult . delegation = stakeDelegationHistory
706+ result . push ( partialResult )
560707 }
561- return totalSum . toString ( )
562- }
563708
564- const votingPower = calculateSum ( response )
565- const totalVotingPower = drepDistr . _sum . amount as bigint
566- const decimalInfluence = Number ( votingPower ) / Number ( totalVotingPower )
567- const influence = ( decimalInfluence * 100 ) . toFixed ( 4 ) + '%'
568- response . influence = influence
569- return response
709+ return result
710+ }
711+ const drepbech32 = fromHex ( 'drep' , dRepId )
712+ return processDelegations ( result , drepbech32 )
570713}
0 commit comments