proposal.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. const { registerJoystreamTypes } = require('@joystream/types');
  2. const { ApiPromise, WsProvider } = require('@polkadot/api');
  3. const TelegramBot = require('node-telegram-bot-api');
  4. // replace yourowntoken below with the Telegram token you receive from @BotFather
  5. const token = 'yourowntoken';
  6. const bot = new TelegramBot(token);
  7. //replace yourownchat, get chat id here https://stackoverflow.com/questions/32423837/telegram-bot-how-to-get-a-group-chat-id
  8. const chatid = 'yourownchat';
  9. async function main () {
  10. registerJoystreamTypes()
  11. // Create the API and wait until ready
  12. const api = await ApiPromise.create({
  13. provider: new WsProvider()
  14. })
  15. let proposalcount = (await api.query.proposalsEngine.proposalCount()).toNumber()
  16. // let activeproposals = []
  17. // let activeproposals = ((await api.query.proposalsEngine.activeProposalIds()).toJSON())[0]
  18. let activeproposals = await getactiveProposals(api)
  19. let filteredproposal
  20. let tobeexecutedprop = await getpendingProposals(api)
  21. let tobeexecutedpropfiltered
  22. const unsubscribe = await api.rpc.chain.subscribeNewHeads(async (header) => {
  23. const block = header.number.toNumber()
  24. const currentproposal = (await api.query.proposalsEngine.proposalCount()).toNumber()
  25. console.log(`Current block: ${block}, Current proposal count: ${currentproposal}, Current active proposal : ${activeproposals}`)
  26. if (currentproposal>proposalcount) {
  27. for (proposalcount+1;proposalcount<currentproposal;proposalcount++) {
  28. const proposal = await getproposalDetail(api,proposalcount+1)
  29. const propcreatedtime = proposal.detail().createdAt.toJSON()
  30. console.log(`New proposal (${proposalcount+1}) created at block ${propcreatedtime}.\r\n ${proposal.postmessage()}`)
  31. bot.sendMessage(chatid, `New proposal (${proposalcount+1}) created at block ${propcreatedtime}.\r\n ${proposal.postmessage()}`, { parse_mode: 'html' })
  32. activeproposals.push(proposalcount+1)
  33. }
  34. }
  35. if (activeproposals[0]>0) {
  36. for (const proposallist of activeproposals){
  37. const proposal = await getproposalDetail(api,proposallist)
  38. let propstage = proposal.stage()[0]
  39. if (propstage == 'Finalized') {
  40. const propstatus = proposal.resultjson()
  41. switch (propstatus[0]){
  42. case 'Approved':
  43. let graceperiod = proposal.graceperiod()
  44. if (graceperiod>0) {
  45. bot.sendMessage(chatid, `Proposalid (${proposallist}) status changed to "Finalized" at block ${proposal.finalizedtime()}.\r\n ${proposal.postmessage()}`, { parse_mode: 'html' })
  46. filteredproposal = activeproposals.filter(e => e != proposallist)
  47. tobeexecutedprop.push(proposallist)
  48. } else {
  49. bot.sendMessage(chatid, `Proposalid (${proposallist}) status changed to "Finalized and Executed" at block ${proposal.finalizedtime()}.\r\n ${proposal.postmessage()}`, { parse_mode: 'html' })
  50. filteredproposal = activeproposals.filter(e => e != proposallist)
  51. }
  52. break;
  53. case 'Expired':
  54. case 'Canceled':
  55. case 'Cancelled':
  56. case 'Rejected':
  57. case 'Slashed':
  58. case 'Vetoed':
  59. // console.log(`Proposal ${proposallist} ${propstatus[0]}`)
  60. // bot.sendMessage(chatid, `Proposalid (${proposallist}) status changed to <b>"Finalized:${propstatus[0]}"</b> at block ${proposal.finalizedtime()}.\r\n ${proposal.postmessage()}`, { parse_mode: 'html' })
  61. // filteredproposal = activeproposals.filter(e => e != proposallist)
  62. // break;
  63. default:
  64. console.log(`Proposal ${proposallist} changed to other status: ${propstatus[0]}`)
  65. bot.sendMessage(chatid, `Proposalid (${proposallist}) status changed to <b>"Finalized:${propstatus[0]}"</b> at block ${proposal.finalizedtime()}.\r\n ${proposal.postmessage()}`, { parse_mode: 'html' })
  66. filteredproposal = activeproposals.filter(e => e != proposallist)
  67. break;
  68. }
  69. activeproposals = filteredproposal
  70. }
  71. }
  72. }
  73. if (tobeexecutedprop[0]>0) {
  74. for (const proposallist of tobeexecutedprop) {
  75. const proposal = await getproposalDetail(api,proposallist)
  76. let exestatus = Object.getOwnPropertyNames(proposal.resultfull()['Approved'])[0]
  77. if (exestatus=='Executed'){
  78. console.log(`Proposal ${proposallist} has been executed`)
  79. bot.sendMessage(chatid, `Proposalid (${proposallist}) <b>has been executed</b> at block ${proposal.finalizedtime()+proposal.graceperiod()}.\r\n ${proposal.postmessage()}`, { parse_mode: 'html' })
  80. tobeexecutedpropfiltered = tobeexecutedprop.filter(e => e != proposallist)
  81. } else {
  82. console.log(`Proposal ${proposallist} Execution is failed`)
  83. bot.sendMessage(chatid, `Proposalid (${proposallist}) <b>failed to be executed</b> at block ${proposal.finalizedtime()+proposal.graceperiod()}.\r\n ${proposal.postmessage()}`, { parse_mode: 'html' })
  84. tobeexecutedpropfiltered = tobeexecutedprop.filter(e => e != proposallist)
  85. }
  86. tobeexecutedprop = tobeexecutedpropfiltered
  87. }
  88. }
  89. })
  90. }
  91. const getpendingProposals = async (api) => {
  92. let tobeexecutedprop = ((await api.query.proposalsEngine.pendingExecutionProposalIds()).toJSON())[0]
  93. if (tobeexecutedprop[0]==0){
  94. return []
  95. } else {
  96. return tobeexecutedprop
  97. }
  98. }
  99. const getactiveProposals = async (api) => {
  100. let activeproposals = ((await api.query.proposalsEngine.activeProposalIds()).toJSON())[0]
  101. if (activeproposals[0]==0){
  102. return []
  103. } else {
  104. return activeproposals
  105. }
  106. }
  107. const getmemberHandle = async (api,memberid) => {
  108. const memberprofile = await api.query.members.memberProfile(memberid)
  109. const handler = memberprofile.raw.handle.toJSON()
  110. return handler
  111. }
  112. const getproposalStatus = (propresultraw) => {
  113. if (propresultraw.hasOwnProperty('proposalStatus')) {
  114. return propresultraw.proposalStatus
  115. } else {
  116. return {Active:null}
  117. }
  118. }
  119. const getfinalTime = (propresultraw) => {
  120. if (propresultraw.hasOwnProperty('finalizedAt')) {
  121. return propresultraw.finalizedAt
  122. } else {
  123. return 0
  124. }
  125. }
  126. const getproposalDetail = async (api,proposalcount) => {
  127. const propdetail = await api.query.proposalsEngine.proposals(proposalcount)
  128. const parameters = propdetail.parameters
  129. const propposterid = propdetail.proposerId.toJSON()
  130. const handler = await getmemberHandle(api,propposterid)
  131. const proptype = await api.query.proposalsCodex.proposalDetailsByProposalId(proposalcount)
  132. const [deftype] = Object.getOwnPropertyNames(proptype.toJSON())
  133. const proptitle = propdetail.title.toJSON()
  134. const propstage = propdetail.status.toJSON()
  135. // const propstatus = propdetail.get("status")
  136. const propstatus = Object.getOwnPropertyNames(propstage)
  137. const propresultraw = propstage[propstatus]
  138. const propfinalresultfull = getproposalStatus(propresultraw)
  139. // const propfinalresultfull = propresultraw.proposalStatus
  140. // const propfinalresultjson = Object.getOwnPropertyNames(propresultraw.proposalStatus)
  141. const propfinaltime = getfinalTime(propresultraw)
  142. // const propfinaltime = propresultraw.finalizedAt
  143. const propfinalresultjson = Object.getOwnPropertyNames(propfinalresultfull)
  144. const graceperiod = propdetail.parameters.gracePeriod.toNumber()
  145. return {
  146. detail : function () {
  147. return propdetail;
  148. },
  149. parameters : function () {
  150. return parameters;
  151. },
  152. stage : function () {
  153. return propstatus;
  154. },
  155. finalizedtime : function () {
  156. return propfinaltime;
  157. },
  158. graceperiod : function () {
  159. return graceperiod;
  160. },
  161. resultfull : function () {
  162. return propfinalresultfull;
  163. },
  164. resultjson : function () {
  165. return propfinalresultjson;
  166. },
  167. postmessage : function () {
  168. return `<b>Type</b>: ${deftype}\r\n <b>Proposer</b>:<a href="https://testnet.joystream.org/#/members/${handler}"> ${handler}(${propposterid})</a>\r\n <b>Title</b>: <a href="https://testnet.joystream.org/#/proposals/${proposalcount}">${proptitle.substring(0,100)}</a>\r\n <b>Stage</b>: ${propstatus}\r\n <b>Result</b>: ${JSON.stringify(propfinalresultfull)}`;
  169. // postmessage : function () {
  170. // return `<b>Type</b>: ${this.deftype()}\r\n <b>Proposer</b>: ${this.handler()}(${this.posterid()})\r\n <b>Title</b>: ${this.title()}\r\n <b>Stage</b>: ${this.stage()}\r\n <b>Result</b>: ${this.result()}`;
  171. }
  172. }
  173. }
  174. main()