12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559 |
- package ethereum
- import (
- "context"
- "errors"
- "fmt"
- "math/big"
- "os"
- "strconv"
- "strings"
- "time"
- "github.com/ditcraft/client/config"
- "github.com/ditcraft/client/git"
- "github.com/ditcraft/client/helpers"
- "github.com/ditcraft/client/smartcontracts/KNWToken"
- "github.com/ditcraft/client/smartcontracts/KNWVoting"
- "github.com/ditcraft/client/smartcontracts/ditCoordinator"
- "github.com/ditcraft/client/smartcontracts/ditDemoCoordinator"
- "github.com/ditcraft/client/smartcontracts/ditToken"
- "github.com/ethereum/go-ethereum/accounts/abi"
- "github.com/ethereum/go-ethereum/accounts/abi/bind"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethclient"
- )
- const correctETHAddressLength = 42
- // SetDitCoordinator will write the dit coordinators address to the config and
- // retrieve the addresses of the KNWToken and KNWVoting contracts
- func SetDitCoordinator(_ditCoordinatorAddressString string) error {
- connection, err := getConnection()
- if err != nil {
- return err
- }
- // Create a new instance of the ditCoordinator to access it
- ditCoordinatorInstance, err := getDitCoordinatorInstance(connection, _ditCoordinatorAddressString)
- if err != nil {
- return err
- }
- // Retrieving the KNWVoting contracts address from the ditCoordinator
- KNWVotingAddress, err := ditCoordinatorInstance.KNWVotingAddress(nil)
- if err != nil {
- return errors.New("Failed to retrieve address of the KNWVoting contract")
- }
- // Check whether the retrieved address is valid (i.e. not zero)
- if KNWVotingAddress == common.HexToAddress("0") {
- return errors.New("Received an invalid address of the KNWVoting contract")
- }
- // Retrieving the KNWToken contracts address from the ditCoordinator
- KNWTokenAddress, err := ditCoordinatorInstance.KNWTokenAddress(nil)
- if err != nil {
- return errors.New("Failed to retrieve address of the KNWToken contract")
- }
- // Check whether the retrieved address is valid (i.e. not zero)
- if KNWTokenAddress == common.HexToAddress("0") {
- return errors.New("Received an invalid address of the KNWToken contract")
- }
- // If in demo mode, also retrieve the xDit token address
- if config.DitConfig.DemoModeActive {
- // Create a new instance of the ditDemoCoordinator to access it
- ditDemoCoordinatorInstance, err := getDitDemoCoordinatorInstance(connection, _ditCoordinatorAddressString)
- if err != nil {
- return err
- }
- // Retrieving the ditToken contracts address from the ditDemoCoordinator
- ditTokenAddress, err := ditDemoCoordinatorInstance.XDitTokenAddress(nil)
- if err != nil {
- return errors.New("Failed to retrieve address of the KNWToken contract")
- }
- config.DitConfig.DitToken = ditTokenAddress.Hex()
- config.DitConfig.Currency = "xDit"
- } else {
- config.DitConfig.DitToken = ""
- config.DitConfig.Currency = "xDai"
- }
- // Setting the retrieved addresses to the config object
- config.DitConfig.DitCoordinator = _ditCoordinatorAddressString
- config.DitConfig.KNWVoting = KNWVotingAddress.Hex()
- config.DitConfig.KNWToken = KNWTokenAddress.Hex()
- config.DitConfig.PassedKYC = false
- // Saving the config back to the file
- err = config.Save()
- if err != nil {
- return nil
- }
- return nil
- }
- // InitDitRepository will initialize a new repository and store its ditContracts address
- // together with additional information into the config
- // When there is no ditContract for this repository, the user will be prompted to deploy one
- func InitDitRepository(_optionalRepository ...string) error {
- if !config.DitConfig.PassedKYC {
- passedKYC, err := CheckForKYC()
- if err != nil {
- return err
- } else if !passedKYC {
- return errors.New("You didn't pass the KYC yet")
- }
- }
- var repository string
- // If a repository name is already provided with the call of this function we will use it...
- if len(_optionalRepository) > 0 {
- repository = _optionalRepository[0]
- } else {
- // ...otherwise we will retrieve the name of this repository
- var err error
- repository, err = git.GetRepository()
- if err != nil {
- return err
- }
- }
- var repositoryArray []config.Repository
- if config.DitConfig.DemoModeActive {
- repositoryArray = config.DitConfig.DemoRepositories
- } else {
- repositoryArray = config.DitConfig.LiveRepositories
- }
- // Searching through the repositories that are in our config
- for i := 0; i < len(repositoryArray); i++ {
- // If the repository was found in our config it has already been initialized
- // In that case we don't need to proceed further
- if repositoryArray[i].Name == repository {
- if len(_optionalRepository) > 0 {
- return nil
- }
- helpers.PrintLine("Repository is already initialized", 0)
- os.Exit(0)
- }
- }
- connection, err := getConnection()
- if err != nil {
- return err
- }
- repoHash := GetHashOfString(repository)
- // Create a new instance of the ditCoordinator to access it
- ditCoordinatorInstance, err := getDitCoordinatorInstance(connection)
- if err != nil {
- return err
- }
- // Retrieving the address of the ditContract that was deployed for this repository
- isInitialized, err := ditCoordinatorInstance.RepositoryIsInitialized(nil, repoHash)
- if err != nil {
- return err
- }
- // If the address is zero, there is no contract deployed
- if !isInitialized {
- // Prompt the user whether he wants to deploy one
- answer := helpers.GetUserInputChoice("This repository hasn't been initialized yet, do you want to initialize it?", "y", "n")
- if answer == "y" {
- // If yes: deploy the ditContract
- err = initDitRepository(ditCoordinatorInstance, repoHash)
- if err != nil {
- return err
- }
- } else {
- // If not: exit
- helpers.PrintLine("No ditContract deployed - repository can't be used with dit", 1)
- os.Exit(0)
- }
- }
- // Retrieving the knowledge-labels of this ditContract
- var knowledgeLabels []string
- for i := 0; i < 3; i++ {
- contractKnowledgeLabels, err := ditCoordinatorInstance.GetKnowledgeLabels(nil, repoHash, big.NewInt(int64(i)))
- if err != nil {
- return err
- }
- if len(contractKnowledgeLabels) > 0 {
- knowledgeLabels = append(knowledgeLabels, contractKnowledgeLabels)
- }
- }
- // Inserting this repositories details into the cobfig
- var newRepository config.Repository
- newRepository.Name = repository
- if strings.Contains(repository, "github.com") {
- newRepository.Provider = "github"
- }
- newRepository.KnowledgeLabels = knowledgeLabels
- newRepository.ActiveVotes = make([]config.ActiveVote, 0)
- repositoryArray = append(repositoryArray, newRepository)
- if config.DitConfig.DemoModeActive {
- config.DitConfig.DemoRepositories = repositoryArray
- } else {
- config.DitConfig.LiveRepositories = repositoryArray
- }
- // Saving the config back to the file
- err = config.Save()
- if err != nil {
- return nil
- }
- return nil
- }
- // ProposeCommit will start a new proposal on the ditContract of this repository
- func ProposeCommit(_commitMessage string) (string, int, error) {
- if !config.DitConfig.PassedKYC {
- passedKYC, err := CheckForKYC()
- if err != nil {
- return "", 0, err
- } else if !passedKYC {
- return "", 0, errors.New("You didn't pass the KYC yet")
- }
- }
- // Searching for this repositories object in the config
- repoIndex, err := searchForRepoInConfig()
- if err != nil {
- return "", 0, err
- }
- repoHash := GetHashOfString(config.DitConfig.LiveRepositories[repoIndex].Name)
- // Gathering the the knowledge-labels from the config
- knowledgeLabels := config.DitConfig.LiveRepositories[repoIndex].KnowledgeLabels
- connection, err := getConnection()
- if err != nil {
- return "", 0, err
- }
- // Create a new instance of the ditContract to access it
- ditCoordinatorInstance, err := getDitCoordinatorInstance(connection)
- if err != nil {
- return "", 0, err
- }
- // Convertig the hex-string-formatted address into address object
- myAddress := common.HexToAddress(config.DitConfig.EthereumKeys.Address)
- // Prompting the user which knowledge-label he wants to use for this proposal
- answerKnowledgeLabel := 0
- userInputString := "Which Knowledge-Label suits this commit most?"
- for i := range knowledgeLabels {
- userInputString += " (" + strconv.Itoa(i+1) + ") " + knowledgeLabels[i]
- }
- for answerKnowledgeLabel < 1 || answerKnowledgeLabel > len(knowledgeLabels) {
- answerKnowledgeLabel, _ = strconv.Atoi(helpers.GetUserInput(userInputString))
- }
- // Retrieving the xDai balance of the user
- xDaiBalance, err := connection.BalanceAt(context.Background(), myAddress, nil)
- if err != nil {
- return "", 0, errors.New("Failed to retrieve " + config.DitConfig.Currency + " balance")
- }
- // Formatting the xDai balance to a human-readable format
- floatBalance := new(big.Float).Quo((new(big.Float).SetInt(xDaiBalance)), big.NewFloat(1000000000000000000))
- // Prompting the user how much stake he wants to set for this proposal
- answerStake := "0"
- floatStakeParsed, _ := strconv.ParseFloat(answerStake, 64)
- floatStake := big.NewFloat(floatStakeParsed)
- helpers.PrintLine(fmt.Sprintf("You have a balance of %.2f xDai", floatBalance), 0)
- userInputString = fmt.Sprintf("How much do you want to stake?")
- for floatStake.Cmp(big.NewFloat(0)) == 0 || floatStake.Cmp(floatBalance) != -1 {
- answerStake = helpers.GetUserInput(userInputString)
- floatStakeParsed, _ = strconv.ParseFloat(answerStake, 64)
- floatStake = big.NewFloat(floatStakeParsed)
- }
- // Prompting the user whether he is sure of this proposal and its details
- floatStakeString := fmt.Sprintf("%.2f", floatStakeParsed)
- helpers.PrintLine(" Proposing the commit with the following settings:", 0)
- helpers.PrintLine(" Commit Message: "+_commitMessage+"", 0)
- helpers.PrintLine(" Knowledge Label: "+knowledgeLabels[answerKnowledgeLabel-1], 0)
- helpers.PrintLine(" The following stake with automatically be deducted: "+floatStakeString+"xDai", 0)
- userIsSure := helpers.GetUserInputChoice("Is that correct?", "y", "n")
- if userIsSure == "n" {
- return "", 0, errors.New("Canceled proposal of commit due to users choice")
- }
- fmt.Println()
- // Crerating the transaction (basic values)
- auth, err := populateTx(connection)
- if err != nil {
- return "", 0, err
- }
- // Setting the value of the transaction to be the selected stake
- weiFloatStake, _ := (new(big.Float).Mul(floatStake, big.NewFloat(1000000000000000000))).Int64()
- intStake := big.NewInt(weiFloatStake)
- auth.Value = intStake
- // Retrieving the last/current proposalID of the ditContract
- // (This will increment after a proposal, so we can see when the proposal is live)
- lastProposalID, err := ditCoordinatorInstance.GetCurrentProposalID(nil, repoHash)
- if err != nil {
- return "", 0, errors.New("Failed to retrieve the current proposal id")
- }
- // Proposing the commit
- transaction, err := ditCoordinatorInstance.ProposeCommit(auth, repoHash, big.NewInt(int64(answerKnowledgeLabel-1)), big.NewInt(int64(180)), big.NewInt(int64(180)))
- if err != nil {
- if strings.Contains(err.Error(), "insufficient funds") {
- return "", 0, errors.New("Your account doesn't have enough xDai to pay for the transaction")
- }
- return "", 0, err
- }
- // Waiting for the proposals transaction to be mined
- helpers.Printf("Waiting for commit proposal transaction to be mined", 0)
- newProposalID := lastProposalID
- waitingFor := 0
- for newProposalID.Cmp(lastProposalID) == 0 {
- waitingFor += 5
- time.Sleep(5 * time.Second)
- fmt.Printf(".")
- // Checking the current proposal ID every 5 seconds
- newProposalID, err = ditCoordinatorInstance.GetCurrentProposalID(nil, repoHash)
- if err != nil {
- return "", 0, errors.New("Failed to retrieve the current proposal id")
- }
- // If we are waiting for more than 2 minutes, the transaction might have failed
- if waitingFor > 180 {
- fmt.Printf("\n")
- helpers.PrintLine("Waiting for over 3 minutes, maybe the transaction or the network failed?", 1)
- helpers.PrintLine("Check at: https://blockscout.com/poa/dai/tx/"+transaction.Hash().Hex(), 1)
- os.Exit(0)
- }
- }
- fmt.Printf("\n")
- // Gathering the information of the new proposal from the ditContract (including the times to commit and reveal)
- newVote, err := gatherProposalInfo(connection, ditCoordinatorInstance, repoHash, newProposalID.Int64())
- if err != nil {
- return "", 0, err
- }
- // Adding the new vote to the config object
- config.DitConfig.LiveRepositories[repoIndex].ActiveVotes = append(config.DitConfig.LiveRepositories[repoIndex].ActiveVotes, newVote)
- // Saving the config back to the file
- err = config.Save()
- if err != nil {
- return "", 0, err
- }
- // Conwerting the stake and used KNW count into a float so that it's human-readable
- floatxDai := new(big.Float).Quo((new(big.Float).SetInt(big.NewInt(int64(newVote.NumTokens)))), big.NewFloat(1000000000000000000))
- floatKNW := new(big.Float).Quo((new(big.Float).SetInt(big.NewInt(int64(newVote.NumKNW)))), big.NewFloat(1000000000000000000))
- // Formatting the time of the commit and reveal phase into a readable format
- timeReveal := time.Unix(int64(newVote.RevealEnd), 0)
- timeRevealString := timeReveal.Format("15:04:05 on 2006/01/02")
- timeCommit := time.Unix(int64(newVote.CommitEnd), 0)
- timeCommitString := timeCommit.Format("15:04:05 on 2006/01/02")
- // Returning the response to the user, we don't want to print this right here and now
- // since we are not sure whether the actual git commands will succeed.
- // So it will be printed afterwards in the main routine
- var responseString string
- responseString += "---------------------------"
- responseString += "\nSuccessfully proposed commit. Vote on proposal started with ID " + strconv.Itoa(int(newVote.ID)) + ""
- responseString += fmt.Sprintf("\nYou staked %.2f %s and used %f KNW.", floatxDai, config.DitConfig.Currency, floatKNW)
- responseString += "\nThe vote will end at " + timeRevealString
- if config.DitConfig.LiveRepositories[repoIndex].Provider == "github" {
- responseString += "\nYour commit is at https://github.com/" + config.DitConfig.LiveRepositories[repoIndex].Name + "/tree/dit_proposal_" + strconv.Itoa(int(newVote.ID))
- }
- responseString += "\n---------------------------"
- if config.DitConfig.DemoModeActive {
- fmt.Println()
- helpers.PrintLine("You may now simulate demo voters with '"+helpers.ColorizeCommand("demo_vote "+strconv.Itoa(int(newVote.ID)))+"' until "+timeCommitString, 3)
- fmt.Println()
- }
- return responseString, int(newProposalID.Int64()), nil
- }
- // Vote will cast a users vote on a proposal
- func Vote(_proposalID string, _choice string, _salt string) error {
- if !config.DitConfig.PassedKYC {
- passedKYC, err := CheckForKYC()
- if err != nil {
- return err
- } else if !passedKYC {
- return errors.New("You didn't pass the KYC yet")
- }
- }
- // Converting the stdin string input of the user into Ints
- proposalID, _ := strconv.Atoi(_proposalID)
- choice, _ := strconv.Atoi(_choice)
- salt, _ := strconv.Atoi(_salt)
- // Searching for this repositories object in the config
- repoIndex, err := searchForRepoInConfig()
- if err != nil {
- return err
- }
- var repositoryArray []config.Repository
- if config.DitConfig.DemoModeActive {
- repositoryArray = config.DitConfig.DemoRepositories
- } else {
- repositoryArray = config.DitConfig.LiveRepositories
- }
- repoHash := GetHashOfString(repositoryArray[repoIndex].Name)
- connection, err := getConnection()
- if err != nil {
- return err
- }
- // Convertig the hex-string-formatted address into address object
- myAddress := common.HexToAddress(config.DitConfig.EthereumKeys.Address)
- // Create a new instance of the ditContract to access it
- ditCooordinatorInstance, err := getDitCoordinatorInstance(connection)
- if err != nil {
- return err
- }
- // Create a new instance of the KNWVoting contract to access it
- KNWVotingInstance, err := getKNWVotingInstance(connection)
- if err != nil {
- return err
- }
- // Retrieving the proposal object from the ditContract
- proposal, err := ditCooordinatorInstance.ProposalsOfRepository(nil, repoHash, big.NewInt(int64(proposalID)))
- if err != nil {
- return errors.New("Failed to retrieve proposal")
- }
- // Verifiying whether the proposal is valid (if KNWVoteID is zero its not valid or non existent)
- if proposal.KNWVoteID.Int64() == 0 {
- return errors.New("Invalid proposalID")
- }
- if proposal.Proposer == myAddress {
- return errors.New("You can't vote on your own proposal")
- }
- // Retrieving the default stake from the ditContract
- requiredStake, err := KNWVotingInstance.GetGrossStake(nil, proposal.KNWVoteID)
- if err != nil {
- return errors.New("Failed to retrieve the required stake of the vote")
- }
- floatStake := new(big.Float).Quo((new(big.Float).SetInt(requiredStake)), big.NewFloat(1000000000000000000))
- helpers.PrintLine("Voting on this proposal will automatically deduct the required stake from you account.", 0)
- helpers.PrintLine(fmt.Sprintf("Required stake: %.2f", floatStake), 0)
- helpers.PrintLine("All participants of the vote will counter-stake the proposer.", 0)
- helpers.PrintLine("You will receive the remaining stake back, no matter how the vote ends.", 0)
- answer := helpers.GetUserInputChoice("Is this okay for you?", "y", "n")
- if answer == "n" {
- // If not: exit
- helpers.PrintLine("No vote executed due to users choice", 1)
- os.Exit(0)
- }
- // In order to create a valid abi-encoded hash of the vote choice and salt
- // we need to create an abi object
- uint256Type, _ := abi.NewType("uint256")
- arguments := abi.Arguments{
- {
- Type: uint256Type,
- },
- {
- Type: uint256Type,
- },
- }
- // We will now put pack this abi object into a bytearray
- bytes, _ := arguments.Pack(
- big.NewInt(int64(choice)),
- big.NewInt(int64(salt)),
- )
- // And finally hash this bytearray with keccak256, resulting in the votehash
- voteHash := crypto.Keccak256Hash(bytes)
- // Verifying whether the commit period of this vote is active
- commitPeriodActive, err := KNWVotingInstance.CommitPeriodActive(nil, proposal.KNWVoteID)
- if err != nil {
- return errors.New("Failed to retrieve opening status")
- }
- // If it is now active it's probably over
- if !commitPeriodActive {
- return errors.New("The commit phase of this vote has ended")
- }
- // Verifying whether the user has already commited a vote on this proposal
- oldDidCommit, err := KNWVotingInstance.DidCommit(nil, myAddress, proposal.KNWVoteID)
- if err != nil {
- return errors.New("Failed to retrieve commit status")
- }
- // If this is the case, the user can not vote again
- if oldDidCommit {
- return errors.New("You already voted on this proposal")
- }
- // Crerating the transaction (basic values)
- auth, err := populateTx(connection)
- if err != nil {
- return err
- }
- // Setting the value of the transaction to be the default stake
- auth.Value = requiredStake
- // Voting on the proposal
- transaction, err := ditCooordinatorInstance.VoteOnProposal(auth, repoHash, big.NewInt(int64(proposalID)), voteHash)
- if err != nil {
- if strings.Contains(err.Error(), "insufficient funds") {
- return errors.New("Your account doesn't have enough xDai to pay for the transaction")
- }
- return errors.New("Failed to commit the vote: " + err.Error())
- }
- // Waiting for the voting transaction to be mined
- helpers.Printf("Waiting for voting transaction to be mined", 0)
- waitingFor := 0
- newDidCommit := oldDidCommit
- for newDidCommit == oldDidCommit {
- waitingFor += 5
- time.Sleep(5 * time.Second)
- fmt.Printf(".")
- // Checking the commit status of the user every 5 seconds
- newDidCommit, err = KNWVotingInstance.DidCommit(nil, myAddress, proposal.KNWVoteID)
- if err != nil {
- return errors.New("Failed to retrieve commit status")
- }
- // If we are waiting for more than 2 minutes, the transaction might have failed
- if waitingFor > 180 {
- fmt.Printf("\n")
- helpers.PrintLine("Waiting for over 3 minutes, maybe the transaction or the network failed?", 1)
- helpers.PrintLine("Check at: https://blockscout.com/poa/dai/tx/"+transaction.Hash().Hex(), 1)
- os.Exit(0)
- }
- }
- fmt.Printf("\n")
- // Gathering the information of the proposal from the ditContract
- newVote, err := gatherProposalInfo(connection, ditCooordinatorInstance, repoHash, int64(proposalID))
- if err != nil {
- return err
- }
- // We will also store the users choice and salt, so that the user doesn't need to remember the salt
- // when he will reveal the vote later on
- newVote.Choice = choice
- newVote.Salt = salt
- // Adding the new vote to the config object
- repositoryArray[repoIndex].ActiveVotes = append(repositoryArray[repoIndex].ActiveVotes, newVote)
- if config.DitConfig.DemoModeActive {
- config.DitConfig.DemoRepositories = repositoryArray
- } else {
- config.DitConfig.LiveRepositories = repositoryArray
- }
- // Saving the config back to the file
- err = config.Save()
- if err != nil {
- return err
- }
- // Formatting the time of the commit and reveal phase into a readable format
- timeCommit := time.Unix(int64(newVote.CommitEnd), 0)
- timeCommitString := timeCommit.Format("15:04:05 on 2006/01/02")
- timeReveal := time.Unix(int64(newVote.RevealEnd), 0)
- timeRevealString := timeReveal.Format("15:04:05 on 2006/01/02")
- if choice == 1 {
- helpers.PrintLine("You successfully voted in favor of the proposal", 0)
- } else {
- helpers.PrintLine("You successfully voted against the proposal", 0)
- }
- // Letting the user know when and how he has to reveal the vote
- helpers.PrintLine("With dit, votes are casted in a concealed manner through a commitment scheme.", 0)
- helpers.PrintLine("This means that votes have to be revealed to the public once the commit-phase is over.", 0)
- helpers.PrintLine("Please open your vote with '"+helpers.ColorizeCommand("open "+strconv.Itoa(int(proposalID)))+"' between "+timeCommitString+" and "+timeRevealString, 0)
- return nil
- }
- // Open will open and thus reveal a vote (that was commited through a hash) to the public during the opening phase
- func Open(_proposalID string) error {
- if !config.DitConfig.PassedKYC {
- passedKYC, err := CheckForKYC()
- if err != nil {
- return err
- } else if !passedKYC {
- return errors.New("You didn't pass the KYC yet")
- }
- }
- // Converting the stdin string input of the user into an int
- proposalID, _ := strconv.Atoi(_proposalID)
- // Searching for this repositories object in the config
- repoIndex, err := searchForRepoInConfig()
- if err != nil {
- return err
- }
- var repositoryArray []config.Repository
- if config.DitConfig.DemoModeActive {
- repositoryArray = config.DitConfig.DemoRepositories
- } else {
- repositoryArray = config.DitConfig.LiveRepositories
- }
- repoHash := GetHashOfString(repositoryArray[repoIndex].Name)
- connection, err := getConnection()
- if err != nil {
- return err
- }
- // Convertig the hex-string-formatted address into an address object
- myAddress := common.HexToAddress(config.DitConfig.EthereumKeys.Address)
- // Create a new instance of the ditContract to access it
- ditCooordinatorInstance, err := getDitCoordinatorInstance(connection)
- if err != nil {
- return err
- }
- // Create a new instance of the KNWVoting contract to access it
- KNWVotingInstance, err := getKNWVotingInstance(connection)
- if err != nil {
- return err
- }
- // Searching for the corresponding vote in the votes stored in the config
- var voteIndex int
- for i := range repositoryArray[repoIndex].ActiveVotes {
- if repositoryArray[repoIndex].ActiveVotes[i].ID == proposalID {
- voteIndex = i
- break
- }
- }
- // Verifying whether the reveal period of this vote is active
- revealPeriodActive, err := KNWVotingInstance.RevealPeriodActive(nil, big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[voteIndex].KNWVoteID)))
- if err != nil {
- return errors.New("Failed to retrieve opening status")
- }
- // If it is now active it hasn't started yet or it's over
- if !revealPeriodActive {
- return errors.New("The opening phase of this vote is not active")
- }
- // Verifying whether the user has commited a vote on this proposal
- didCommit, err := KNWVotingInstance.DidCommit(nil, myAddress, big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[voteIndex].KNWVoteID)))
- if err != nil {
- return errors.New("Failed to retrieve commit status")
- }
- // If this is not the case the user never participated in this proposal through a vote
- if !didCommit {
- return errors.New("You didn't vote on this proposal")
- }
- // Verifying whether the user has revealed his vote on this proposal
- oldDidReveal, err := KNWVotingInstance.DidReveal(nil, myAddress, big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[voteIndex].KNWVoteID)))
- if err != nil {
- return errors.New("Failed to retrieve opening status")
- }
- // If this is the case, the user already revealed his vote
- if oldDidReveal {
- return errors.New("You already opened your vote on this proposal")
- }
- // Crerating the transaction (basic values)
- auth, err := populateTx(connection)
- if err != nil {
- return err
- }
- // Gathering the original choice and the salt from the config
- choice := big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[voteIndex].Choice))
- salt := big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[voteIndex].Salt))
- // Revealing the vote on the proposal
- transaction, err := ditCooordinatorInstance.OpenVoteOnProposal(auth, repoHash, big.NewInt(int64(proposalID)), choice, salt)
- if err != nil {
- if strings.Contains(err.Error(), "insufficient funds") {
- return errors.New("Your account doesn't have enough xDai to pay for the transaction")
- }
- return errors.New("Failed to open the vote: " + err.Error())
- }
- // Waiting for the reveal transaction to be mined
- helpers.Printf("Waiting for opening transaction to be mined", 0)
- waitingFor := 0
- newDidReveal := oldDidReveal
- for newDidReveal == oldDidReveal {
- waitingFor += 5
- time.Sleep(5 * time.Second)
- fmt.Printf(".")
- // Checking the reveal status of the user every 5 seconds
- newDidReveal, err = KNWVotingInstance.DidReveal(nil, myAddress, big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[voteIndex].KNWVoteID)))
- if err != nil {
- return errors.New("Failed to retrieve opening status")
- }
- // If we are waiting for more than 2 minutes, the transaction might have failed
- if waitingFor > 180 {
- fmt.Printf("\n")
- helpers.PrintLine("Waiting for over 3 minutes, maybe the transaction or the network failed?", 1)
- helpers.PrintLine("Check at: https://blockscout.com/poa/dai/tx/"+transaction.Hash().Hex(), 1)
- os.Exit(0)
- }
- }
- fmt.Printf("\n")
- // Formatting the time of the reveal phase into a readable format
- timeReveal := time.Unix(int64(repositoryArray[repoIndex].ActiveVotes[voteIndex].RevealEnd), 0)
- timeRevealString := timeReveal.Format("15:04:05 on 2006/01/02")
- helpers.PrintLine("Successfully opened your vote", 0)
- helpers.PrintLine("To finalize it when the vote is over, execute '"+helpers.ColorizeCommand("finalize "+_proposalID)+"' after "+timeRevealString, 3)
- return nil
- }
- // Finalize will finalize a vote as it will trigger the calculation of the reward of this user
- // including the xDai and KNW reward in case of a voting for the winning decision
- // or the losing of xDai and KNW in case of a voting for the losing decision
- // The first caller who executes this will also trigger the calculation whether the vote passed or not
- func Finalize(_proposalID string) (bool, bool, error) {
- if !config.DitConfig.PassedKYC {
- passedKYC, err := CheckForKYC()
- if err != nil {
- return false, false, err
- } else if !passedKYC {
- return false, false, errors.New("You didn't pass the KYC yet")
- }
- }
- // Converting the stdin string input of the user into an int
- proposalID, _ := strconv.Atoi(_proposalID)
- // Searching for this repositories object in the config
- repoIndex, err := searchForRepoInConfig()
- if err != nil {
- return false, false, err
- }
- var repositoryArray []config.Repository
- if config.DitConfig.DemoModeActive {
- repositoryArray = config.DitConfig.DemoRepositories
- } else {
- repositoryArray = config.DitConfig.LiveRepositories
- }
- repoHash := GetHashOfString(repositoryArray[repoIndex].Name)
- connection, err := getConnection()
- if err != nil {
- return false, false, err
- }
- // Convertig the hex-string-formatted address into an address object
- myAddress := common.HexToAddress(config.DitConfig.EthereumKeys.Address)
- // Create a new instance of the ditContract to access it
- ditCooordinatorInstance, err := getDitCoordinatorInstance(connection)
- if err != nil {
- return false, false, err
- }
- // Create a new instance of the KNWToken contract to access it
- KNWTokenInstance, err := getKNWTokenInstance(connection)
- if err != nil {
- return false, false, err
- }
- // Create a new instance of the KNWVoting contract to access it
- KNWVotingInstance, err := getKNWVotingInstance(connection)
- if err != nil {
- return false, false, err
- }
- // Searching for the corresponding vote in the votes stored in the config
- var voteIndex int
- for i := range repositoryArray[repoIndex].ActiveVotes {
- if repositoryArray[repoIndex].ActiveVotes[i].ID == proposalID {
- voteIndex = i
- break
- }
- }
- // If this user already called the Resolve function for this vote it's not possible anymore
- if repositoryArray[repoIndex].ActiveVotes[voteIndex].Resolved {
- return false, false, errors.New("You already finalized this vote")
- }
- // Verifying whether the vote has already ended
- pollEnded, err := KNWVotingInstance.PollEnded(nil, big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[voteIndex].KNWVoteID)))
- if err != nil {
- return false, false, errors.New("Failed to retrieve vote status")
- }
- // If not, we can't resolve it
- if !pollEnded {
- return false, false, errors.New("The vote hasn't ended yet")
- }
- // Verifying whether the user is a participant of this vote
- didCommit, err := KNWVotingInstance.DidCommit(nil, myAddress, big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[voteIndex].KNWVoteID)))
- if err != nil {
- return false, false, errors.New("Failed to retrieve commit status")
- }
- // Retrieve the selected proposal obkect
- proposal, err := ditCooordinatorInstance.ProposalsOfRepository(nil, repoHash, big.NewInt(int64(proposalID)))
- if err != nil {
- return false, false, errors.New("Failed to retrieve the new proposal")
- }
- // Indicates whether the called was the proposer or not
- isProposer := (proposal.Proposer == myAddress)
- // If not, we are not allowed to call this function (it would fail)
- if !didCommit && myAddress != proposal.Proposer {
- return false, false, errors.New("You didn't participate in this vote")
- }
- // Saving the old xDai balance
- oldxDaiBalance, err := connection.BalanceAt(context.Background(), myAddress, nil)
- if err != nil {
- return false, false, errors.New("Failed to retrieve " + config.DitConfig.Currency + " balance")
- }
- // Saving the old KNW balance
- oldKNWBalance, err := KNWTokenInstance.BalanceOfLabel(nil, myAddress, repositoryArray[repoIndex].ActiveVotes[voteIndex].KnowledgeLabel)
- if err != nil {
- return false, false, errors.New("Failed to retrieve KNW balance")
- }
- // Crerating the transaction (basic values)
- auth, err := populateTx(connection)
- if err != nil {
- return false, false, err
- }
- // Resolving the vote
- transaction, err := ditCooordinatorInstance.FinalizeVote(auth, repoHash, big.NewInt(int64(proposalID)))
- if err != nil {
- if strings.Contains(err.Error(), "insufficient funds") {
- return false, false, errors.New("Your account doesn't have enough xDai to pay for the transaction")
- }
- return false, false, errors.New("Failed to finalize the vote: " + err.Error())
- }
- // Waiting for the resolve transaction to be mined
- helpers.Printf("Waiting for finalizing transaction to be mined", 0)
- waitingFor := 0
- newxDaiBalance := oldxDaiBalance
- for oldxDaiBalance.Cmp(newxDaiBalance) == 0 {
- waitingFor += 5
- time.Sleep(5 * time.Second)
- fmt.Printf(".")
- // Checking the balance of the user every 5 seconds, if it changed, a transaction was executed
- newxDaiBalance, err = connection.BalanceAt(context.Background(), myAddress, nil)
- if err != nil {
- return false, false, errors.New("Failed to retrieve opening status")
- }
- // If we are waiting for more than 2 minutes, the transaction might have failed
- if waitingFor > 180 {
- fmt.Printf("\n")
- helpers.PrintLine("Waiting for over 3 minutes, maybe the transaction or the network failed?", 1)
- helpers.PrintLine("Check at: https://blockscout.com/poa/dai/tx/"+transaction.Hash().Hex(), 1)
- os.Exit(0)
- }
- }
- fmt.Printf("\n")
- // Saving the new KNW balance after resolving the vote
- newKNWBalance, err := KNWTokenInstance.BalanceOfLabel(nil, myAddress, repositoryArray[repoIndex].ActiveVotes[voteIndex].KnowledgeLabel)
- if err != nil {
- return false, false, errors.New("Failed to retrieve KNW balance")
- }
- // Retrieving the outcome of the vote
- pollPassed, err := KNWVotingInstance.IsPassed(nil, big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[voteIndex].KNWVoteID)))
- if err != nil {
- return false, false, errors.New("Failed to retrieve vote outcome")
- }
- fmt.Printf("\n")
- // Show the user how the vote ended
- if pollPassed {
- helpers.PrintLine("Successfully finalized the vote - it passed", 0)
- if proposal.Proposer == common.HexToAddress(config.DitConfig.EthereumKeys.Address) {
- helpers.PrintLine("You received your stake back and will share the opposing voters slashes stakes", 0)
- }
- } else {
- helpers.PrintLine("Successfully finalized the vote - it didn't pass", 0)
- if proposal.Proposer == common.HexToAddress(config.DitConfig.EthereumKeys.Address) {
- helpers.PrintLine("Your stake was slashed and will be distributed amongst the voters", 0)
- }
- }
- // If the user got some xDai as a reward, this will be shown to the user
- if newxDaiBalance.Cmp(oldxDaiBalance) > 0 {
- difference := newxDaiBalance.Sub(newxDaiBalance, oldxDaiBalance)
- floatDifference := new(big.Float).Quo((new(big.Float).SetInt64(difference.Int64())), big.NewFloat(1000000000000000000))
- helpers.PrintLine(fmt.Sprintf("You gained %.2f "+config.DitConfig.Currency+"\n", floatDifference), 0)
- }
- // Also shwoing the user how man KNW tokens he got/lost
- if oldKNWBalance.Cmp(newKNWBalance) < 0 {
- difference := newKNWBalance.Sub(newKNWBalance, oldKNWBalance)
- floatDifference := new(big.Float).Quo((new(big.Float).SetInt64(difference.Int64())), big.NewFloat(1000000000000000000))
- helpers.PrintLine(fmt.Sprintf("You earned %f KNW Tokens for the knowledge label '%s'\n", floatDifference, repositoryArray[repoIndex].ActiveVotes[voteIndex].KnowledgeLabel), 0)
- } else if oldKNWBalance.Cmp(newKNWBalance) > 0 {
- difference := oldKNWBalance.Sub(oldKNWBalance, newKNWBalance)
- floatDifference := new(big.Float).Quo((new(big.Float).SetInt64(difference.Int64())), big.NewFloat(1000000000000000000))
- helpers.PrintLine(fmt.Sprintf("You lost %f KNW Tokens for the knowledge label '%s'\n", floatDifference, repositoryArray[repoIndex].ActiveVotes[voteIndex].KnowledgeLabel), 0)
- }
- // Saving the resolved-status in the config
- repositoryArray[repoIndex].ActiveVotes[voteIndex].Resolved = true
- if config.DitConfig.DemoModeActive {
- config.DitConfig.DemoRepositories = repositoryArray
- } else {
- config.DitConfig.LiveRepositories = repositoryArray
- }
- // Saving the config back to the file
- err = config.Save()
- if err != nil {
- return false, false, err
- }
- // if config.DitConfig.DemoModeActive && len(config.DitConfig.DemoRepositories[repoIndex].ActiveVotes[voteIndex].DemoChoices) == 3 {
- // for i := 0; i < 3; i++ {
- // _, err := demo.Finalize(_proposalID, i)
- // if err != nil {
- // helpers.PrintLine("Error during vote finalizing of demo voter "+strconv.Itoa(i), 2)
- // }
- // }
- // }
- return pollPassed, isProposer, nil
- }
- // GetVoteInfo will print information about a vote
- func GetVoteInfo(_proposalID ...int) error {
- // Searching for this repositories object in the config
- repoIndex, err := searchForRepoInConfig()
- if err != nil {
- return err
- }
- var repositoryArray []config.Repository
- if config.DitConfig.DemoModeActive {
- repositoryArray = config.DitConfig.DemoRepositories
- } else {
- repositoryArray = config.DitConfig.LiveRepositories
- }
- repoHash := GetHashOfString(repositoryArray[repoIndex].Name)
- connection, err := getConnection()
- if err != nil {
- return err
- }
- // Create a new instance of the ditContract to access it
- ditCooordinatorInstance, err := getDitCoordinatorInstance(connection)
- if err != nil {
- return err
- }
- // Create a new instance of the KNWVoting contract to access it
- KNWVotingInstance, err := getKNWVotingInstance(connection)
- if err != nil {
- return err
- }
- // Retrieving the current proposalID
- currentProposalIDBigInt, err := ditCooordinatorInstance.GetCurrentProposalID(nil, repoHash)
- if err != nil {
- return errors.New("Failed to retrieve the current proposal id")
- }
- // Converting the current proposal id of the ditContract to an int
- // if it is zero, there are no votes
- currentProposalID := int(currentProposalIDBigInt.Int64())
- if currentProposalID == 0 {
- helpers.PrintLine("There are no votes for this repository", 1)
- os.Exit(0)
- }
- // If a proposalID is specified in the function call, use that
- var proposalID int
- if len(_proposalID) > 0 {
- proposalID = _proposalID[0]
- // If not, let the user select on that is between 1 and the current proposal ID
- } else {
- for proposalID < 1 || proposalID > currentProposalID {
- proposalID, _ = strconv.Atoi(helpers.GetUserInput("Select a proposal ID between 1 and " + strconv.Itoa(currentProposalID)))
- }
- }
- // Retrieve the selected proposal obkect
- proposal, err := ditCooordinatorInstance.ProposalsOfRepository(nil, repoHash, big.NewInt(int64(proposalID)))
- if err != nil {
- return errors.New("Failed to retrieve the new proposal")
- }
- // Retrieving information about this vote from the KNWVoting contract itself
- KNWPoll, err := KNWVotingInstance.PollMap(nil, proposal.KNWVoteID)
- if err != nil {
- return errors.New("Failed to retrieve vote information")
- }
- // Retrieving grossStake from this vote
- grossStake, err := KNWVotingInstance.GetGrossStake(nil, proposal.KNWVoteID)
- if err != nil {
- return errors.New("Failed to retrieve the gross stake")
- }
- floatGrossStake := new(big.Float).Quo((new(big.Float).SetInt(grossStake)), big.NewFloat(1000000000000000000))
- // Retrieving netStake from this vote
- netStake, err := KNWVotingInstance.GetNetStake(nil, proposal.KNWVoteID)
- if err != nil {
- return errors.New("Failed to retrieve the net stake")
- }
- floatNetStake := new(big.Float).Quo((new(big.Float).SetInt(netStake)), big.NewFloat(1000000000000000000))
- // Formatting the commit and reveal time to a human-readable format
- timeCommit := time.Unix(KNWPoll.CommitEndDate.Int64(), 0)
- timeCommitString := timeCommit.Format("15:04:05 on 2006/01/02")
- timeReveal := time.Unix(KNWPoll.RevealEndDate.Int64(), 0)
- timeRevealString := timeReveal.Format("15:04:05 on 2006/01/02")
- // Printing the information about this vote
- helpers.PrintLine("---------------------------", 0)
- helpers.PrintLine("Proposal ID: "+strconv.Itoa(proposalID), 0)
- helpers.PrintLine("URL: https://github.com/"+repositoryArray[repoIndex].Name+"/tree/dit_proposal_"+strconv.Itoa(proposalID), 0)
- helpers.PrintLine("Proposer: "+proposal.Proposer.Hex(), 0)
- helpers.PrintLine("Knowledge-Label: "+proposal.KnowledgeLabel, 0)
- // If the user participated in this vote, the choice and stake/KNW are also printed
- for i := range repositoryArray[repoIndex].ActiveVotes {
- if repositoryArray[repoIndex].ActiveVotes[i].ID == proposalID {
- floatxDai := new(big.Float).Quo((new(big.Float).SetInt(big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[i].NumTokens)))), big.NewFloat(1000000000000000000))
- floatKNW := new(big.Float).Quo((new(big.Float).SetInt(big.NewInt(int64(repositoryArray[repoIndex].ActiveVotes[i].NumKNW)))), big.NewFloat(1000000000000000000))
- if proposal.Proposer.Hex() != config.DitConfig.EthereumKeys.Address {
- helpers.PrintLine("Your choice: "+strconv.Itoa(repositoryArray[repoIndex].ActiveVotes[i].Choice), 0)
- }
- helpers.PrintLine(fmt.Sprintf("You staked %.2f %s and used %f KNW\n", floatxDai, config.DitConfig.Currency, floatKNW), 0)
- break
- } else {
- helpers.PrintLine(fmt.Sprintf("Required (gross) stake: %.2f "+config.DitConfig.Currency+"\n", floatGrossStake), 0)
- }
- }
- helpers.PrintLine(fmt.Sprintf("Current net stake: %.2f "+config.DitConfig.Currency+"\n", floatNetStake), 0)
- helpers.PrintLine("Vote phase end: "+timeCommitString, 0)
- helpers.PrintLine("Opening phase end: "+timeRevealString, 0)
- helpers.PrintLine("Resolved? "+strconv.FormatBool(proposal.IsFinalized), 0)
- helpers.PrintLine("Passed? "+strconv.FormatBool(proposal.ProposalAccepted), 0)
- helpers.PrintLine("---------------------------", 0)
- return nil
- }
- // GetBalances will print the xDai and KNW balances
- func GetBalances() error {
- connection, err := getConnection()
- if err != nil {
- return err
- }
- if len(config.DitConfig.KNWToken) != correctETHAddressLength {
- return errors.New("Invalid KNWToken address, please do '" + helpers.ColorizeCommand("set_coordinator") + "' first")
- }
- // Convertig the hex-string-formatted address into an address object
- myAddress := common.HexToAddress(config.DitConfig.EthereumKeys.Address)
- // Create a new instance of the KNWToken to access it
- KNWTokenInstance, err := getKNWTokenInstance(connection)
- if err != nil {
- return err
- }
- // Retrieving the number of knowledge-labels where the user has a balance in
- labelCount, err := KNWTokenInstance.LabelCountOfAddress(nil, myAddress)
- if err != nil {
- return errors.New("Failed to retrieve knowledge label count of address")
- }
- // Converting this count to an int
- labelCountInt := labelCount.Int64()
- // Retrieving each of the labels
- var labelsOfAddress []string
- for i := 1; i <= int(labelCountInt); i++ {
- newLabel, err := KNWTokenInstance.LabelOfAddress(nil, myAddress, big.NewInt(int64(i)))
- if err != nil {
- return errors.New("Failed to retrieve knowledge label count of address")
- }
- if len(newLabel) > 0 {
- labelsOfAddress = append(labelsOfAddress, newLabel)
- }
- }
- var floatBalance *big.Float
- if !config.DitConfig.DemoModeActive {
- // Retrieving the xDai balance of the user
- xDaiBalance, err := connection.BalanceAt(context.Background(), myAddress, nil)
- if err != nil {
- return errors.New("Failed to retrieve " + config.DitConfig.Currency + " balance")
- }
- helpers.PrintLine("Balances for address "+config.DitConfig.EthereumKeys.Address+":", 0)
- // Formatting the xDai balance to a human-readable format
- floatBalance = new(big.Float).Quo((new(big.Float).SetInt(xDaiBalance)), big.NewFloat(1000000000000000000))
- } else {
- // Create a new instance of the ditToken to access it
- ditTokenInstance, err := getDitTokenInstance(connection)
- if err != nil {
- return err
- }
- // Retrieving the xDit balance of the user
- xDitBalance, err := ditTokenInstance.BalanceOf(nil, myAddress)
- if err != nil {
- return errors.New("Failed to retrieve " + config.DitConfig.Currency + " balance")
- }
- helpers.PrintLine("Balances for address "+config.DitConfig.EthereumKeys.Address+":", 0)
- // Formatting the xDai balance to a human-readable format
- floatBalance = new(big.Float).Quo((new(big.Float).SetInt(xDitBalance)), big.NewFloat(1000000000000000000))
- }
- helpers.PrintLine(fmt.Sprintf(config.DitConfig.Currency+"-Balance: %.2f "+config.DitConfig.Currency, floatBalance), 0)
- helpers.PrintLine("", 0)
- // Printing each KNW balance
- helpers.PrintLine("KNW-Balances:", 0)
- if len(labelsOfAddress) == 0 {
- helpers.PrintLine("- No labels with any balance found", 0)
- } else {
- for i := 0; i < len(labelsOfAddress); i++ {
- // Retrieve each KNW balance
- balanceOfLabel, err := KNWTokenInstance.BalanceOfLabel(nil, myAddress, labelsOfAddress[i])
- if err != nil {
- return err
- }
- // Formatting each KNW balance to a human-readable format
- floatBalance := new(big.Float).Quo((new(big.Float).SetInt(balanceOfLabel)), big.NewFloat(1000000000000000000))
- helpers.PrintLine(fmt.Sprintf(" - "+labelsOfAddress[i]+": %.2f KNW", floatBalance), 0)
- }
- }
- return nil
- }
- // CheckForKYC will return whether a user has already passed the KYC
- func CheckForKYC() (bool, error) {
- connection, err := getConnection()
- if err != nil {
- return false, err
- }
- // Convertig the hex-string-formatted address into an address object
- myAddress := common.HexToAddress(config.DitConfig.EthereumKeys.Address)
- // Create a new instance of the KNWToken to access it
- ditCoordinatorInstance, err := getDitCoordinatorInstance(connection)
- if err != nil {
- return false, err
- }
- passedKYC, err := ditCoordinatorInstance.PassedKYC(nil, myAddress)
- if err != nil {
- return false, err
- }
- if !passedKYC {
- return false, nil
- }
- config.DitConfig.PassedKYC = true
- err = config.Save()
- if err != nil {
- return false, err
- }
- return true, nil
- }
- // gatherProposalInfo will retrieve necessary information about a proposal from the ditContract
- func gatherProposalInfo(_connection *ethclient.Client, _ditCoordinatorInstance *ditCoordinator.DitCoordinator, _repoHash [32]byte, _proposalID int64) (config.ActiveVote, error) {
- // Retrieve the proposal object from the ditContract
- var newVote config.ActiveVote
- proposal, err := _ditCoordinatorInstance.ProposalsOfRepository(nil, _repoHash, big.NewInt(_proposalID))
- if err != nil {
- return newVote, errors.New("Failed to retrieve the new proposal")
- }
- // Store the information about this vote in an object
- newVote.ID = int(_proposalID)
- newVote.KNWVoteID = int(proposal.KNWVoteID.Int64())
- newVote.KnowledgeLabel = proposal.KnowledgeLabel
- // Create a new instance of the KNWVoting contract to access it
- KNWVotingInstance, err := getKNWVotingInstance(_connection)
- if err != nil {
- return newVote, err
- }
- // Retrieving the information about this vote from the KNWVOting contract itself
- KNWPoll, err := KNWVotingInstance.PollMap(nil, big.NewInt(int64(newVote.KNWVoteID)))
- if err != nil {
- return newVote, errors.New("Failed to retrieve vote information")
- }
- ethereumAddress := config.DitConfig.EthereumKeys.Address
- newVote.CommitEnd = int(KNWPoll.CommitEndDate.Int64())
- newVote.RevealEnd = int(KNWPoll.RevealEndDate.Int64())
- // Retrieving the amount of xDai a user has staked for this vote
- numTokens, err := KNWVotingInstance.GetGrossStake(nil, big.NewInt(int64(newVote.KNWVoteID)))
- if err != nil {
- return newVote, errors.New("Failed to retrieve grossStake")
- }
- // Retrieving the number of votes a user has for this vote
- numVotes, err := KNWVotingInstance.GetNumVotes(nil, common.HexToAddress(ethereumAddress), big.NewInt(int64(newVote.KNWVoteID)))
- if err != nil {
- return newVote, errors.New("Failed to retrieve numVotes")
- }
- // Retrieving the number of KNW tokens a user has staked for this vote
- numKNW, err := KNWVotingInstance.GetNumKNW(nil, common.HexToAddress(ethereumAddress), big.NewInt(int64(newVote.KNWVoteID)))
- if err != nil {
- return newVote, errors.New("Failed to retrieve numKNW")
- }
- newVote.NumTokens = int(numTokens.Int64())
- newVote.NumVotes = int(numVotes.Int64())
- newVote.NumKNW = int(numKNW.Int64())
- return newVote, nil
- }
- // TODO
- func initDitRepository(_ditCoordinatorInstance *ditCoordinator.DitCoordinator, _repoHash [32]byte) error {
- connection, err := getConnection()
- if err != nil {
- return err
- }
- // Setting the voting setting for this repository
- var voteSettings [7]*big.Int
- // Majority (in percent)
- voteSettings[0] = big.NewInt(50)
- // KNW minting method (0 = regular)
- voteSettings[1] = big.NewInt(0)
- // KNW burning method (0 = square-root based, 1 = divide by 2 each time, 2 = proportial to the winning percentage)
- voteSettings[2] = big.NewInt(0)
- // TODO
- voteSettings[3] = big.NewInt(120)
- // TODO
- voteSettings[4] = big.NewInt(86400)
- // TODO
- voteSettings[5] = big.NewInt(120)
- // TODO
- voteSettings[6] = big.NewInt(86400)
- // Prompting the user to provide 1 to 3 knowledge-labels for this repository
- helpers.PrintLine("Please provide knowledge labels that will be used for this repository:", 0)
- helpers.PrintLine("Note: At least one has to be provided, press ENTER to skip", 0)
- var knowledgeLabels []string
- for len(knowledgeLabels) < 3 {
- newLabel := helpers.GetUserInput("Knowledge Label " + strconv.Itoa(len(knowledgeLabels)+1))
- if len(newLabel) > 0 {
- knowledgeLabels = append(knowledgeLabels, newLabel)
- }
- if len(newLabel) == 0 && len(knowledgeLabels) > 0 {
- if len(knowledgeLabels) < 3 {
- for i := 0; i <= 3-len(knowledgeLabels); i++ {
- knowledgeLabels = append(knowledgeLabels, "")
- }
- }
- break
- }
- }
- // Crerating the transaction (basic values)
- auth, err := populateTx(connection)
- if err != nil {
- return err
- }
- // Initializing the repository = deploying a new ditContract
- transaction, err := _ditCoordinatorInstance.InitRepository(auth, _repoHash, knowledgeLabels[0], knowledgeLabels[1], knowledgeLabels[2], voteSettings)
- if err != nil {
- if strings.Contains(err.Error(), "insufficient funds") {
- return errors.New("Your account doesn't have enough xDai to pay for the transaction")
- }
- return err
- }
- // Waiting for the deployment transaction to be mined
- helpers.Printf("Waiting for initialization transaction to be mined", 0)
- boolTrue := true
- isInitialized := false
- waitingFor := 0
- for isInitialized != boolTrue {
- waitingFor += 5
- time.Sleep(5 * time.Second)
- fmt.Printf(".")
- // Checking the repository status every 5 seconds
- isInitialized, err = _ditCoordinatorInstance.RepositoryIsInitialized(nil, _repoHash)
- if err != nil {
- return err
- }
- // If we are waiting for more than 2 minutes, the transaction might have failed
- if waitingFor > 180 {
- fmt.Printf("\n")
- helpers.PrintLine("Waiting for over 3 minutes, maybe the transaction or the network failed?", 1)
- helpers.PrintLine("Check at: https://blockscout.com/poa/dai/tx/"+transaction.Hash().Hex(), 1)
- os.Exit(0)
- }
- }
- fmt.Printf("\n")
- return nil
- }
- // populateTX will set the necessary values for a ethereum transaction
- // amount of gas, gasprice, nonce, sign this with the private key
- func populateTx(_connection *ethclient.Client) (*bind.TransactOpts, error) {
- // Retrieve the decrypted private key through a password prompt
- var err error
- privateKeyString, err := config.GetPrivateKey()
- if err != nil {
- return nil, err
- }
- // Converting the private key string into a private key object
- privateKey, err := crypto.HexToECDSA(privateKeyString)
- if err != nil {
- return nil, errors.New("Failed to convert ethereum private-key")
- }
- // Retrieving the current pending nonce of our address
- pendingNonce, err := _connection.PendingNonceAt(context.Background(), common.HexToAddress(config.DitConfig.EthereumKeys.Address))
- if err != nil {
- return nil, errors.New("Failed to retrieve nonce for ethereum transaction")
- }
- // Retrieving the current non-pending nonce of our address
- nonpendingNonce, err := _connection.NonceAt(context.Background(), common.HexToAddress(config.DitConfig.EthereumKeys.Address), nil)
- if err != nil {
- return nil, errors.New("Failed to retrieve nonce for ethereum transaction")
- }
- // Edge-Case for slow nodes
- nonce := pendingNonce
- if nonpendingNonce > pendingNonce {
- nonce = nonpendingNonce
- }
- // Retrieving the suggested gasprice by the network
- gasPrice, err := _connection.SuggestGasPrice(context.Background())
- if err != nil {
- return nil, errors.New("Failed to retrieve the gas-price for ethereum transaction")
- }
- // Minimum gas price is 10 gwei for now, which works best for rinkeby
- // Will be changed later on
- defaultGasPrice := big.NewInt(1000000000)
- if gasPrice.Cmp(defaultGasPrice) != 1 {
- gasPrice = defaultGasPrice
- }
- // Setting the values into the transaction-options object
- auth := bind.NewKeyedTransactor(privateKey)
- auth.Nonce = big.NewInt(int64(nonce))
- auth.Value = big.NewInt(0)
- auth.GasLimit = uint64(1000000)
- auth.GasPrice = gasPrice
- return auth, nil
- }
- func getDitCoordinatorInstance(_connection *ethclient.Client, _ditCoordinatorAddress ...string) (*ditCoordinator.DitCoordinator, error) {
- var ditCoordinatorAddressString string
- if len(_ditCoordinatorAddress) > 0 {
- ditCoordinatorAddressString = _ditCoordinatorAddress[0]
- } else {
- if len(config.DitConfig.DitCoordinator) != correctETHAddressLength {
- return nil, errors.New("Invalid ditCoordinator address, please do '" + helpers.ColorizeCommand("set_coordinator") + "' first")
- }
- ditCoordinatorAddressString = config.DitConfig.DitCoordinator
- }
- // Convertig the hex-string-formatted address into an address object
- ditCoordinatorAddress := common.HexToAddress(ditCoordinatorAddressString)
- // Create a new instance of the ditCoordinator to access it
- ditCoordinatorInstance, err := ditCoordinator.NewDitCoordinator(ditCoordinatorAddress, _connection)
- if err != nil {
- return nil, errors.New("Failed to find ditCoordinator at provided address")
- }
- return ditCoordinatorInstance, nil
- }
- func getDitDemoCoordinatorInstance(_connection *ethclient.Client, _ditDemoCoordinatorAddress ...string) (*ditDemoCoordinator.DitDemoCoordinator, error) {
- var ditDemoCoordinatorAddressString string
- if len(_ditDemoCoordinatorAddress) > 0 {
- ditDemoCoordinatorAddressString = _ditDemoCoordinatorAddress[0]
- } else {
- if len(config.DitConfig.DitCoordinator) != correctETHAddressLength {
- return nil, errors.New("Invalid ditDemoCoordinator address, please do '" + helpers.ColorizeCommand("set_coordinator") + "' first")
- }
- ditDemoCoordinatorAddressString = config.DitConfig.DitCoordinator
- }
- // Convertig the hex-string-formatted address into an address object
- ditDemoCoordinatorAddress := common.HexToAddress(ditDemoCoordinatorAddressString)
- // Create a new instance of the ditDemoCoordinator to access it
- ditDemoCoordinatorInstance, err := ditDemoCoordinator.NewDitDemoCoordinator(ditDemoCoordinatorAddress, _connection)
- if err != nil {
- return nil, errors.New("Failed to find ditDemoCoordinator at provided address")
- }
- return ditDemoCoordinatorInstance, nil
- }
- func getKNWTokenInstance(_connection *ethclient.Client) (*KNWToken.KNWToken, error) {
- KNWTokenAddress := common.HexToAddress(config.DitConfig.KNWToken)
- // Create a new instance of the KNWToken contract to access it
- KNWTokenInstance, err := KNWToken.NewKNWToken(KNWTokenAddress, _connection)
- if err != nil {
- return nil, errors.New("Failed to find KNWToken at provided address")
- }
- return KNWTokenInstance, nil
- }
- func getDitTokenInstance(_connection *ethclient.Client) (*ditToken.MintableERC20, error) {
- ditTokenAddress := common.HexToAddress(config.DitConfig.DitToken)
- // Create a new instance of the KNWToken contract to access it
- ditTokenInstance, err := ditToken.NewMintableERC20(ditTokenAddress, _connection)
- if err != nil {
- return nil, errors.New("Failed to find ditToken at provided address")
- }
- return ditTokenInstance, nil
- }
- func getKNWVotingInstance(_connection *ethclient.Client) (*KNWVoting.KNWVoting, error) {
- KNWVotingAddress := common.HexToAddress(config.DitConfig.KNWVoting)
- // Create a new instance of the KNWVoting contract to access it
- KNWVotingInstance, err := KNWVoting.NewKNWVoting(KNWVotingAddress, _connection)
- if err != nil {
- return nil, errors.New("Failed to find KNWVoting at provided address")
- }
- return KNWVotingInstance, nil
- }
- // getConnection will return a connection to the ethereum blockchain
- func getConnection() (*ethclient.Client, error) {
- // Connecting to rinkeby via infura
- connection, err := ethclient.Dial("https://sokol.poa.network")
- if err != nil {
- return nil, errors.New("Failed to connect to the ethereum network")
- }
- return connection, nil
- }
- // searchForRepoInConfig will search for the current repo in the config
- func searchForRepoInConfig() (int64, error) {
- // Retrieve the name of the repo we are in from git
- repository, err := git.GetRepository()
- if err != nil {
- return 0, err
- }
- var repositoryArray []config.Repository
- if config.DitConfig.DemoModeActive {
- repositoryArray = config.DitConfig.DemoRepositories
- } else {
- repositoryArray = config.DitConfig.LiveRepositories
- }
- // Search for the repo in our config
- for i := range repositoryArray {
- if repositoryArray[i].Name == repository {
- // Return the index of this repository if it was found
- return int64(i), nil
- }
- }
- // Return an error if nothing was found
- return 0, errors.New("Repository hasn't been initialized")
- }
- // GetHashOfString takes a string a returns it as keccak256
- func GetHashOfString(_string string) [32]byte {
- repoHash32 := [32]byte{}
- copy(repoHash32[:], crypto.Keccak256([]byte(_string))[:])
- return repoHash32
- }
|