-
Notifications
You must be signed in to change notification settings - Fork 0
/
handler.go
145 lines (119 loc) · 3.99 KB
/
handler.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package grants
import (
"fmt"
"time"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/x/feegrant"
"github.com/cosmos/gogoproto/proto"
"google.golang.org/grpc/codes"
"github.com/desmos-labs/caerus/types"
"github.com/desmos-labs/caerus/utils"
)
type Handler struct {
cdc codec.Codec
chainClient ChainClient
db Database
}
// NewHandler returns a new Handler instance
func NewHandler(client ChainClient, cdc codec.Codec, db Database) *Handler {
return &Handler{
cdc: cdc,
chainClient: client,
db: db,
}
}
// --------------------------------------------------------------------------------------------------------------------
// HandleFeeGrantRequest handles the request of a fee grant from the user having the given token
func (h *Handler) HandleFeeGrantRequest(req *RequestFeeGrantRequest) (*RequestFeeAllowanceResponse, error) {
// Unmarshal the allowance
var allowance feegrant.FeeAllowanceI
err := h.cdc.UnpackAny(req.Allowance, &allowance)
if err != nil {
return nil, err
}
// Get the app details
app, found, err := h.db.GetApp(req.AppID)
if err != nil {
return nil, err
}
if !found {
return nil, utils.WrapErr(codes.FailedPrecondition, "application not found")
}
// Check if the app has granted a MsgGrantFeeAllowance permission
hasGrantedAuthzAuthorization, err := h.chainClient.HasGrantedMsgGrantAllowanceAuthorization(app.WalletAddress)
if err != nil {
return nil, err
}
if !hasGrantedAuthzAuthorization {
return nil, utils.WrapErr(codes.FailedPrecondition, "on-chain authorization not found")
}
// Check if the application has reached the number of requests
requestRateLimit, err := h.db.GetAppFeeGrantRequestsLimit(req.AppID)
if err != nil {
return nil, err
}
requestsCount, err := h.db.GetAppFeeGrantRequestsCount(req.AppID)
if err != nil {
return nil, err
}
if requestRateLimit > 0 && requestsCount >= requestRateLimit {
return nil, utils.NewTooManyRequestsError("number of fee grant requests allowed reached")
}
// Check if the user has already been granted the fee grant
hasBeenGranted, err := h.db.HasFeeGrantBeenGrantedToUser(req.AppID, req.DesmosAddress)
if err != nil {
return nil, err
}
if hasBeenGranted {
return nil, utils.WrapErr(codes.FailedPrecondition, "you have already been granted the authorizations in the past")
}
// Check if the user already has on-chain funds
hasFunds, err := h.chainClient.HasFunds(req.DesmosAddress)
if err != nil {
return nil, err
}
if hasFunds {
return nil, utils.WrapErr(codes.FailedPrecondition, "you already have funds in your wallet")
}
// Check if the user already has an on-chain grant
hasGrant, err := h.chainClient.HasFeeGrant(req.DesmosAddress, app.WalletAddress)
if err != nil {
return nil, err
}
var grantTime *time.Time
if hasGrant {
grantTime = utils.GetTimePointer(time.Now())
}
// Store the request inside the database
request := types.NewFeeGrantRequest(req.AppID, req.DesmosAddress, allowance, time.Now(), grantTime)
err = h.db.SaveFeeGrantRequest(request)
if err != nil {
return nil, err
}
// Return the response
return &RequestFeeAllowanceResponse{RequestId: request.ID}, nil
}
func (h *Handler) HandleRequestFeeGrantDetailsRequest(req *RequestFeeGrantDetailsRequest) (*GetFeeAllowanceDetailsResponse, error) {
request, found, err := h.db.GetFeeGrantRequest(req.AppID, req.FeeGrantAllowanceRequestID)
if err != nil {
return nil, err
}
if !found {
return nil, utils.WrapErr(codes.NotFound, "fee grant request not found")
}
msg, ok := request.Allowance.(proto.Message)
if !ok {
return nil, utils.WrapErr(codes.Internal, fmt.Sprintf("cannot proto marshal %T", msg))
}
allowanceAny, err := codectypes.NewAnyWithValue(msg)
if err != nil {
return nil, err
}
return &GetFeeAllowanceDetailsResponse{
UserDesmosAddress: request.DesmosAddress,
Allowance: allowanceAny,
RequestTime: request.RequestTime,
GrantTime: request.GrantTime,
}, nil
}