github.com/DapperCollectives/CAST/backend@v0.0.0-20230921221157-1350c8be7c96/main/strategies/token_weighted_default.go (about)

     1  package strategies
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  
     7  	"github.com/DapperCollectives/CAST/backend/main/models"
     8  	s "github.com/DapperCollectives/CAST/backend/main/shared"
     9  	shared "github.com/DapperCollectives/CAST/backend/main/shared"
    10  	"github.com/rs/zerolog/log"
    11  )
    12  
    13  type TokenWeightedDefault struct {
    14  	s.StrategyStruct
    15  	DB *s.Database
    16  }
    17  
    18  func (s *TokenWeightedDefault) FetchBalance(
    19  	b *models.Balance,
    20  	p *models.Proposal,
    21  ) (*models.Balance, error) {
    22  
    23  	var c models.Community
    24  	if err := c.GetCommunityByProposalId(s.DB, b.Proposal_id); err != nil {
    25  		return nil, err
    26  	}
    27  
    28  	strategy, err := models.MatchStrategyByProposal(*c.Strategies, *p.Strategy)
    29  	if err != nil {
    30  		log.Error().Err(err).Msg("Unable to find strategy for contract")
    31  		return nil, err
    32  	}
    33  
    34  	if err := s.FetchBalanceFromSnapshot(&strategy, b); err != nil {
    35  		log.Error().Err(err).Msg("Error calling snapshot client")
    36  		return nil, err
    37  	}
    38  
    39  	if err := b.CreateBalance(s.DB); err != nil {
    40  		log.Error().Err(err).Msg("Error creating balance in the database.")
    41  		return nil, err
    42  	}
    43  
    44  	return b, nil
    45  }
    46  
    47  func (s *TokenWeightedDefault) FetchBalanceFromSnapshot(
    48  	strategy *models.Strategy,
    49  	b *models.Balance,
    50  ) error {
    51  
    52  	var ftBalance = &shared.FTBalanceResponse{}
    53  	ftBalance.NewFTBalance()
    54  
    55  	if *strategy.Contract.Name == "FlowToken" {
    56  		if err := s.FlowAdapter.GetAddressBalanceAtBlockHeight(
    57  			b.Addr,
    58  			b.BlockHeight,
    59  			ftBalance,
    60  			&strategy.Contract,
    61  		); err != nil {
    62  			log.Error().Err(err).Msg("Error fetching balance from snapshot client")
    63  			return err
    64  		}
    65  		b.PrimaryAccountBalance = ftBalance.PrimaryAccountBalance
    66  		b.SecondaryAccountBalance = ftBalance.SecondaryAccountBalance
    67  		b.StakingBalance = ftBalance.StakingBalance
    68  
    69  	} else {
    70  		if err := s.FlowAdapter.GetAddressBalanceAtBlockHeight(
    71  			b.Addr,
    72  			b.BlockHeight,
    73  			ftBalance,
    74  			&strategy.Contract,
    75  		); err != nil {
    76  			log.Error().Err(err).Msg("Error fetching balance.")
    77  			return err
    78  		}
    79  		b.PrimaryAccountBalance = ftBalance.Balance
    80  		b.SecondaryAccountBalance = 0
    81  		b.StakingBalance = 0
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  func (s *TokenWeightedDefault) TallyVotes(
    88  	votes []*models.VoteWithBalance,
    89  	r *models.ProposalResults,
    90  	p *models.Proposal,
    91  ) (models.ProposalResults, error) {
    92  
    93  	for _, vote := range votes {
    94  		if vote.PrimaryAccountBalance != nil {
    95  			var allowedBalance float64
    96  
    97  			if p.Max_weight != nil {
    98  				allowedBalance = p.EnforceMaxWeight(float64(*vote.PrimaryAccountBalance))
    99  			} else {
   100  				allowedBalance = float64(*vote.PrimaryAccountBalance)
   101  			}
   102  
   103  			r.Results[vote.Choice] += int(allowedBalance)
   104  			r.Results_float[vote.Choice] += allowedBalance * math.Pow(10, -8)
   105  		}
   106  	}
   107  
   108  	return *r, nil
   109  }
   110  
   111  func (s *TokenWeightedDefault) GetVoteWeightForBalance(
   112  	vote *models.VoteWithBalance,
   113  	proposal *models.Proposal,
   114  ) (float64, error) {
   115  	var weight float64
   116  	var ERROR error = fmt.Errorf("No weight found, address: %s, strategy: %s.", vote.Addr, *proposal.Strategy)
   117  
   118  	if vote.PrimaryAccountBalance == nil {
   119  		return 0.00, nil
   120  	}
   121  
   122  	weight = float64(*vote.PrimaryAccountBalance) * math.Pow(10, -8)
   123  
   124  	switch {
   125  	case proposal.Max_weight != nil && weight > *proposal.Max_weight:
   126  		weight = *proposal.Max_weight
   127  		return weight, nil
   128  	case proposal.Max_weight != nil && weight < *proposal.Max_weight:
   129  		return weight, nil
   130  	case weight == 0.00:
   131  		return 0.00, nil
   132  	case weight > 0.00:
   133  		return weight, nil
   134  	default:
   135  		return weight, ERROR
   136  	}
   137  }
   138  
   139  func (s *TokenWeightedDefault) GetVotes(
   140  	votes []*models.VoteWithBalance,
   141  	proposal *models.Proposal,
   142  ) ([]*models.VoteWithBalance, error) {
   143  
   144  	for _, vote := range votes {
   145  		weight, err := s.GetVoteWeightForBalance(vote, proposal)
   146  		if err != nil {
   147  			return nil, err
   148  		}
   149  		vote.Weight = &weight
   150  	}
   151  	return votes, nil
   152  }
   153  
   154  func (s *TokenWeightedDefault) RequiresSnapshot() bool {
   155  	return true
   156  }
   157  
   158  func (s *TokenWeightedDefault) InitStrategy(
   159  	f *shared.FlowAdapter,
   160  	db *shared.Database,
   161  ) {
   162  	s.FlowAdapter = f
   163  	s.DB = db
   164  }