Skip to content

Commit

Permalink
add parameter truncateByDeimals to holders by strategy endpoint
Browse files Browse the repository at this point in the history
Truncate will take the number of decimals of the token (if > 0)
and will compute the holders balance without them.

Signed-off-by: p4u <pau@dabax.net>
  • Loading branch information
p4u committed Aug 28, 2024
1 parent 2755159 commit 246d1ea
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 15 deletions.
2 changes: 1 addition & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ func (capi *census3API) CreateInitialTokens(tokensPath string) error {
return err
}
defer func() {
if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) {
if err := tx.Rollback(); err != nil && !errors.Is(err, sql.ErrTxDone) {
log.Errorw(err, "create token transaction rollback failed")
}
}()
Expand Down
4 changes: 2 additions & 2 deletions api/censuses.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (capi *census3API) createAndPublishCensus(req *Census, qID string) (uint64,
return 0, ErrCantCreateCensus.WithErr(err)
}
defer func() {
if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) {
if err := tx.Rollback(); err != nil && !errors.Is(err, sql.ErrTxDone) {
log.Errorw(err, "holders transaction rollback failed")
}
}()
Expand Down Expand Up @@ -154,7 +154,7 @@ func (capi *census3API) createAndPublishCensus(req *Census, qID string) (uint64,
// init some variables to get computed in the following steps
calculateStrategyProgress := capi.queue.StepProgressChannel(qID, 1, 3)
strategyHolders, censusWeight, totalTokensBlockNumber, err := capi.CalculateStrategyHolders(
internalCtx, strategy.Predicate, strategyTokensBySymbol, calculateStrategyProgress)
internalCtx, strategy.Predicate, strategyTokensBySymbol, calculateStrategyProgress, false)
if err != nil {
return 0, ErrEvalStrategyPredicate.WithErr(err)
}
Expand Down
17 changes: 17 additions & 0 deletions api/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ func InnerCensusID(blockNumber, strategyID uint64, anonymous bool) uint64 {
// combines them.
func (capi *census3API) CalculateStrategyHolders(ctx context.Context,
predicate string, tokens map[string]*StrategyToken, progressCh chan float64,
truncateByDecimals bool,
) (map[common.Address]*big.Int, *big.Int, uint64, error) {
// TODO: write a benchmark and try to optimize this function

Expand Down Expand Up @@ -297,6 +298,7 @@ func (capi *census3API) CalculateStrategyHolders(ctx context.Context,
if token == nil {
return nil, nil, totalTokensBlockNumber, fmt.Errorf("token not found for predicate: %s", validPredicate.String())
}

// get the strategy holders from the database
holders, err := capi.db.QueriesRO.TokenHoldersByMinBalance(ctx,
queries.TokenHoldersByMinBalanceParams{
Expand All @@ -311,13 +313,25 @@ func (capi *census3API) CalculateStrategyHolders(ctx context.Context,
}
return nil, nil, totalTokensBlockNumber, err
}

// Convert decimals to *big.Int by calculating 10^decimals
decimalsBigInt := new(big.Int).SetUint64(0)
if ti, ok := tokensInfo[validPredicate.String()]; ok && truncateByDecimals {
decimalsBigInt = new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(ti.Decimals)), nil)
}

// parse holders addresses and balances
for _, holder := range holders {
holderAddr := common.BytesToAddress(holder.HolderID)
holderBalance, ok := new(big.Int).SetString(holder.Balance, 10)
if !ok {
return nil, nil, totalTokensBlockNumber, fmt.Errorf("error decoding balance of holder %s", holderAddr.String())
}
// truncate the balance by the decimals if required
if truncateByDecimals && decimalsBigInt.Uint64() > 0 {
holderBalance = new(big.Int).Div(holderBalance, decimalsBigInt)
}

if _, exists := strategyHolders[holderAddr]; !exists {
strategyHolders[holderAddr] = holderBalance
censusWeight = new(big.Int).Add(censusWeight, holderBalance)
Expand All @@ -332,6 +346,9 @@ func (capi *census3API) CalculateStrategyHolders(ctx context.Context,
if err != nil {
return nil, nil, totalTokensBlockNumber, err
}

// TODO: the truncateByDEcimals is not implemented for complex predicates

// parse the evaluation results
for address, value := range res.Data {
strategyHolders[common.HexToAddress(address)] = value
Expand Down
14 changes: 9 additions & 5 deletions api/strategies.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (capi *census3API) getStrategies(msg *api.APIdata, ctx *httprouter.HTTPCont
return ErrCantGetStrategies.WithErr(err)
}
defer func() {
if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) {
if err := tx.Rollback(); err != nil && !errors.Is(err, sql.ErrTxDone) {
log.Errorw(err, "create strategy transaction rollback failed")
}
}()
Expand Down Expand Up @@ -195,7 +195,7 @@ func (capi *census3API) createStrategy(msg *api.APIdata, ctx *httprouter.HTTPCon
return ErrCantCreateStrategy.WithErr(err)
}
defer func() {
if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) {
if err := tx.Rollback(); err != nil && !errors.Is(err, sql.ErrTxDone) {
log.Errorw(err, "create strategy transaction rollback failed")
}
}()
Expand Down Expand Up @@ -368,7 +368,7 @@ func (capi *census3API) importStrategyDump(ipfsURI string, dump []byte) (uint64,
return 0, ErrCantCreateStrategy.WithErr(err)
}
defer func() {
if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) {
if err := tx.Rollback(); err != nil && !errors.Is(err, sql.ErrTxDone) {
log.Errorw(err, "create strategy transaction rollback failed")
}
}()
Expand Down Expand Up @@ -561,6 +561,10 @@ func (capi *census3API) launchStrategyHolders(_ *api.APIdata, ctx *httprouter.HT
return ErrMalformedStrategyID.WithErr(err)
}
strategyID := uint64(iStrategyID)

// get truncateByDecimals from query params and decode it as boolean
truncateByDecimals := ctx.Request.URL.Query().Get("truncateByDecimals") == "true"

// get token information from the database
checkCtx, cancel := context.WithTimeout(ctx.Request.Context(), checkStrategyHoldersTimeout)
defer cancel()
Expand Down Expand Up @@ -597,7 +601,7 @@ func (capi *census3API) launchStrategyHolders(_ *api.APIdata, ctx *httprouter.HT
}
}
strategyHolders, _, _, err := capi.CalculateStrategyHolders(
bgCtx, strategy.Predicate, strategyTokensBySymbol, nil)
bgCtx, strategy.Predicate, strategyTokensBySymbol, nil, truncateByDecimals)
if err != nil {
if ok := capi.queue.Fail(queueID, ErrEvalStrategyPredicate.WithErr(err)); !ok {
log.Errorf("error updating list strategy holders queue %s", queueID)
Expand Down Expand Up @@ -713,7 +717,7 @@ func (capi *census3API) estimateStrategySizeAndAccuracy(queueID string,
}
// calculate the strategy holders
strategyHolders, _, _, err := capi.CalculateStrategyHolders(internalCtx,
strategy.Predicate, strategy.Tokens, calculateStrategyProgress)
strategy.Predicate, strategy.Tokens, calculateStrategyProgress, false)
if err != nil {
return 0, 0, ErrEvalStrategyPredicate.WithErr(err)
}
Expand Down
4 changes: 2 additions & 2 deletions api/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func (capi *census3API) createToken(msg *api.APIdata, ctx *httprouter.HTTPContex
return ErrCantCreateStrategy.WithErr(err)
}
defer func() {
if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) {
if err := tx.Rollback(); err != nil && !errors.Is(err, sql.ErrTxDone) {
log.Errorw(err, "create strategy transaction rollback failed")
}
}()
Expand Down Expand Up @@ -360,7 +360,7 @@ func (capi *census3API) deleteToken(address common.Address, chainID uint64, exte
return ErrCantGetTokens.WithErr(err)
}
defer func() {
if err := tx.Rollback(); err != nil && !errors.Is(sql.ErrTxDone, err) {
if err := tx.Rollback(); err != nil && !errors.Is(err, sql.ErrTxDone) {
log.Errorw(err, "error rolling back tokens transaction")
}
}()
Expand Down
2 changes: 1 addition & 1 deletion apiclient/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const (
// parameters
CreateStrategyURI = "/strategies"
// GetTokenHoldersByStrategyURI is the URI for getting token holders of a given strategy
GetTokenHoldersByStrategyURI = "/strategies/%d/holders"
GetTokenHoldersByStrategyURI = "/strategies/%d/holders?truncateByDecimals=%s"
// GetTokenHoldersByStrategyURI is the URI for getting token holders of a given strategy
GetTokenHoldersByStrategyQueueURI = "/strategies/%d/holders/queue/%s"

Expand Down
12 changes: 8 additions & 4 deletions apiclient/strategies.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@ func (c *HTTPclient) Strategy(strategyID uint64) (*api.Strategy, error) {
// receives the strategyID and returns the queueID of the task and an error if
// something went wrong. The status of the task can be checked with the
// HoldersByStrategyQueue method.
func (c *HTTPclient) HoldersByStrategy(strategyID uint64) (string, error) {
// If truncateByDecimals is true, the amounts will be truncated by the decimals
// of the token (if > 0). Truncate only works for simple strategies (single token).
func (c *HTTPclient) HoldersByStrategy(strategyID uint64, truncateByDecimals bool) (string, error) {
// construct the URL to the API with the given parameters
endpoint := fmt.Sprintf(GetTokenHoldersByStrategyURI, strategyID)
endpoint := fmt.Sprintf(GetTokenHoldersByStrategyURI, strategyID, fmt.Sprintf("%t", truncateByDecimals))
u, err := c.constructURL(endpoint)
if err != nil {
return "", fmt.Errorf("%w: %w", ErrConstructingURL, err)
Expand Down Expand Up @@ -193,8 +195,10 @@ func (c *HTTPclient) HoldersByStrategyQueue(strategyID uint64, queueID string) (
// strategy, it receives the strategyID and returns a map of addresses and
// amounts and an error if something went wrong. This method is a wrapper
// around the HoldersByStrategy and HoldersByStrategyQueue methods.
func (c *HTTPclient) AllHoldersByStrategy(strategyID uint64) (map[common.Address]*big.Int, error) {
queueID, err := c.HoldersByStrategy(strategyID)
// If truncateByDecimals is true, the amounts will be truncated by the decimals
// of the token (if > 0). Truncate only works for simple strategies (single token).
func (c *HTTPclient) AllHoldersByStrategy(strategyID uint64, truncateByDecimals bool) (map[common.Address]*big.Int, error) {
queueID, err := c.HoldersByStrategy(strategyID, truncateByDecimals)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 246d1ea

Please sign in to comment.