/ src / services / GovernanceV3Service.ts
GovernanceV3Service.ts
  1  import {
  2    AaveTokenV3Service,
  3    AccessLevel,
  4    ChainId,
  5    GovernanceCoreService,
  6    GovernanceDataHelperService,
  7    GovernancePowerType,
  8    Payload,
  9    PayloadsDataHelperService,
 10  } from '@aave/contract-helpers';
 11  import { BigNumber } from 'ethers';
 12  import { formatUnits } from 'ethers/lib/utils';
 13  import { governanceV3Config } from 'src/ui-config/governanceConfig';
 14  import { getProvider } from 'src/utils/marketsAndNetworksConfig';
 15  
 16  export type PayloadParams = {
 17    payloadControllerAddress: string;
 18    payloadId: number;
 19    chainId: ChainId;
 20  };
 21  
 22  type PayloadData = {
 23    [key in ChainId]: {
 24      [payloadsControllerAddres: string]: number[];
 25    };
 26  };
 27  
 28  export type EnhancedPayload = Payload & {
 29    chainId: number;
 30  };
 31  
 32  export class GovernanceV3Service {
 33    private getDataHelperService() {
 34      const provider = getProvider(governanceV3Config.coreChainId);
 35      return new GovernanceDataHelperService(
 36        governanceV3Config.addresses.GOVERNANCE_DATA_HELPER,
 37        provider
 38      );
 39    }
 40  
 41    private getCoreService() {
 42      const provider = getProvider(governanceV3Config.coreChainId);
 43      return new GovernanceCoreService(governanceV3Config.addresses.GOVERNANCE_CORE, provider);
 44    }
 45  
 46    private getPayloadDataHelperService(chainId: ChainId) {
 47      const provider = getProvider(chainId);
 48      const payload = new PayloadsDataHelperService(
 49        governanceV3Config.payloadsControllerDataHelpers[chainId],
 50        provider
 51      );
 52      return payload;
 53    }
 54  
 55    async getProposalsData(from = 0, to = 0, limit = 10) {
 56      const dataHelperService = this.getDataHelperService();
 57      const proposals = await dataHelperService.getProposalsData(
 58        governanceV3Config.addresses.GOVERNANCE_CORE,
 59        from,
 60        to,
 61        limit
 62      );
 63      return proposals;
 64    }
 65  
 66    async getVotingConfig() {
 67      const dataHelperService = this.getDataHelperService();
 68      const votingConfig = await dataHelperService.getConstants(
 69        governanceV3Config.addresses.GOVERNANCE_CORE,
 70        [AccessLevel.Short_Executor, AccessLevel.Long_Executor]
 71      );
 72      return votingConfig;
 73    }
 74  
 75    async getProposalCount() {
 76      const coreService = this.getCoreService();
 77      return coreService.getProposalCount();
 78    }
 79  
 80    async getRepresentationData(user: string) {
 81      const dataHelperService = this.getDataHelperService();
 82      const representationData = await dataHelperService.getRepresentationData(
 83        governanceV3Config.addresses.GOVERNANCE_CORE,
 84        user,
 85        [...governanceV3Config.votingChainIds]
 86      );
 87      return representationData;
 88    }
 89  
 90    updateRepresentativesForChain(
 91      user: string,
 92      representatives: Array<{ chainId: ChainId; representative: string }>
 93    ) {
 94      const coreService = this.getCoreService();
 95      return coreService.updateRepresentativesForChain(user, representatives);
 96    }
 97  
 98    async getVotingPowerAt(blockHash: string, user: string, votingAssets: string[]) {
 99      const provider = getProvider(governanceV3Config.coreChainId);
100      const block = await provider.getBlock(blockHash);
101  
102      const tokenServices = votingAssets.map((token) => {
103        return {
104          asset: token,
105          service: new AaveTokenV3Service(token, provider),
106        };
107      });
108      const result = await Promise.all(
109        tokenServices.map(
110          async (s) => (await s.service.getPowerAt(block.number, user, GovernancePowerType.VOTING))[0]
111        )
112      );
113      const totalPower = result.reduce((acum, elem) => acum.add(elem), BigNumber.from(0));
114      return formatUnits(totalPower, 18);
115    }
116  
117    async getPayloadsData(payloadsControllerAddress: string, payloadIds: number[], chainId: ChainId) {
118      const dataHelperService = this.getPayloadDataHelperService(chainId);
119      const payloadsData = await dataHelperService.getPayloadsData(
120        payloadsControllerAddress,
121        payloadIds
122      );
123      return payloadsData;
124    }
125  
126    async getMultiChainPayloadsData(params: PayloadParams[]) {
127      const payloadsByChainId: PayloadData = params.reduce(
128        (acc, { chainId, payloadControllerAddress, payloadId }) => {
129          if (!acc[chainId]) {
130            acc[chainId] = {};
131          }
132  
133          if (!acc[chainId][payloadControllerAddress]) {
134            acc[chainId][payloadControllerAddress] = [];
135          }
136  
137          acc[chainId][payloadControllerAddress].push(payloadId);
138          return acc;
139        },
140        {} as PayloadData
141      );
142  
143      const promises: Promise<EnhancedPayload[]>[] = [];
144      Object.entries(payloadsByChainId).forEach(([chainId, payloads]) => {
145        const chainIdKey = +chainId;
146        Object.entries(payloads).forEach(([payloadControllerAddress, payloadIds]) => {
147          promises.push(
148            this.getPayloadsData(payloadControllerAddress, payloadIds, chainIdKey).then((data) =>
149              data.map((payload) => ({ ...payload, chainId: chainIdKey }))
150            )
151          );
152        });
153      });
154  
155      const data = await Promise.all(promises);
156      return data.flat();
157    }
158  }