/
bank.go
130 lines (109 loc) · 2.58 KB
/
bank.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package utils
import (
"fmt"
"sort"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/neutron-org/neutron/v2/x/dex/types"
"github.com/cosmos/cosmos-sdk/types/query"
)
func FilteredPaginateAccountBalances(
ctx sdk.Context,
bankKeeper types.BankKeeper,
address sdk.AccAddress,
pageRequest *query.PageRequest,
onResult func(coin sdk.Coin, accumulate bool) bool,
) (*query.PageResponse, error) {
// if the PageRequest is nil, use default PageRequest
if pageRequest == nil {
pageRequest = &query.PageRequest{}
}
offset := pageRequest.Offset
key := pageRequest.Key
limit := pageRequest.Limit
countTotal := pageRequest.CountTotal
if pageRequest.Reverse {
return nil, fmt.Errorf("invalid request, reverse pagination is not enabled")
}
if offset > 0 && key != nil {
return nil, fmt.Errorf("invalid request, either offset or key is expected, got both")
}
if limit == 0 {
limit = query.DefaultLimit
// count total results when the limit is zero/not supplied
countTotal = true
}
if len(key) != 0 {
// paginate with key
var (
numHits uint64
nextKey []byte
)
startAccum := false
bankKeeper.IterateAccountBalances(ctx, address, func(coin sdk.Coin) bool {
if coin.Denom == string(key) {
startAccum = true
}
if numHits == limit {
nextKey = []byte(coin.Denom)
return true
}
if startAccum {
hit := onResult(coin, true)
if hit {
numHits++
}
}
return false
})
return &query.PageResponse{
NextKey: nextKey,
}, nil
}
// else default pagination (with offset)
end := offset + limit
var (
numHits uint64
nextKey []byte
)
bankKeeper.IterateAccountBalances(ctx, address, func(coin sdk.Coin) bool {
accumulate := numHits >= offset && numHits < end
hit := onResult(coin, accumulate)
if hit {
numHits++
}
if numHits == end+1 {
if nextKey == nil {
nextKey = []byte(coin.Denom)
}
if !countTotal {
return true
}
}
return false
})
res := &query.PageResponse{NextKey: nextKey}
if countTotal {
res.Total = numHits
}
return res, nil
}
// SanitizeCoins takes an unsorted list of coins and sorts them, removes coins with amount zero and combines duplicate coins
func SanitizeCoins(coins []sdk.Coin) sdk.Coins {
sort.SliceStable(coins, func(i, j int) bool {
return coins[i].Denom < coins[j].Denom
})
cleanCoins := sdk.Coins{}
lastDenom := ""
for _, coin := range coins {
if coin.IsZero() {
continue
}
if lastDenom != coin.Denom {
cleanCoins = append(cleanCoins, coin)
} else {
cleanCoins[len(cleanCoins)-1].Add(coin)
}
lastDenom = coin.Denom
}
return cleanCoins
}