-
Notifications
You must be signed in to change notification settings - Fork 4
/
onramp.go
106 lines (91 loc) · 3.46 KB
/
onramp.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
package transaction_v2
import (
"context"
"strings"
"time"
"github.com/google/uuid"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
transactionpb "github.com/code-payments/code-protobuf-api/generated/go/transaction/v2"
"github.com/code-payments/code-server/pkg/code/common"
"github.com/code-payments/code-server/pkg/code/data/onramp"
"github.com/code-payments/code-server/pkg/code/data/phone"
"github.com/code-payments/code-server/pkg/code/limit"
currency_lib "github.com/code-payments/code-server/pkg/currency"
"github.com/code-payments/code-server/pkg/grpc/client"
)
func (s *transactionServer) DeclareFiatOnrampPurchaseAttempt(ctx context.Context, req *transactionpb.DeclareFiatOnrampPurchaseAttemptRequest) (*transactionpb.DeclareFiatOnrampPurchaseAttemptResponse, error) {
log := s.log.WithField("method", "DeclareFiatOnrampPurchaseAttempt")
log = client.InjectLoggingMetadata(ctx, log)
var deviceType client.DeviceType
userAgent, err := client.GetUserAgent(ctx)
if err == nil {
deviceType = userAgent.DeviceType
} else {
deviceType = client.DeviceTypeUnknown
}
owner, err := common.NewAccountFromProto(req.Owner)
if err != nil {
log.WithError(err).Warn("invalid owner account")
return nil, status.Error(codes.Internal, "")
}
log = log.WithField("owner_account", owner.PublicKey().ToBase58())
signature := req.Signature
req.Signature = nil
if err := s.auth.Authenticate(ctx, owner, req, signature); err != nil {
return nil, err
}
verificationRecord, err := s.data.GetLatestPhoneVerificationForAccount(ctx, owner.PublicKey().ToBase58())
switch err {
case nil:
case phone.ErrVerificationNotFound:
return &transactionpb.DeclareFiatOnrampPurchaseAttemptResponse{
Result: transactionpb.DeclareFiatOnrampPurchaseAttemptResponse_INVALID_OWNER,
}, nil
default:
log.WithError(err).Warn("failure getting phone verification record")
return nil, status.Error(codes.Internal, "")
}
log = log.WithField("phone_number", verificationRecord.PhoneNumber)
currency := currency_lib.Code(strings.ToLower(req.PurchaseAmount.Currency))
amount := req.PurchaseAmount.NativeAmount
nonce, err := uuid.FromBytes(req.Nonce.Value)
if err != nil {
log.WithError(err).Warn("nonce is invalid")
return nil, status.Error(codes.Internal, "")
}
log = log.WithField("nonce", nonce.String())
// Validate the purchase amount makes sense within defined limits
sendLimit, ok := limit.SendLimits[currency]
if !ok || currency == currency_lib.KIN {
return &transactionpb.DeclareFiatOnrampPurchaseAttemptResponse{
Result: transactionpb.DeclareFiatOnrampPurchaseAttemptResponse_UNSUPPORTED_CURRENCY,
}, nil
} else if amount > sendLimit.PerTransaction {
return &transactionpb.DeclareFiatOnrampPurchaseAttemptResponse{
Result: transactionpb.DeclareFiatOnrampPurchaseAttemptResponse_AMOUNT_EXCEEDS_MAXIMUM,
}, nil
}
record := &onramp.Record{
Owner: owner.PublicKey().ToBase58(),
Platform: int(deviceType),
Currency: string(currency),
Amount: amount,
Nonce: nonce,
CreatedAt: time.Now(),
}
err = s.data.PutFiatOnrampPurchase(ctx, record)
if err != nil && err != onramp.ErrPurchaseAlreadyExists {
log.WithError(err).Warn("failure creating fiat onramp purchase record")
return nil, status.Error(codes.Internal, "")
}
recordBuyModulePurchaseInitiatedEvent(
ctx,
currency,
amount,
deviceType,
)
return &transactionpb.DeclareFiatOnrampPurchaseAttemptResponse{
Result: transactionpb.DeclareFiatOnrampPurchaseAttemptResponse_OK,
}, nil
}