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  }