github.com/DapperCollectives/CAST/backend@v0.0.0-20230921221157-1350c8be7c96/main/strategies/float_nfts.go (about) 1 package strategies 2 3 import ( 4 "errors" 5 6 "github.com/DapperCollectives/CAST/backend/main/models" 7 "github.com/DapperCollectives/CAST/backend/main/shared" 8 "github.com/rs/zerolog/log" 9 ) 10 11 type FloatNFTs struct { 12 shared.StrategyStruct 13 DB *shared.Database 14 } 15 16 func (f *FloatNFTs) FetchBalance( 17 balance *models.Balance, 18 p *models.Proposal, 19 ) (*models.Balance, error) { 20 21 v := models.Vote{Proposal_id: balance.Proposal_id, Addr: balance.Addr} 22 vb := &models.VoteWithBalance{ 23 NFTs: []*models.NFT{}, 24 Vote: v, 25 } 26 27 var c models.Community 28 if err := c.GetCommunityByProposalId(f.DB, balance.Proposal_id); err != nil { 29 return nil, err 30 } 31 32 strategy, err := models.MatchStrategyByProposal(*c.Strategies, *p.Strategy) 33 if err != nil { 34 log.Error().Err(err).Msg("Unable to find strategy for contract.") 35 return nil, err 36 } 37 38 if strategy.Contract.Float_event_id == nil { 39 log.Error().Msg("No float event id field was found for contract.") 40 } 41 42 if err := f.queryNFTs(*vb, strategy, balance); err != nil { 43 return nil, err 44 } 45 46 return balance, nil 47 } 48 49 func (f *FloatNFTs) queryNFTs( 50 vb models.VoteWithBalance, 51 strategy models.Strategy, 52 balance *models.Balance, 53 ) error { 54 hasEventNFT, err := f.FlowAdapter.CheckIfUserHasEvent(vb.Vote.Addr, &strategy.Contract) 55 if err != nil { 56 return err 57 } 58 59 if !hasEventNFT { 60 errMsg := "the user does not have this Float event in their wallet" 61 log.Error().Err(err).Msg(errMsg) 62 return errors.New(errMsg) 63 } 64 65 nftIds, err := f.FlowAdapter.GetFloatNFTIds(vb.Vote.Addr, &strategy.Contract) 66 for _, nftId := range nftIds { 67 nft := &models.NFT{ 68 ID: nftId, 69 } 70 vb.NFTs = append(vb.NFTs, nft) 71 } 72 73 doesExist, err := models.DoesNFTExist(f.DB, &vb) 74 if err != nil { 75 return err 76 } 77 78 //in this strategy we don't consider multple NFTs for the same event 79 //so we just use 1 for NFTCount 80 if !doesExist { 81 err = models.CreateUserNFTRecord(f.DB, &vb) 82 balance.NFTCount = 1 // force set to one if user has an event. 83 } 84 85 return err 86 } 87 88 func (f *FloatNFTs) TallyVotes( 89 votes []*models.VoteWithBalance, 90 r *models.ProposalResults, 91 proposal *models.Proposal, 92 ) (models.ProposalResults, error) { 93 94 for _, vote := range votes { 95 if len(vote.NFTs) != 0 { 96 var voteWeight float64 97 98 voteWeight, err := f.GetVoteWeightForBalance(vote, proposal) 99 if err != nil { 100 return models.ProposalResults{}, err 101 } 102 103 r.Results[vote.Choice] += int(voteWeight) 104 r.Results_float[vote.Choice] += voteWeight 105 } 106 } 107 108 return *r, nil 109 } 110 111 func (f *FloatNFTs) GetVoteWeightForBalance(vote *models.VoteWithBalance, proposal *models.Proposal) (float64, error) { 112 nftIds, err := models.GetUserNFTs(f.DB, vote) 113 if err != nil { 114 log.Error().Err(err).Msg("error in GetVoteWeightForBalance for BalanceOfNFTs strategy") 115 return 0.00, err 116 } 117 118 if proposal.Max_weight != nil && float64(len(nftIds)) > *proposal.Max_weight { 119 return *proposal.Max_weight, nil 120 } 121 122 return float64(len(nftIds)), nil 123 } 124 125 func (f *FloatNFTs) GetVotes( 126 votes []*models.VoteWithBalance, 127 proposal *models.Proposal, 128 ) ([]*models.VoteWithBalance, error) { 129 130 for _, vote := range votes { 131 weight, err := f.GetVoteWeightForBalance(vote, proposal) 132 if err != nil { 133 return nil, err 134 } 135 vote.Weight = &weight 136 } 137 138 return votes, nil 139 } 140 141 func (f *FloatNFTs) RequiresSnapshot() bool { 142 return false 143 } 144 145 func (f *FloatNFTs) InitStrategy( 146 fa *shared.FlowAdapter, 147 db *shared.Database, 148 ) { 149 f.FlowAdapter = fa 150 f.DB = db 151 }