forked from stellar/go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
send.go
executable file
·149 lines (125 loc) · 4.94 KB
/
send.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
146
147
148
149
package compliance
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"github.com/fonero-project/fonero-golang/protocols/compliance"
"github.com/fonero-project/fonero-golang/services/internal/bridge-compliance-shared/http/helpers"
"github.com/fonero-project/fonero-golang/services/internal/bridge-compliance-shared/protocols"
)
// SendRequest represents request sent to /send endpoint of compliance server
type SendRequest struct {
// Payment ID - used to resubmit auth request in case of `pending` response.
ID string `form:"id" valid:"required"`
// Source account ID
Source string `form:"source" valid:"required,fonero_accountid"`
// Sender address (like alice*fonero.org)
Sender string `form:"sender" valid:"required,fonero_address"`
// Destination address (like bob*fonero.org)
Destination string `form:"destination" valid:"required,fonero_address"`
// ForwardDestination
ForwardDestination *protocols.ForwardDestination `form:"forward_destination" valid:"-"`
// Amount destination should receive
Amount string `form:"amount" valid:"required,fonero_amount"`
// Code of the asset destination should receive
AssetCode string `form:"asset_code" valid:"optional,fonero_asset_code"`
// Issuer of the asset destination should receive
AssetIssuer string `form:"asset_issuer" valid:"optional,fonero_accountid"`
// Only for path_payment
SendMax string `form:"send_max" valid:"optional,fonero_amount"`
// Only for path_payment
SendAssetCode string `form:"send_asset_code" valid:"optional,fonero_asset_code"`
// Only for path_payment
SendAssetIssuer string `form:"send_asset_issuer" valid:"optional,fonero_accountid"`
// path[n][asset_code] path[n][asset_issuer]
Path []protocols.Asset `form:"path" valid:"-"`
// Extra memo
ExtraMemo string `form:"extra_memo" valid:"-"`
}
// ToValuesSpecial converts special values from http.Request to struct
func (request *SendRequest) FromRequestSpecial(r *http.Request, destination interface{}) error {
var forwardDestination protocols.ForwardDestination
forwardDestination.Domain = r.PostFormValue("forward_destination[domain]")
forwardDestination.Fields = make(url.Values)
err := r.ParseForm()
if err != nil {
return err
}
for key := range r.PostForm {
matches := protocols.FederationDestinationFieldName.FindStringSubmatch(key)
if len(matches) < 2 {
continue
}
fieldName := matches[1]
forwardDestination.Fields.Add(fieldName, r.PostFormValue(key))
}
if forwardDestination.Domain != "" && len(forwardDestination.Fields) > 0 {
request.ForwardDestination = &forwardDestination
}
var path []protocols.Asset
for i := 0; i < 5; i++ {
codeFieldName := fmt.Sprintf(protocols.PathCodeField, i)
issuerFieldName := fmt.Sprintf(protocols.PathIssuerField, i)
// If the element does not exist in PostForm break the loop
if _, exists := r.PostForm[codeFieldName]; !exists {
break
}
code := r.PostFormValue(codeFieldName)
issuer := r.PostFormValue(issuerFieldName)
if code == "" && issuer == "" {
path = append(path, protocols.Asset{})
} else {
path = append(path, protocols.Asset{code, issuer})
}
}
request.Path = path
return nil
}
// ToValuesSpecial adds special values (not easily convertable) to given url.Values
func (request SendRequest) ToValuesSpecial(values url.Values) {
if request.ForwardDestination != nil {
values.Add("forward_destination[domain]", request.ForwardDestination.Domain)
for key := range request.ForwardDestination.Fields {
values.Add(fmt.Sprintf("forward_destination[fields][%s]", key), request.ForwardDestination.Fields.Get(key))
}
}
for i, asset := range request.Path {
values.Set(fmt.Sprintf(protocols.PathCodeField, i), asset.Code)
values.Set(fmt.Sprintf(protocols.PathIssuerField, i), asset.Issuer)
}
}
// Validate is additional validation method to validate special fields.
func (request *SendRequest) Validate(params ...interface{}) error {
if request.Destination == "" && request.ForwardDestination == nil {
return helpers.NewMissingParameter("destination")
}
asset := protocols.Asset{request.AssetCode, request.AssetIssuer}
err := asset.Validate()
if err != nil {
return helpers.NewInvalidParameterError("asset", err.Error())
}
sendAsset := protocols.Asset{request.SendAssetCode, request.SendAssetIssuer}
err = sendAsset.Validate()
if err != nil {
return helpers.NewInvalidParameterError("asset", err.Error())
}
for i, asset := range request.Path {
err := asset.Validate()
if err != nil {
return helpers.NewInvalidParameterError(fmt.Sprintf("path[%d]", i), err.Error())
}
}
return nil
}
// SendResponse represents response returned by /send endpoint
type SendResponse struct {
helpers.SuccessResponse
compliance.AuthResponse `json:"auth_response"`
// xdr.Transaction base64-encoded. Sequence number of this transaction will be equal 0.
TransactionXdr string `json:"transaction_xdr,omitempty"`
}
// Marshal marshals SendResponse
func (response *SendResponse) Marshal() ([]byte, error) {
return json.MarshalIndent(response, "", " ")
}