statistics.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. import { ApiPromise, WsProvider } from "@polkadot/api";
  2. import { types } from "@joystream/types";
  3. import { AccountId, Balance, BlockNumber, EventRecord, Hash, Moment } from "@polkadot/types/interfaces";
  4. import { Exchange, Media, MintStatistics, ProposalTypes, StatisticsData, ValidatorReward } from "./StatisticsData";
  5. import { u32, Vec } from "@polkadot/types";
  6. import { ElectionStake, Seats } from "@joystream/types/council";
  7. import { Mint, MintId } from "@joystream/types/mint";
  8. import { ContentId, DataObject } from "@joystream/types/media";
  9. import { RoleParameters } from "@joystream/types/roles";
  10. import { Entity, EntityId } from "@joystream/types/versioned-store";
  11. import Option from "@polkadot/types/codec/Option";
  12. import Linkage from "@polkadot/types/codec/Linkage";
  13. import { PostId, ThreadId } from "@joystream/types/common";
  14. import { CategoryId } from "@joystream/types/forum";
  15. const BURN_ADDRESS = "5D5PhZQNJzcJXVBxwJxZcsutjKPqUPydrvpu6HeiBfMaeKQu";
  16. const FIRST_COUNCIL_BLOCK = 908796;
  17. const COUNCIL_ROUND_OFFSET = 5;
  18. const PROVIDER_URL = "wss://rome-rpc-endpoint.joystream.org:9944";
  19. export class StatisticsCollector {
  20. private api?: ApiPromise;
  21. constructor() {}
  22. async getStatistics(startBlock: number, endBlock: number): Promise<StatisticsData> {
  23. this.api = await StatisticsCollector.connectApi();
  24. let startHash = (await this.api.rpc.chain.getBlockHash(startBlock)) as Hash;
  25. let endHash = (await this.api.rpc.chain.getBlockHash(endBlock)) as Hash;
  26. let statistics = new StatisticsData();
  27. statistics.startBlock = startBlock;
  28. statistics.endBlock = endBlock;
  29. statistics.newBlocks = endBlock - startBlock;
  30. statistics.percNewBlocks = StatisticsCollector.convertToPercentage(statistics.newBlocks, endBlock);
  31. await this.fillBasicInfo(startHash, endHash, statistics);
  32. await this.fillMintsInfo(startHash, endHash, statistics);
  33. // await this.fillCouncilElectionInfo(startHash, endHash, startBlock, statistics);
  34. await this.fillForumInfo(startHash, endHash, statistics);
  35. this.api.disconnect();
  36. return statistics;
  37. //
  38. // if (statistics.electionVotes) {
  39. // statistics.avgVotePerApplicant = statistics.electionVotes / statistics.electionApplicants;
  40. // } else {
  41. // statistics.avgVotePerApplicant = 0;
  42. // }
  43. //
  44. //
  45. //
  46. //
  47. // let startIssuance = await this.api.query.balances.totalIssuance.at(startHash) as unknown as Balance;
  48. // let endIssuance = await this.api.query.balances.totalIssuance.at(endHash) as unknown as Balance;
  49. // statistics.newIssuance = endIssuance.toNumber() - startIssuance.toNumber();
  50. // statistics.totalIssuance = endIssuance.toNumber();
  51. // statistics.percNewIssuance = this.convertToPercentage(statistics.newIssuance, statistics.totalIssuance);
  52. //
  53. // let startNrMembers = await this.api.query.members.membersCreated.at(startHash) as unknown as MemberId;
  54. // let endNrNumber = await this.api.query.members.membersCreated.at(endHash) as unknown as MemberId;
  55. // statistics.newMembers = endNrNumber.toNumber() - startNrMembers.toNumber();
  56. // statistics.totalMembers = endNrNumber.toNumber();
  57. // statistics.percNewMembers = this.convertToPercentage(statistics.newMembers, statistics.totalMembers);
  58. //
  59. //
  60. // let startNrStakes = await this.api.query.stake.stakesCreated.at(startHash) as StakeId;
  61. // let endNrStakes = await this.api.query.stake.stakesCreated.at(endHash) as StakeId;
  62. // statistics.newStakes = endNrStakes.toNumber() - startNrStakes.toNumber();
  63. //
  64. // for (let i = startNrStakes.toNumber(); i < endNrStakes.toNumber(); ++i) {
  65. // let stakeResult = await this.api.query.stake.stakes(i) as unknown as [Stake, Linkage<StakeId>];
  66. // let stake = stakeResult[0] as Stake;
  67. //
  68. // statistics.totalNewStakeValue += stake.value ? stake.value.toNumber() : 0;
  69. // }
  70. //
  71. // // let startBurnedTokens = await this.api.query.balances.freeBalance.at(startHash, BURN_ADDRESS) as Balance;
  72. // // let endBurnedTokens = await this.api.query.balances.freeBalance.at(endHash, BURN_ADDRESS) as Balance;
  73. // //
  74. // // statistics.totalBurned = endBurnedTokens.toNumber() - startBurnedTokens.toNumber();
  75. //
  76. // let startNrChannels = (await this.api.query.contentWorkingGroup.nextChannelId.at(startHash) as ChannelId).toNumber() - 1;
  77. // let endNrChannels = (await this.api.query.contentWorkingGroup.nextChannelId.at(endHash) as ChannelId).toNumber() - 1;
  78. //
  79. // statistics.newChannels = endNrChannels - startNrChannels;
  80. // statistics.totalChannels = endNrChannels;
  81. // statistics.percNewChannels = this.convertToPercentage(statistics.newChannels, statistics.totalChannels);
  82. //
  83. // let startMedias = await this.getMedia(api, startHash);
  84. // let endMedias = await this.getMedia(api, endHash);
  85. //
  86. // let newMedia = endMedias.filter((endMedia) => {
  87. // return !startMedias.some((startMedia) => startMedia.id == endMedia.id);
  88. // });
  89. //
  90. // statistics.newMedia = newMedia.length;
  91. // statistics.totalMedia = endMedias.length;
  92. // statistics.percNewMedia = this.convertToPercentage(statistics.newMedia, statistics.totalMedia);
  93. //
  94. // let startDataObjects = await this.api.query.dataDirectory.knownContentIds.at(startHash) as Vec<ContentId>;
  95. // let startUsedSpace = await this.computeUsedSpaceInBytes(api, startDataObjects);
  96. //
  97. // let endDataObjects = await this.api.query.dataDirectory.knownContentIds.at(endHash) as Vec<ContentId>;
  98. // let endUsedSpace = await this.computeUsedSpaceInBytes(api, endDataObjects);
  99. //
  100. // statistics.newUsedSpace = endUsedSpace - startUsedSpace;
  101. // statistics.totalUsedSpace = endUsedSpace;
  102. // statistics.percNewUsedSpace = this.convertToPercentage(statistics.newUsedSpace, statistics.totalUsedSpace);
  103. //
  104. // statistics.avgNewSizePerContent = Number((statistics.newUsedSpace / statistics.newMedia).toFixed(2));
  105. // statistics.totalAvgSizePerContent = Number((statistics.totalUsedSpace / statistics.totalMedia).toFixed(2));
  106. // statistics.percAvgSizePerContent = this.convertToPercentage(statistics.avgNewSizePerContent, statistics.totalAvgSizePerContent);
  107. //
  108. // //
  109. // // for (let startMedia of startMedias) {
  110. // // let deleted = !endMedias.some((endMedia) => {
  111. // // return endMedia.id == startMedia.id;
  112. // // })
  113. // // if (deleted) {
  114. // // ++statistics.deletedMedia;
  115. // // }
  116. // // }
  117. //
  118. // let startTimestamp = await this.api.query.timestamp.now.at(startHash) as unknown as Moment;
  119. // let endTimestamp = await this.api.query.timestamp.now.at(endHash) as unknown as Moment;
  120. // let avgBlockProduction = (((endTimestamp.toNumber() - startTimestamp.toNumber())
  121. // / 1000) / statistics.newBlocks);
  122. // statistics.avgBlockProduction = Number(avgBlockProduction.toFixed(2));
  123. //
  124. // let startPostId = await this.api.query.forum.nextPostId.at(startHash) as unknown as PostId;
  125. // let endPostId = await this.api.query.forum.nextPostId.at(endHash) as unknown as PostId;
  126. // statistics.startPosts = startPostId.toNumber() - 1;
  127. // statistics.newPosts = endPostId.toNumber() - startPostId.toNumber();
  128. // statistics.endPosts = endPostId.toNumber() - 1;
  129. // statistics.percNewPosts = this.convertToPercentage(statistics.newPosts, statistics.endPosts);
  130. //
  131. // let startThreadId = await this.api.query.forum.nextThreadId.at(startHash) as unknown as ThreadId;
  132. // let endThreadId = await this.api.query.forum.nextThreadId.at(endHash) as unknown as ThreadId;
  133. // statistics.newThreads = endThreadId.toNumber() - startThreadId.toNumber();
  134. // statistics.totalThreads = endThreadId.toNumber() - 1;
  135. // statistics.percNewThreads = this.convertToPercentage(statistics.newThreads, statistics.totalThreads);
  136. //
  137. // Updated Code
  138. // let startCategoryId = (await this.api.query.forum.nextCategoryId.at(startHash) as unknown as CategoryId).toNumber();
  139. // let endCategoryId = (await this.api.query.forum.nextCategoryId.at(endHash) as unknown as CategoryId).toNumber();
  140. // statistics.startCategories = startCategoryId;
  141. // statistics.endCategories = endCategoryId;
  142. // statistics.newCategories = endCategoryId - startCategoryId;
  143. //
  144. // let startNrProposals = await this.api.query.proposalsEngine.proposalCount.at(startHash) as unknown as u32;
  145. // let endNrProposals = await this.api.query.proposalsEngine.proposalCount.at(endHash) as unknown as u32;
  146. // statistics.newProposals = endNrProposals.toNumber() - startNrProposals.toNumber();
  147. //
  148. // for (let i = startNrProposals.toNumber(); i < endNrProposals.toNumber(); ++i) {
  149. // let proposalNumber = i - 1;
  150. // let proposalDetails = await this.api.query.proposalsCodex.proposalDetailsByProposalId.at(endHash, proposalNumber) as ProposalDetails;
  151. // switch (proposalDetails.type) {
  152. // case ProposalTypes.Text:
  153. // ++statistics.newTextProposals;
  154. // break;
  155. //
  156. // case ProposalTypes.RuntimeUpgrade:
  157. // ++statistics.newRuntimeUpgradeProposal;
  158. // break;
  159. //
  160. // case ProposalTypes.SetElectionParameters:
  161. // ++statistics.newSetElectionParametersProposal;
  162. // break;
  163. //
  164. // case ProposalTypes.Spending:
  165. // ++statistics.newSpendingProposal;
  166. // break;
  167. //
  168. // case ProposalTypes.SetLead:
  169. // ++statistics.newSetLeadProposal;
  170. // break;
  171. //
  172. // case ProposalTypes.SetContentWorkingGroupMintCapacity:
  173. // ++statistics.newSetContentWorkingGroupMintCapacityProposal;
  174. // break;
  175. //
  176. // case ProposalTypes.EvictStorageProvider:
  177. // ++statistics.newEvictStorageProviderProposal;
  178. // break;
  179. //
  180. // case ProposalTypes.SetValidatorCount:
  181. // ++statistics.newSetValidatorCountProposal;
  182. // break;
  183. //
  184. // case ProposalTypes.SetStorageRoleParameters:
  185. // ++statistics.newSetStorageRoleParametersProposal;
  186. // break;
  187. // }
  188. // }
  189. //
  190. // let validatorRewards: ValidatorReward[] = [];
  191. // let exchangesCollection: Exchange[] = [];
  192. // let promises = [];
  193. //
  194. // console.time('extractValidatorsRewards');
  195. // for (let i = startBlock; i < endBlock; ++i) {
  196. // let promise = (async () => {
  197. // const blockHash: Hash = await this.api.rpc.chain.getBlockHash(i);
  198. // const events = await this.api.query.system.events.at(blockHash) as Vec<EventRecord>;
  199. // let rewards = await this.extractValidatorsRewards(api, i, events);
  200. // if (rewards.length) {
  201. // validatorRewards = validatorRewards.concat(rewards);
  202. // }
  203. // let exchanges = this.extractExchanges(i, events);
  204. // if (exchanges.length) {
  205. // exchangesCollection = exchangesCollection.concat(exchanges);
  206. // }
  207. //
  208. // })();
  209. // promises.push(promise);
  210. // }
  211. // await Promise.all(promises);
  212. // console.timeEnd('extractValidatorsRewards');
  213. //
  214. // statistics.newValidatorReward = validatorRewards.map((validatorReward) => validatorReward.sharedReward).reduce((a, b) => a + b);
  215. // let avgValidators = validatorRewards.map((validatorReward) => validatorReward.validators).reduce((a, b) => a + b) / validatorRewards.length;
  216. // statistics.avgValidators = Number(avgValidators.toFixed(2));
  217. //
  218. // statistics.newTokensBurn = exchangesCollection.map((exchange) => exchange.amount).reduce((a, b) => a + b);
  219. //
  220. // statistics.newStorageProviderReward = await this.computeStorageRewards(api, startBlock, endBlock);
  221. //
  222. // this.api.disconnect();
  223. // return statistics;
  224. }
  225. async fillBasicInfo(startHash: Hash, endHash: Hash, statistics: StatisticsData) {
  226. let startDate = (await this.api.query.timestamp.now.at(startHash)) as Moment;
  227. let endDate = (await this.api.query.timestamp.now.at(endHash)) as Moment;
  228. statistics.dateStart = new Date(startDate.toNumber()).toLocaleDateString("en-US");
  229. statistics.dateEnd = new Date(endDate.toNumber()).toLocaleDateString("en-US");
  230. }
  231. async fillMintsInfo(startHash: Hash, endHash: Hash, statistics: StatisticsData) {
  232. let startNrMints = parseInt((await this.api.query.minting.mintsCreated.at(startHash)).toString());
  233. let endNrMints = parseInt((await this.api.query.minting.mintsCreated.at(endHash)).toString());
  234. statistics.newMints = endNrMints - startNrMints;
  235. // statistics.startMinted = 0;
  236. // statistics.endMinted = 0;
  237. for (let i = 0; i < startNrMints; ++i) {
  238. let startMintResult = ((await this.api.query.minting.mints.at(startHash, i)) as unknown) as [Mint, Linkage<MintId>];
  239. let startMint = startMintResult[0];
  240. if (!startMint) {
  241. continue;
  242. }
  243. let endMintResult = ((await this.api.query.minting.mints.at(endHash, i)) as unknown) as [Mint, Linkage<MintId>];
  244. let endMint = endMintResult[0];
  245. if (!endMint) {
  246. continue;
  247. }
  248. let startMintTotal = parseInt(startMint.getField("total_minted").toString());
  249. let endMintTotal = parseInt(endMint.getField("total_minted").toString());
  250. // statistics.startMinted += startMintTotal;
  251. statistics.totalMinted += endMintTotal - startMintTotal;
  252. statistics.totalMintCapacityIncrease += parseInt(endMint.getField("capacity").toString()) - parseInt(startMint.getField("capacity").toString());
  253. }
  254. for (let i = startNrMints; i < endNrMints; ++i) {
  255. let endMintResult = ((await this.api.query.minting.mints.at(endHash, i)) as unknown) as [Mint, Linkage<MintId>];
  256. let endMint = endMintResult[0] as Mint;
  257. if (!endMint) {
  258. return;
  259. }
  260. statistics.totalMinted = parseInt(endMint.getField("total_minted").toString());
  261. }
  262. let councilMint = (await this.api.query.council.councilMint.at(endHash)) as MintId;
  263. let councilMintStatistics = await this.computeMintInfo(councilMint, startHash, endHash);
  264. statistics.startCouncilMinted = councilMintStatistics.startMinted;
  265. statistics.endCouncilMinted = councilMintStatistics.endMinted;
  266. statistics.newCouncilMinted = councilMintStatistics.diffMinted;
  267. statistics.percNewCouncilMinted = councilMintStatistics.percMinted;
  268. let curatorMint = (await this.api.query.contentWorkingGroup.mint.at(endHash)) as MintId;
  269. let curatorMintStatistics = await this.computeMintInfo(curatorMint, startHash, endHash);
  270. statistics.startCuratorMinted = curatorMintStatistics.startMinted;
  271. statistics.endCuratorMinted = curatorMintStatistics.endMinted;
  272. statistics.newCuratorMinted = curatorMintStatistics.diffMinted;
  273. statistics.percCuratorMinted = curatorMintStatistics.percMinted;
  274. let storageProviderMint = (await this.api.query.storageWorkingGroup.mint.at(endHash)) as MintId;
  275. let storageProviderMintStatistics = await this.computeMintInfo(storageProviderMint, startHash, endHash);
  276. statistics.startStorageMinted = storageProviderMintStatistics.startMinted;
  277. statistics.endStorageMinted = storageProviderMintStatistics.endMinted;
  278. statistics.newStorageMinted = storageProviderMintStatistics.diffMinted;
  279. statistics.percStorageMinted = storageProviderMintStatistics.percMinted;
  280. }
  281. async computeMintInfo(mintId: MintId, startHash: Hash, endHash: Hash): Promise<MintStatistics> {
  282. if (mintId.toString() == "0") {
  283. return new MintStatistics(0, 0, 0);
  284. }
  285. let startMintResult = ((await this.api.query.minting.mints.at(startHash, mintId)) as unknown) as [Mint, Linkage<MintId>];
  286. let startMint = (startMintResult[0] as unknown) as Mint;
  287. if (!startMint) {
  288. return new MintStatistics(0, 0, 0);
  289. }
  290. let endMintResult = ((await this.api.query.minting.mints.at(endHash, mintId)) as unknown) as [Mint, Linkage<MintId>];
  291. let endMint = (endMintResult[0] as unknown) as Mint;
  292. if (!endMint) {
  293. return new MintStatistics(0, 0, 0);
  294. }
  295. let mintStatistics = new MintStatistics();
  296. mintStatistics.startMinted = parseInt(startMint.getField("total_minted").toString());
  297. mintStatistics.endMinted = parseInt(endMint.getField("total_minted").toString());
  298. mintStatistics.diffMinted = mintStatistics.endMinted - mintStatistics.startMinted;
  299. mintStatistics.percMinted = StatisticsCollector.convertToPercentage(mintStatistics.diffMinted, mintStatistics.endMinted);
  300. return mintStatistics;
  301. }
  302. async fillCouncilElectionInfo(startHash: Hash, endHash: Hash, startBlock: number, statistics: StatisticsData) {
  303. statistics.councilRound = ((await this.api.query.councilElection.round.at(startHash)) as u32).toNumber() - COUNCIL_ROUND_OFFSET;
  304. let seats = (await this.api.query.council.activeCouncil.at(startHash)) as Seats;
  305. statistics.councilMembers = seats.length;
  306. let applicants: Vec<AccountId>;
  307. let currentSearchBlock = startBlock - 1;
  308. do {
  309. let applicantHash = await this.api.rpc.chain.getBlockHash(currentSearchBlock);
  310. applicants = (await this.api.query.councilElection.applicants.at(applicantHash)) as Vec<AccountId>;
  311. --currentSearchBlock;
  312. } while (applicants.length == 0);
  313. statistics.electionApplicants = applicants.length;
  314. statistics.electionApplicantsStakes = 0;
  315. for (let applicant of applicants) {
  316. let applicantStakes = ((await this.api.query.councilElection.applicantStakes.at(startHash, applicant)) as unknown) as ElectionStake;
  317. statistics.electionApplicantsStakes += applicantStakes.new.toNumber();
  318. }
  319. statistics.electionVotes = seats.map((seat) => seat.backers.length).reduce((a, b) => a + b);
  320. }
  321. async fillForumInfo(startHash: Hash, endHash: Hash, statistics: StatisticsData) {
  322. let startPostId = (await this.api.query.forum.nextPostId.at(startHash)) as PostId;
  323. let endPostId = (await this.api.query.forum.nextPostId.at(endHash)) as PostId;
  324. statistics.startPosts = startPostId.toNumber();
  325. statistics.endPosts = endPostId.toNumber() + 1;
  326. statistics.newPosts = statistics.endPosts - statistics.startPosts;
  327. statistics.percNewPosts = StatisticsCollector.convertToPercentage(statistics.newPosts, statistics.endPosts);
  328. let startThreadId = ((await this.api.query.forum.nextThreadId.at(startHash)) as unknown) as ThreadId;
  329. let endThreadId = ((await this.api.query.forum.nextThreadId.at(endHash)) as unknown) as ThreadId;
  330. statistics.startThreads = startThreadId.toNumber();
  331. statistics.endThreads = endThreadId.toNumber() + 1;
  332. statistics.newThreads = statistics.endThreads - statistics.startThreads;
  333. statistics.percNewThreads = StatisticsCollector.convertToPercentage(statistics.newThreads, statistics.endThreads);
  334. let startCategoryId = (await this.api.query.forum.nextCategoryId.at(startHash)) as CategoryId;
  335. let endCategoryId = (await this.api.query.forum.nextCategoryId.at(endHash)) as CategoryId;
  336. statistics.startCategories = startCategoryId.toNumber();
  337. statistics.endCategories = endCategoryId.toNumber() + 1;
  338. statistics.newCategories = statistics.endCategories - statistics.startCategories;
  339. statistics.perNewCategories = StatisticsCollector.convertToPercentage(statistics.startCategories, statistics.endCategories);
  340. }
  341. static async extractValidatorsRewards(api: ApiPromise, blockNumber: number, events: Vec<EventRecord>): Promise<ValidatorReward[]> {
  342. let valRewards = [];
  343. // const api = await this.connectApi();
  344. for (let { event } of events) {
  345. if (event.section === "staking" && event.method === "Reward") {
  346. const sharedReward = event.data[0] as Balance;
  347. const remainingReward = event.data[1] as Balance;
  348. const oldHash: Hash = await api.rpc.chain.getBlockHash(blockNumber - 1);
  349. const slotStake = (await api.query.staking.slotStake.at(oldHash)) as Balance;
  350. const validatorInfo = (await api.query.staking.currentElected.at(oldHash)) as AccountId;
  351. const valReward = new ValidatorReward();
  352. valReward.sharedReward = sharedReward.toNumber();
  353. valReward.remainingReward = remainingReward.toNumber();
  354. valReward.validators = validatorInfo.length;
  355. valReward.slotStake = slotStake.toNumber();
  356. // date: new Date(timestamp.toNumber()),
  357. valReward.blockNumber = blockNumber;
  358. // session: session.toNumber(),
  359. // era: era.toNumber()
  360. valRewards.push(valReward);
  361. }
  362. }
  363. return valRewards;
  364. }
  365. static async computeStorageRewards(api: ApiPromise, startBlock: number, endBlock: number): Promise<number> {
  366. let estimateOfStorageReward = 0;
  367. for (let blockHeight = startBlock; blockHeight < endBlock; blockHeight += 600) {
  368. const blockHash: Hash = await api.rpc.chain.getBlockHash(blockHeight);
  369. const storageProviders = ((await api.query.actors.actorAccountIds.at(blockHash)) as Vec<AccountId>).length;
  370. const storageParameters = ((await api.query.actors.parameters.at(blockHash, "StorageProvider")) as Option<RoleParameters>).unwrap();
  371. const reward = storageParameters.reward.toNumber();
  372. const rewardPeriod = storageParameters.reward_period.toNumber();
  373. estimateOfStorageReward += (storageProviders * reward * rewardPeriod) / 600;
  374. }
  375. return estimateOfStorageReward;
  376. }
  377. static extractExchanges(blockNumber: number, events: Vec<EventRecord>): Exchange[] {
  378. let exchanges = [];
  379. for (let { event } of events) {
  380. if (event.section === "balances" && event.method === "Transfer") {
  381. const recipient = event.data[1] as AccountId;
  382. if (recipient.toString() === BURN_ADDRESS) {
  383. // For all events of "Transfer" type with matching recipient...
  384. const sender = event.data[0] as AccountId;
  385. const amountJOY = event.data[2] as Balance;
  386. const feesJOY = event.data[3] as Balance;
  387. //const memo = await api.query.memo.memo.at(blockHash, sender) as Text;
  388. let exchange = new Exchange();
  389. exchange.sender = sender.toString();
  390. // recipient: recipient.toString(),
  391. exchange.amount = amountJOY.toNumber();
  392. exchange.fees = feesJOY.toNumber();
  393. // date: new Date(timestamp.toNumber()),
  394. exchange.blockNumber = blockNumber;
  395. // session: session.toNumber(),
  396. // era: era.toNumber()
  397. exchanges.push(exchange);
  398. }
  399. }
  400. }
  401. return exchanges;
  402. }
  403. static convertToPercentage(value: number, totalValue: number): number {
  404. return Number(((value / totalValue) * 100).toFixed(2));
  405. }
  406. static async computeUsedSpaceInBytes(api: ApiPromise, contentIds: Vec<ContentId>) {
  407. let space = 0;
  408. for (let contentId of contentIds) {
  409. let dataObject = (await api.query.dataDirectory.dataObjectByContentId(contentId)) as Option<DataObject>;
  410. space += dataObject.unwrap().size_in_bytes.toNumber();
  411. }
  412. return space;
  413. }
  414. static async getMedia(api: ApiPromise, blockHash: Hash) {
  415. let nrEntities = ((await api.query.versionedStore.nextEntityId.at(blockHash)) as EntityId).toNumber();
  416. let medias: Media[] = [];
  417. for (let i = 0; i < nrEntities; ++i) {
  418. let entity = ((await api.query.versionedStore.entityById.at(blockHash, i)) as unknown) as Entity;
  419. if (entity.class_id.toNumber() != 7) {
  420. continue;
  421. }
  422. let title = entity.entity_values[0].value.value.toString();
  423. medias.push(new Media(entity.id.toNumber(), title));
  424. }
  425. return medias;
  426. }
  427. static async connectApi(): Promise<ApiPromise> {
  428. // const provider = new WsProvider('wss://testnet.joystream.org:9944');
  429. const provider = new WsProvider(PROVIDER_URL);
  430. // Create the API and wait until ready
  431. return await ApiPromise.create({ provider, types });
  432. }
  433. }