demo.go 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. package demo
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "math/big"
  7. "os"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "github.com/ditcraft/client/config"
  12. "github.com/ditcraft/client/git"
  13. "github.com/ditcraft/client/helpers"
  14. "github.com/ditcraft/client/smartcontracts/KNWToken"
  15. "github.com/ditcraft/client/smartcontracts/KNWVoting"
  16. "github.com/ditcraft/client/smartcontracts/ditDemoCoordinator"
  17. "github.com/ditcraft/client/smartcontracts/ditToken"
  18. "github.com/ethereum/go-ethereum/accounts/abi/bind"
  19. "github.com/ethereum/go-ethereum/common"
  20. "github.com/ethereum/go-ethereum/crypto"
  21. "github.com/ethereum/go-ethereum/ethclient"
  22. )
  23. const correctETHAddressLength = 42
  24. var demoVoterAddresses = []string{
  25. "0x0000000000000000000000000000000000000000",
  26. "0x0000000000000000000000000000000000000000",
  27. "0x0000000000000000000000000000000000000000",
  28. }
  29. var demoVoterPrivateKeys = []string{
  30. "0000000000000000000000000000000000000000000000000000000000000000",
  31. "0000000000000000000000000000000000000000000000000000000000000000",
  32. "0000000000000000000000000000000000000000000000000000000000000000",
  33. }
  34. // ProposeCommit will start a new proposal on the ditContract of this repository
  35. func ProposeCommit(_commitMessage string) (string, int, error) {
  36. if !config.DitConfig.PassedKYC {
  37. passedKYC, err := CheckForKYC()
  38. if err != nil {
  39. return "", 0, err
  40. } else if !passedKYC {
  41. return "", 0, errors.New("You didn't pass the KYC yet")
  42. }
  43. }
  44. // Searching for this repositories object in the config
  45. repoIndex, err := searchForRepoInConfig()
  46. if err != nil {
  47. return "", 0, err
  48. }
  49. repoHash := getHashOfString(config.DitConfig.DemoRepositories[repoIndex].Name)
  50. // Gathering the the knowledge-labels from the config
  51. knowledgeLabels := config.DitConfig.DemoRepositories[repoIndex].KnowledgeLabels
  52. connection, err := getConnection()
  53. if err != nil {
  54. return "", 0, err
  55. }
  56. // Create a new instance of the ditContract to access it
  57. ditCoordinatorInstance, err := getDitDemoCoordinatorInstance(connection)
  58. if err != nil {
  59. return "", 0, err
  60. }
  61. // Create a new instance of the ditToken to access it
  62. ditTokenInstance, err := getDitTokenInstance(connection)
  63. if err != nil {
  64. return "", 0, err
  65. }
  66. // Convertig the hex-string-formatted address into address object
  67. myAddress := common.HexToAddress(config.DitConfig.EthereumKeys.Address)
  68. // Prompting the user which knowledge-label he wants to use for this proposal
  69. answerKnowledgeLabel := 0
  70. userInputString := "Which Knowledge-Label suits this commit most?"
  71. for i := range knowledgeLabels {
  72. userInputString += " (" + strconv.Itoa(i+1) + ") " + knowledgeLabels[i]
  73. }
  74. for answerKnowledgeLabel < 1 || answerKnowledgeLabel > len(knowledgeLabels) {
  75. answerKnowledgeLabel, _ = strconv.Atoi(helpers.GetUserInput(userInputString))
  76. }
  77. // Retrieving the xDit balance of the user
  78. xDitBalance, err := ditTokenInstance.BalanceOf(nil, myAddress)
  79. if err != nil {
  80. return "", 0, errors.New("Failed to retrieve " + config.DitConfig.Currency + " balance")
  81. }
  82. // Formatting the xDit balance to a human-readable format
  83. floatBalance := new(big.Float).Quo((new(big.Float).SetInt(xDitBalance)), big.NewFloat(1000000000000000000))
  84. // Prompting the user how much stake he wants to set for this proposal
  85. answerStake := "0"
  86. floatStakeParsed, _ := strconv.ParseFloat(answerStake, 64)
  87. floatStake := big.NewFloat(floatStakeParsed)
  88. helpers.PrintLine(fmt.Sprintf("You have a balance of %.2f xDit", floatBalance), 0)
  89. userInputString = fmt.Sprintf("How much do you want to stake?")
  90. for floatStake.Cmp(big.NewFloat(0)) == 0 || floatStake.Cmp(floatBalance) != -1 {
  91. answerStake = helpers.GetUserInput(userInputString)
  92. floatStakeParsed, _ = strconv.ParseFloat(answerStake, 64)
  93. floatStake = big.NewFloat(floatStakeParsed)
  94. }
  95. // Prompting the user whether he is sure of this proposal and its details
  96. floatStakeString := fmt.Sprintf("%.2f", floatStakeParsed)
  97. helpers.PrintLine(" Proposing the commit with the following settings:", 0)
  98. helpers.PrintLine(" Commit Message: "+_commitMessage+"", 0)
  99. helpers.PrintLine(" Knowledge Label: "+knowledgeLabels[answerKnowledgeLabel-1], 0)
  100. helpers.PrintLine(" The following stake with automatically be deducted: "+floatStakeString+" xDit", 0)
  101. userIsSure := helpers.GetUserInputChoice("Is that correct?", "y", "n")
  102. if userIsSure == "n" {
  103. return "", 0, errors.New("Canceled proposal of commit due to users choice")
  104. }
  105. fmt.Println()
  106. // Setting the value of the transaction to be the selected stake
  107. weiFloatStake, _ := (new(big.Float).Mul(floatStake, big.NewFloat(1000000000000000000))).Int64()
  108. intStake := big.NewInt(weiFloatStake)
  109. approvedBalance, err := ditTokenInstance.Allowance(nil, myAddress, common.HexToAddress(config.DitConfig.DitCoordinator))
  110. if err != nil {
  111. return "", 0, errors.New("Failed to retrieve xDit allowance")
  112. }
  113. if approvedBalance.Cmp(intStake) == -1 {
  114. helpers.PrintLine("Since xDit is a token, we need to set an allowance first", 0)
  115. // Crerating the transaction (basic values)
  116. auth, err := populateTx(connection)
  117. if err != nil {
  118. return "", 0, err
  119. }
  120. _, err = ditTokenInstance.Approve(auth, common.HexToAddress(config.DitConfig.DitCoordinator), xDitBalance)
  121. if err != nil {
  122. return "", 0, err
  123. }
  124. newAllowance := approvedBalance
  125. for newAllowance.Cmp(approvedBalance) == 0 {
  126. newAllowance, err = ditTokenInstance.Allowance(nil, myAddress, common.HexToAddress(config.DitConfig.DitCoordinator))
  127. if err != nil {
  128. return "", 0, errors.New("Failed to retrieve xDit allowance")
  129. }
  130. time.Sleep(2 * time.Second)
  131. }
  132. fmt.Println()
  133. }
  134. // Crerating the transaction (basic values)
  135. auth, err := populateTx(connection)
  136. if err != nil {
  137. return "", 0, err
  138. }
  139. // Retrieving the last/current proposalID of the ditContract
  140. // (This will increment after a proposal, so we can see when the proposal is live)
  141. lastProposalID, err := ditCoordinatorInstance.GetCurrentProposalID(nil, repoHash)
  142. if err != nil {
  143. return "", 0, errors.New("Failed to retrieve the current proposal id")
  144. }
  145. helpers.PrintLine("Now the actual commit proposal will be executed", 0)
  146. // Proposing the commit
  147. transaction, err := ditCoordinatorInstance.ProposeCommit(auth, repoHash, big.NewInt(int64(answerKnowledgeLabel-1)), big.NewInt(int64(120)), big.NewInt(int64(120)), intStake)
  148. if err != nil {
  149. if strings.Contains(err.Error(), "insufficient funds") {
  150. return "", 0, errors.New("Your account doesn't have enough xDai to pay for the transaction")
  151. }
  152. return "", 0, err
  153. }
  154. // Waiting for the proposals transaction to be mined
  155. helpers.Printf("Waiting for commit proposal transaction to be mined", 0)
  156. newProposalID := lastProposalID
  157. waitingFor := 0
  158. for newProposalID.Cmp(lastProposalID) == 0 {
  159. waitingFor += 5
  160. time.Sleep(5 * time.Second)
  161. fmt.Printf(".")
  162. // Checking the current proposal ID every 5 seconds
  163. newProposalID, err = ditCoordinatorInstance.GetCurrentProposalID(nil, repoHash)
  164. if err != nil {
  165. return "", 0, errors.New("Failed to retrieve the current proposal id")
  166. }
  167. // If we are waiting for more than 2 minutes, the transaction might have failed
  168. if waitingFor > 180 {
  169. fmt.Printf("\n")
  170. helpers.PrintLine("Waiting for over 3 minutes, maybe the transaction or the network failed?", 1)
  171. helpers.PrintLine("Check at: https://blockscout.com/poa/dai/tx/"+transaction.Hash().Hex(), 1)
  172. os.Exit(0)
  173. }
  174. }
  175. fmt.Printf("\n")
  176. // Gathering the information of the new proposal from the ditContract (including the times to commit and reveal)
  177. newVote, err := gatherProposalInfo(connection, ditCoordinatorInstance, repoHash, newProposalID.Int64())
  178. if err != nil {
  179. return "", 0, err
  180. }
  181. // Adding the new vote to the config object
  182. config.DitConfig.DemoRepositories[repoIndex].ActiveVotes = append(config.DitConfig.DemoRepositories[repoIndex].ActiveVotes, newVote)
  183. // Saving the config back to the file
  184. err = config.Save()
  185. if err != nil {
  186. return "", 0, err
  187. }
  188. // Conwerting the stake and used KNW count into a float so that it's human-readable
  189. floatETH := new(big.Float).Quo((new(big.Float).SetInt(big.NewInt(int64(newVote.NumTokens)))), big.NewFloat(1000000000000000000))
  190. floatKNW := new(big.Float).Quo((new(big.Float).SetInt(big.NewInt(int64(newVote.NumKNW)))), big.NewFloat(1000000000000000000))
  191. // Formatting the time of the commit and reveal phase into a readable format
  192. timeReveal := time.Unix(int64(newVote.RevealEnd), 0)
  193. timeRevealString := timeReveal.Format("15:04:05 on 2006/01/02")
  194. timeCommit := time.Unix(int64(newVote.CommitEnd), 0)
  195. timeCommitString := timeCommit.Format("15:04:05 on 2006/01/02")
  196. // Returning the response to the user, we don't want to print this right here and now
  197. // since we are not sure whether the actual git commands will succeed.
  198. // So it will be printed afterwards in the main routine
  199. var responseString string
  200. responseString += "---------------------------"
  201. responseString += "\nSuccessfully proposed commit. Vote on proposal started with ID " + strconv.Itoa(int(newVote.ID)) + ""
  202. responseString += fmt.Sprintf("\nYou staked %.2f %s and used %f KNW", floatETH, config.DitConfig.Currency, floatKNW)
  203. responseString += "\nThe vote will end at " + timeRevealString
  204. if config.DitConfig.DemoRepositories[repoIndex].Provider == "github" {
  205. responseString += "\nYour commit is at https://github.com/" + config.DitConfig.DemoRepositories[repoIndex].Name + "/tree/dit_proposal_" + strconv.Itoa(int(newVote.ID))
  206. }
  207. responseString += "\n---------------------------"
  208. if config.DitConfig.DemoModeActive {
  209. fmt.Println()
  210. helpers.PrintLine("Since this is the demo mode, five auto-validators will automatically vote on your proposed commit. You will see the outcome after the vote ended.", 3)
  211. helpers.PrintLine("All validators now have time to vote on your proposed commit until "+timeCommitString, 3)
  212. helpers.PrintLine("To finalize the vote, execute '"+helpers.ColorizeCommand("finalize "+strconv.Itoa(int(newVote.ID)))+"' after "+timeRevealString, 3)
  213. fmt.Println()
  214. }
  215. return responseString, int(newProposalID.Int64()), nil
  216. }
  217. // // Vote will cast the demo accounts' votes on a proposal
  218. // func Vote(_proposalID string) error {
  219. // if !config.DitConfig.PassedKYC {
  220. // passedKYC, err := CheckForKYC()
  221. // if err != nil {
  222. // return err
  223. // } else if !passedKYC {
  224. // return errors.New("You didn't pass the KYC yet")
  225. // }
  226. // }
  227. // helpers.PrintLine("Starting demo voters to simulate participants", 3)
  228. // for i := 0; i < 3; i++ {
  229. // rand.Seed(time.Now().UnixNano())
  230. // randomSelection := rand.Intn(2)
  231. // randomSalt := rand.Intn(123456789)
  232. // err := _executeVote(_proposalID, strconv.Itoa(randomSelection), strconv.Itoa(randomSalt), i)
  233. // if err != nil {
  234. // helpers.PrintLine("Error during vote commiting of demo voter "+strconv.Itoa(i), 2)
  235. // }
  236. // }
  237. // return nil
  238. // }
  239. // func _executeVote(_proposalID string, _choice string, _salt string, _demoVoter int) error {
  240. // // Converting the stdin string input of the user into Ints
  241. // proposalID, _ := strconv.Atoi(_proposalID)
  242. // choice, _ := strconv.Atoi(_choice)
  243. // salt, _ := strconv.Atoi(_salt)
  244. // // Searching for this repositories object in the config
  245. // ditContractIndex, err := searchForRepoInConfig()
  246. // if err != nil {
  247. // return err
  248. // }
  249. // repoHash := getHashOfString(config.DitConfig.DemoRepositories[ditContractIndex].Name)
  250. // connection, err := getConnection()
  251. // if err != nil {
  252. // return err
  253. // }
  254. // // Convertig the hex-string-formatted address into address object
  255. // myAddress := common.HexToAddress(demoVoterAddresses[_demoVoter])
  256. // // Create a new instance of the ditContract to access it
  257. // ditCoordingatorInstance, err := getDitDemoCoordinatorInstance(connection)
  258. // if err != nil {
  259. // return err
  260. // }
  261. // // Create a new instance of the KNWVoting contract to access it
  262. // KNWVotingInstance, err := getKNWVotingInstance(connection)
  263. // if err != nil {
  264. // return err
  265. // }
  266. // // Searching for the corresponding vote in the votes stored in the config
  267. // var voteIndex int
  268. // for i := range config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes {
  269. // if config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[i].ID == proposalID {
  270. // voteIndex = i
  271. // break
  272. // }
  273. // }
  274. // // Retrieving the proposal object from the ditContract
  275. // proposal, err := ditCoordingatorInstance.ProposalsOfRepository(nil, repoHash, big.NewInt(int64(proposalID)))
  276. // if err != nil {
  277. // return errors.New("Failed to retrieve proposal")
  278. // }
  279. // // Verifiying whether the proposal is valid (if KNWVoteID is zero its not valid or non existent)
  280. // if proposal.KNWVoteID.Int64() == 0 {
  281. // return errors.New("Invalid proposalID")
  282. // }
  283. // if proposal.Proposer == myAddress {
  284. // return errors.New("The demo voter can't vote on his own proposal")
  285. // }
  286. // // Retrieving the default stake from the ditContract
  287. // requiredStake, err := KNWVotingInstance.GetGrossStake(nil, proposal.KNWVoteID)
  288. // if err != nil {
  289. // return errors.New("Failed to retrieve the required stake of the vote")
  290. // }
  291. // // In order to create a valid abi-encoded hash of the vote choice and salt
  292. // // we need to create an abi object
  293. // uint256Type, _ := abi.NewType("uint256")
  294. // arguments := abi.Arguments{
  295. // {
  296. // Type: uint256Type,
  297. // },
  298. // {
  299. // Type: uint256Type,
  300. // },
  301. // }
  302. // // We will now put pack this abi object into a bytearray
  303. // bytes, _ := arguments.Pack(
  304. // big.NewInt(int64(choice)),
  305. // big.NewInt(int64(salt)),
  306. // )
  307. // // And finally hash this bytearray with keccak256, resulting in the votehash
  308. // voteHash := crypto.Keccak256Hash(bytes)
  309. // // Verifying whether the commit period of this vote is active
  310. // commitPeriodActive, err := KNWVotingInstance.CommitPeriodActive(nil, proposal.KNWVoteID)
  311. // if err != nil {
  312. // return errors.New("Failed to retrieve opening status")
  313. // }
  314. // // If it is now active it's probably over
  315. // if !commitPeriodActive {
  316. // return errors.New("The commit phase of this vote has ended")
  317. // }
  318. // // Verifying whether the user has already commited a vote on this proposal
  319. // oldDidCommit, err := KNWVotingInstance.DidCommit(nil, myAddress, proposal.KNWVoteID)
  320. // if err != nil {
  321. // return errors.New("Failed to retrieve commit status")
  322. // }
  323. // // If this is the case, the user can not vote again
  324. // if oldDidCommit {
  325. // return errors.New("The demo voter already voted on this proposal")
  326. // }
  327. // var auth *bind.TransactOpts
  328. // // Crerating the transaction (basic values)
  329. // auth, err = populateTx(connection, demoVoterPrivateKeys[_demoVoter], demoVoterAddresses[_demoVoter])
  330. // if err != nil {
  331. // return err
  332. // }
  333. // // Setting the value of the transaction to be the default stake
  334. // auth.Value = requiredStake
  335. // // Voting on the proposal
  336. // _, err = ditCoordingatorInstance.VoteOnProposal(auth, repoHash, big.NewInt(int64(proposalID)), voteHash)
  337. // if err != nil {
  338. // if strings.Contains(err.Error(), "insufficient funds") {
  339. // return errors.New("The demo voters account doesn't have enough ETH to pay for the transaction")
  340. // }
  341. // return errors.New("Failed to commit the vote: " + err.Error())
  342. // }
  343. // // We will also store the users choice and salt, so that the user doesn't need to remember the salt
  344. // // when he will reveal the vote later on
  345. // if _demoVoter == 0 {
  346. // config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoChoices = make([]int, 3)
  347. // config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoSalts = make([]int, 3)
  348. // }
  349. // config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoChoices[_demoVoter] = choice
  350. // config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoSalts[_demoVoter] = salt
  351. // // Saving the config back to the file
  352. // err = config.Save()
  353. // if err != nil {
  354. // return err
  355. // }
  356. // // Formatting the time of the commit and reveal phase into a readable format
  357. // timeCommit := time.Unix(int64(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].CommitEnd), 0)
  358. // timeCommitString := timeCommit.Format("15:04:05 on 2006/01/02")
  359. // timeReveal := time.Unix(int64(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].RevealEnd), 0)
  360. // timeRevealString := timeReveal.Format("15:04:05 on 2006/01/02")
  361. // helpers.PrintLine("Demo-Voter "+strconv.Itoa(_demoVoter)+" casted a vote on the proposed commit", 3)
  362. // if _demoVoter == 2 {
  363. // fmt.Println()
  364. // helpers.PrintLine("With dit, votes are casted in a concealed manner through a commitment scheme.", 3)
  365. // helpers.PrintLine("This means that votes have to be opened and thus revealed to the public once the commit-phase is over.", 3)
  366. // helpers.PrintLine("Please open the concealed demo votes with '"+helpers.ColorizeCommand("demo_open "+strconv.Itoa(int(proposalID)))+"' between "+timeCommitString+" and "+timeRevealString, 3)
  367. // }
  368. // return nil
  369. // }
  370. // // Open will reveal the demo voters' conceal votes
  371. // func Open(_proposalID string, _demoVoter int) error {
  372. // if !config.DitConfig.PassedKYC {
  373. // passedKYC, err := CheckForKYC()
  374. // if err != nil {
  375. // return err
  376. // } else if !passedKYC {
  377. // return errors.New("You didn't pass the KYC yet")
  378. // }
  379. // }
  380. // // Converting the stdin string input of the user into an int
  381. // proposalID, _ := strconv.Atoi(_proposalID)
  382. // // Searching for this repositories object in the config
  383. // ditContractIndex, err := searchForRepoInConfig()
  384. // if err != nil {
  385. // return err
  386. // }
  387. // repoHash := getHashOfString(config.DitConfig.DemoRepositories[ditContractIndex].Name)
  388. // connection, err := getConnection()
  389. // if err != nil {
  390. // return err
  391. // }
  392. // // Convertig the hex-string-formatted address into an address object
  393. // myAddress := common.HexToAddress(demoVoterAddresses[_demoVoter])
  394. // // Create a new instance of the ditContract to access it
  395. // ditCoordinatorInstance, err := getDitDemoCoordinatorInstance(connection)
  396. // if err != nil {
  397. // return err
  398. // }
  399. // // Create a new instance of the KNWVoting contract to access it
  400. // KNWVotingInstance, err := getKNWVotingInstance(connection)
  401. // if err != nil {
  402. // return err
  403. // }
  404. // // Searching for the corresponding vote in the votes stored in the config
  405. // var voteIndex int
  406. // for i := range config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes {
  407. // if config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[i].ID == proposalID {
  408. // voteIndex = i
  409. // break
  410. // }
  411. // }
  412. // if len(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoChoices) != 3 || len(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoSalts) != 3 {
  413. // return errors.New("No demo voters voted on this vote")
  414. // }
  415. // // Verifying whether the reveal period of this vote is active
  416. // revealPeriodActive, err := KNWVotingInstance.RevealPeriodActive(nil, big.NewInt(int64(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].KNWVoteID)))
  417. // if err != nil {
  418. // return errors.New("Failed to retrieve opening status")
  419. // }
  420. // // If it is now active it hasn't started yet or it's over
  421. // if !revealPeriodActive {
  422. // return errors.New("The opening phase of this vote is not active")
  423. // }
  424. // // Verifying whether the user has commited a vote on this proposal
  425. // didCommit, err := KNWVotingInstance.DidCommit(nil, myAddress, big.NewInt(int64(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].KNWVoteID)))
  426. // if err != nil {
  427. // return errors.New("Failed to retrieve commit status")
  428. // }
  429. // // If this is not the case the user never participated in this proposal through a vote
  430. // if !didCommit {
  431. // return errors.New("The demo voter didn't vote on this proposal")
  432. // }
  433. // // Verifying whether the user has revealed his vote on this proposal
  434. // oldDidReveal, err := KNWVotingInstance.DidReveal(nil, myAddress, big.NewInt(int64(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].KNWVoteID)))
  435. // if err != nil {
  436. // return errors.New("Failed to retrieve opening status")
  437. // }
  438. // // If this is the case, the user already revealed his vote
  439. // if oldDidReveal {
  440. // return errors.New("The demo voter already opened the vote on this proposal")
  441. // }
  442. // // Crerating the transaction (basic values)
  443. // auth, err := populateTx(connection, demoVoterPrivateKeys[_demoVoter], demoVoterAddresses[_demoVoter])
  444. // if err != nil {
  445. // return err
  446. // }
  447. // // Gathering the original choice and the salt from the config
  448. // choice := big.NewInt(int64(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoChoices[_demoVoter]))
  449. // salt := big.NewInt(int64(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoSalts[_demoVoter]))
  450. // // Revealing the vote on the proposal
  451. // _, err = ditCoordinatorInstance.OpenVoteOnProposal(auth, repoHash, big.NewInt(int64(proposalID)), choice, salt)
  452. // if err != nil {
  453. // if strings.Contains(err.Error(), "insufficient funds") {
  454. // return errors.New("The demo voters account doesn't have enough ETH to pay for the transaction")
  455. // }
  456. // return errors.New("Failed to open the vote: " + err.Error())
  457. // }
  458. // var stringChoice string
  459. // if config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoChoices[_demoVoter] == 1 {
  460. // stringChoice = "for"
  461. // } else {
  462. // stringChoice = "against"
  463. // }
  464. // helpers.PrintLine("Demo-Voter "+strconv.Itoa(_demoVoter)+" opened his vote commitment (voted "+stringChoice+" the proposal) ", 3)
  465. // if _demoVoter == 2 {
  466. // // Formatting the time of the reveal phase into a readable format
  467. // timeReveal := time.Unix(int64(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].RevealEnd), 0)
  468. // timeRevealString := timeReveal.Format("15:04:05 on 2006/01/02")
  469. // helpers.PrintLine("Successfully opened all the concealed demo votes.", 3)
  470. // fmt.Println("")
  471. // helpers.PrintLine("After the vote ended, the vote has to be finalized. This includes", 3)
  472. // helpers.PrintLine("calculating the outcome and distributing KNW tokens and ETH stakes.", 3)
  473. // helpers.PrintLine("To do so when the vote is over, execute '"+helpers.ColorizeCommand("finalize "+_proposalID)+"' after "+timeRevealString, 3)
  474. // }
  475. // return nil
  476. // }
  477. // // Finalize will finalize a demo voters' vote as it will trigger the calculation of the reward
  478. // // of this user including the ETH and KNW reward in case of a voting for the winning decision
  479. // // or the losing of ETH and KNW in case of a voting for the losing decision
  480. // // The first caller who executes this will also trigger the calculation whether the vote passed or not
  481. // func Finalize(_proposalID string) (bool, error) {
  482. // if !config.DitConfig.PassedKYC {
  483. // passedKYC, err := CheckForKYC()
  484. // if err != nil {
  485. // return false, err
  486. // } else if !passedKYC {
  487. // return false, errors.New("You didn't pass the KYC yet")
  488. // }
  489. // }
  490. // // Converting the stdin string input of the user into an int
  491. // proposalID, _ := strconv.Atoi(_proposalID)
  492. // // Searching for this repositories object in the config
  493. // ditContractIndex, err := searchForRepoInConfig()
  494. // if err != nil {
  495. // return false, err
  496. // }
  497. // repoHash := getHashOfString(config.DitConfig.DemoRepositories[ditContractIndex].Name)
  498. // connection, err := getConnection()
  499. // if err != nil {
  500. // return false, err
  501. // }
  502. // // Convertig the hex-string-formatted address into an address object
  503. // myAddress := common.HexToAddress(demoVoterAddresses[_demoVoter])
  504. // // Create a new instance of the ditContract to access it
  505. // ditCoordinatorInstance, err := getDitDemoCoordinatorInstance(connection)
  506. // if err != nil {
  507. // return false, err
  508. // }
  509. // // Create a new instance of the KNWVoting contract to access it
  510. // KNWVotingInstance, err := getKNWVotingInstance(connection)
  511. // if err != nil {
  512. // return false, err
  513. // }
  514. // // Searching for the corresponding vote in the votes stored in the config
  515. // var voteIndex int
  516. // for i := range config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes {
  517. // if config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[i].ID == proposalID {
  518. // voteIndex = i
  519. // break
  520. // }
  521. // }
  522. // if len(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoChoices) != 3 || len(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].DemoSalts) != 3 {
  523. // return false, errors.New("No demo voters voted on this vote")
  524. // }
  525. // // Verifying whether the vote has already ended
  526. // pollEnded, err := KNWVotingInstance.PollEnded(nil, big.NewInt(int64(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].KNWVoteID)))
  527. // if err != nil {
  528. // return false, errors.New("Failed to retrieve vote status")
  529. // }
  530. // // If not, we can't resolve it
  531. // if !pollEnded {
  532. // return false, errors.New("The vote hasn't ended yet")
  533. // }
  534. // // Verifying whether the user is a participant of this vote
  535. // didCommit, err := KNWVotingInstance.DidCommit(nil, myAddress, big.NewInt(int64(config.DitConfig.DemoRepositories[ditContractIndex].ActiveVotes[voteIndex].KNWVoteID)))
  536. // if err != nil {
  537. // return false, errors.New("Failed to retrieve commit status")
  538. // }
  539. // // Retrieve the selected proposal obkect
  540. // proposal, err := ditCoordinatorInstance.ProposalsOfRepository(nil, repoHash, big.NewInt(int64(proposalID)))
  541. // if err != nil {
  542. // return false, errors.New("Failed to retrieve the new proposal")
  543. // }
  544. // // If not, we are not allowed to call this function (it would fail)
  545. // if !didCommit && myAddress != proposal.Proposer {
  546. // return false, errors.New("The demo voter didn't participate in this vote")
  547. // }
  548. // // Crerating the transaction (basic values)
  549. // auth, err := populateTx(connection, demoVoterPrivateKeys[_demoVoter], demoVoterAddresses[_demoVoter])
  550. // if err != nil {
  551. // return false, err
  552. // }
  553. // // Resolving the vote
  554. // _, err = ditCoordinatorInstance.FinalizeVote(auth, repoHash, big.NewInt(int64(proposalID)))
  555. // if err != nil {
  556. // if strings.Contains(err.Error(), "insufficient funds") {
  557. // return false, errors.New("The demo voters account doesn't have enough ETH to pay for the transaction")
  558. // }
  559. // return false, errors.New("Failed to finalize the vote: " + err.Error())
  560. // }
  561. // helpers.PrintLine("Finalized vote for demo voter "+strconv.Itoa(_demoVoter), 3)
  562. // return true, nil
  563. // }
  564. // CheckForKYC will return whether a user has already passed the KYC
  565. func CheckForKYC() (bool, error) {
  566. connection, err := getConnection()
  567. if err != nil {
  568. return false, err
  569. }
  570. // Convertig the hex-string-formatted address into an address object
  571. myAddress := common.HexToAddress(config.DitConfig.EthereumKeys.Address)
  572. // Create a new instance of the KNWToken to access it
  573. ditCoordinatorInstance, err := getDitDemoCoordinatorInstance(connection)
  574. if err != nil {
  575. return false, err
  576. }
  577. passedKYC, err := ditCoordinatorInstance.PassedKYC(nil, myAddress)
  578. if err != nil {
  579. return false, err
  580. }
  581. if !passedKYC {
  582. return false, nil
  583. }
  584. config.DitConfig.PassedKYC = true
  585. err = config.Save()
  586. if err != nil {
  587. return false, err
  588. }
  589. return true, nil
  590. }
  591. // populateTX will set the necessary values for a ethereum transaction
  592. // amount of gas, gasprice, nonce, sign this with the private key
  593. func populateTx(_connection *ethclient.Client) (*bind.TransactOpts, error) {
  594. // Retrieve the decrypted private key through a password prompt
  595. var err error
  596. privateKeyString, err := config.GetPrivateKey()
  597. if err != nil {
  598. return nil, err
  599. }
  600. // Converting the private key string into a private key object
  601. privateKey, err := crypto.HexToECDSA(privateKeyString)
  602. if err != nil {
  603. return nil, errors.New("Failed to convert ethereum private-key")
  604. }
  605. // Retrieving the current pending nonce of our address
  606. pendingNonce, err := _connection.PendingNonceAt(context.Background(), common.HexToAddress(config.DitConfig.EthereumKeys.Address))
  607. if err != nil {
  608. return nil, errors.New("Failed to retrieve nonce for ethereum transaction")
  609. }
  610. // Retrieving the current non-pending nonce of our address
  611. nonpendingNonce, err := _connection.NonceAt(context.Background(), common.HexToAddress(config.DitConfig.EthereumKeys.Address), nil)
  612. if err != nil {
  613. return nil, errors.New("Failed to retrieve nonce for ethereum transaction")
  614. }
  615. // Edge-Case for slow nodes
  616. nonce := pendingNonce
  617. if nonpendingNonce > pendingNonce {
  618. nonce = nonpendingNonce
  619. }
  620. // Retrieving the suggested gasprice by the network
  621. gasPrice, err := _connection.SuggestGasPrice(context.Background())
  622. if err != nil {
  623. return nil, errors.New("Failed to retrieve the gas-price for ethereum transaction")
  624. }
  625. // Minimum gas price is 10 gwei for now, which works best for rinkeby
  626. // Will be changed later on
  627. defaultGasPrice := big.NewInt(1000000000)
  628. if gasPrice.Cmp(defaultGasPrice) != 1 {
  629. gasPrice = defaultGasPrice
  630. }
  631. // Setting the values into the transaction-options object
  632. auth := bind.NewKeyedTransactor(privateKey)
  633. auth.Nonce = big.NewInt(int64(nonce))
  634. auth.Value = big.NewInt(0)
  635. auth.GasLimit = uint64(1000000)
  636. auth.GasPrice = gasPrice
  637. return auth, nil
  638. }
  639. func getDitDemoCoordinatorInstance(_connection *ethclient.Client, _ditDemoCoordinatorAddress ...string) (*ditDemoCoordinator.DitDemoCoordinator, error) {
  640. var ditDemoCoordinatorAddressString string
  641. if len(_ditDemoCoordinatorAddress) > 0 {
  642. ditDemoCoordinatorAddressString = _ditDemoCoordinatorAddress[0]
  643. } else {
  644. if len(config.DitConfig.DitCoordinator) != correctETHAddressLength {
  645. return nil, errors.New("Invalid ditDemoCoordinator address, please do '" + helpers.ColorizeCommand("set_coordinator") + "' first")
  646. }
  647. ditDemoCoordinatorAddressString = config.DitConfig.DitCoordinator
  648. }
  649. // Convertig the hex-string-formatted address into an address object
  650. ditDemoCoordinatorAddress := common.HexToAddress(ditDemoCoordinatorAddressString)
  651. // Create a new instance of the ditDemoCoordinator to access it
  652. ditDemoCoordinatorInstance, err := ditDemoCoordinator.NewDitDemoCoordinator(ditDemoCoordinatorAddress, _connection)
  653. if err != nil {
  654. return nil, errors.New("Failed to find ditDemoCoordinator at provided address")
  655. }
  656. return ditDemoCoordinatorInstance, nil
  657. }
  658. func getKNWTokenInstance(_connection *ethclient.Client) (*KNWToken.KNWToken, error) {
  659. KNWTokenAddress := common.HexToAddress(config.DitConfig.KNWToken)
  660. // Create a new instance of the KNWToken contract to access it
  661. KNWTokenInstance, err := KNWToken.NewKNWToken(KNWTokenAddress, _connection)
  662. if err != nil {
  663. return nil, errors.New("Failed to find KNWToken at provided address")
  664. }
  665. return KNWTokenInstance, nil
  666. }
  667. func getKNWVotingInstance(_connection *ethclient.Client) (*KNWVoting.KNWVoting, error) {
  668. KNWVotingAddress := common.HexToAddress(config.DitConfig.KNWVoting)
  669. // Create a new instance of the KNWVoting contract to access it
  670. KNWVotingInstance, err := KNWVoting.NewKNWVoting(KNWVotingAddress, _connection)
  671. if err != nil {
  672. return nil, errors.New("Failed to find KNWVoting at provided address")
  673. }
  674. return KNWVotingInstance, nil
  675. }
  676. // getConnection will return a connection to the ethereum blockchain
  677. func getConnection() (*ethclient.Client, error) {
  678. // Connecting to rinkeby via infura
  679. connection, err := ethclient.Dial("https://sokol.poa.network")
  680. if err != nil {
  681. return nil, errors.New("Failed to connect to the ethereum network")
  682. }
  683. return connection, nil
  684. }
  685. // searchForRepoInConfig will search for the current repo in the config
  686. func searchForRepoInConfig() (int64, error) {
  687. // Retrieve the name of the repo we are in from git
  688. repository, err := git.GetRepository()
  689. if err != nil {
  690. return 0, err
  691. }
  692. // Search for the repo in our config
  693. for i := range config.DitConfig.DemoRepositories {
  694. if config.DitConfig.DemoRepositories[i].Name == repository {
  695. // Return the index of this repository if it was found
  696. return int64(i), nil
  697. }
  698. }
  699. // Return an error if nothing was found
  700. return 0, errors.New("Repository hasn't been initialized")
  701. }
  702. func getHashOfString(_string string) [32]byte {
  703. repoHash32 := [32]byte{}
  704. copy(repoHash32[:], crypto.Keccak256([]byte(_string))[:])
  705. return repoHash32
  706. }
  707. // gatherProposalInfo will retrieve necessary information about a proposal from the ditContract
  708. func gatherProposalInfo(_connection *ethclient.Client, _ditCoordinatorInstance *ditDemoCoordinator.DitDemoCoordinator, _repoHash [32]byte, _proposalID int64) (config.ActiveVote, error) {
  709. // Retrieve the proposal object from the ditContract
  710. var newVote config.ActiveVote
  711. proposal, err := _ditCoordinatorInstance.ProposalsOfRepository(nil, _repoHash, big.NewInt(_proposalID))
  712. if err != nil {
  713. return newVote, errors.New("Failed to retrieve the new proposal")
  714. }
  715. // Store the information about this vote in an object
  716. newVote.ID = int(_proposalID)
  717. newVote.KNWVoteID = int(proposal.KNWVoteID.Int64())
  718. newVote.KnowledgeLabel = proposal.KnowledgeLabel
  719. // Create a new instance of the KNWVoting contract to access it
  720. KNWVotingInstance, err := getKNWVotingInstance(_connection)
  721. if err != nil {
  722. return newVote, err
  723. }
  724. // Retrieving the information about this vote from the KNWVOting contract itself
  725. KNWPoll, err := KNWVotingInstance.PollMap(nil, big.NewInt(int64(newVote.KNWVoteID)))
  726. if err != nil {
  727. return newVote, errors.New("Failed to retrieve vote information")
  728. }
  729. ethereumAddress := config.DitConfig.EthereumKeys.Address
  730. newVote.CommitEnd = int(KNWPoll.CommitEndDate.Int64())
  731. newVote.RevealEnd = int(KNWPoll.RevealEndDate.Int64())
  732. // Retrieving the amount of xDit a user has staked for this vote
  733. numTokens, err := KNWVotingInstance.GetGrossStake(nil, big.NewInt(int64(newVote.KNWVoteID)))
  734. if err != nil {
  735. return newVote, errors.New("Failed to retrieve grossStake")
  736. }
  737. // Retrieving the number of votes a user has for this vote
  738. numVotes, err := KNWVotingInstance.GetNumVotes(nil, common.HexToAddress(ethereumAddress), big.NewInt(int64(newVote.KNWVoteID)))
  739. if err != nil {
  740. return newVote, errors.New("Failed to retrieve numVotes")
  741. }
  742. // Retrieving the number of KNW tokens a user has staked for this vote
  743. numKNW, err := KNWVotingInstance.GetNumKNW(nil, common.HexToAddress(ethereumAddress), big.NewInt(int64(newVote.KNWVoteID)))
  744. if err != nil {
  745. return newVote, errors.New("Failed to retrieve numKNW")
  746. }
  747. newVote.NumTokens = int(numTokens.Int64())
  748. newVote.NumVotes = int(numVotes.Int64())
  749. newVote.NumKNW = int(numKNW.Int64())
  750. return newVote, nil
  751. }
  752. func getDitTokenInstance(_connection *ethclient.Client) (*ditToken.MintableERC20, error) {
  753. ditTokenAddress := common.HexToAddress(config.DitConfig.DitToken)
  754. // Create a new instance of the KNWToken contract to access it
  755. ditTokenInstance, err := ditToken.NewMintableERC20(ditTokenAddress, _connection)
  756. if err != nil {
  757. return nil, errors.New("Failed to find ditToken at provided address")
  758. }
  759. return ditTokenInstance, nil
  760. }