forked from stellar/go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
path_payment.go
167 lines (143 loc) · 4.91 KB
/
path_payment.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package txnbuild
import (
"github.com/stellar/go/amount"
"github.com/stellar/go/support/errors"
"github.com/stellar/go/xdr"
)
// PathPayment represents the Stellar path_payment operation. This operation was removed
// in Stellar Protocol 12 and replaced by PathPaymentStrictReceive.
// Deprecated: This operation was renamed to PathPaymentStrictReceive,
// which functions identically.
type PathPayment = PathPaymentStrictReceive
// PathPaymentStrictReceive represents the Stellar path_payment_strict_receive operation. See
// https://developers.stellar.org/docs/start/list-of-operations/
type PathPaymentStrictReceive struct {
SendAsset Asset
SendMax string
Destination string
DestAsset Asset
DestAmount string
Path []Asset
SourceAccount string
}
// BuildXDR for PathPaymentStrictReceive returns a fully configured XDR Operation.
func (pp *PathPaymentStrictReceive) BuildXDR() (xdr.Operation, error) {
// Set XDR send asset
if pp.SendAsset == nil {
return xdr.Operation{}, errors.New("you must specify an asset to send for payment")
}
xdrSendAsset, err := pp.SendAsset.ToXDR()
if err != nil {
return xdr.Operation{}, errors.Wrap(err, "failed to set asset type")
}
// Set XDR send max
xdrSendMax, err := amount.Parse(pp.SendMax)
if err != nil {
return xdr.Operation{}, errors.Wrap(err, "failed to parse maximum amount to send")
}
// Set XDR destination
var xdrDestination xdr.MuxedAccount
err = xdrDestination.SetAddress(pp.Destination)
if err != nil {
return xdr.Operation{}, errors.Wrap(err, "failed to set destination address")
}
// Set XDR destination asset
if pp.DestAsset == nil {
return xdr.Operation{}, errors.New("you must specify an asset for destination account to receive")
}
xdrDestAsset, err := pp.DestAsset.ToXDR()
if err != nil {
return xdr.Operation{}, errors.Wrap(err, "failed to set asset type")
}
// Set XDR destination amount
xdrDestAmount, err := amount.Parse(pp.DestAmount)
if err != nil {
return xdr.Operation{}, errors.Wrap(err, "failed to parse amount of asset destination account receives")
}
// Set XDR path
var xdrPath []xdr.Asset
var xdrPathAsset xdr.Asset
for _, asset := range pp.Path {
xdrPathAsset, err = asset.ToXDR()
if err != nil {
return xdr.Operation{}, errors.Wrap(err, "failed to set asset type")
}
xdrPath = append(xdrPath, xdrPathAsset)
}
opType := xdr.OperationTypePathPaymentStrictReceive
xdrOp := xdr.PathPaymentStrictReceiveOp{
SendAsset: xdrSendAsset,
SendMax: xdrSendMax,
Destination: xdrDestination,
DestAsset: xdrDestAsset,
DestAmount: xdrDestAmount,
Path: xdrPath,
}
body, err := xdr.NewOperationBody(opType, xdrOp)
if err != nil {
return xdr.Operation{}, errors.Wrap(err, "failed to build XDR OperationBody")
}
op := xdr.Operation{Body: body}
SetOpSourceAccount(&op, pp.SourceAccount)
return op, nil
}
// FromXDR for PathPaymentStrictReceive initialises the txnbuild struct from the corresponding xdr Operation.
func (pp *PathPaymentStrictReceive) FromXDR(xdrOp xdr.Operation) error {
result, ok := xdrOp.Body.GetPathPaymentStrictReceiveOp()
if !ok {
return errors.New("error parsing path_payment operation from xdr")
}
pp.SourceAccount = accountFromXDR(xdrOp.SourceAccount)
pp.Destination = result.Destination.Address()
pp.DestAmount = amount.String(result.DestAmount)
pp.SendMax = amount.String(result.SendMax)
destAsset, err := assetFromXDR(result.DestAsset)
if err != nil {
return errors.Wrap(err, "error parsing dest_asset in path_payment operation")
}
pp.DestAsset = destAsset
sendAsset, err := assetFromXDR(result.SendAsset)
if err != nil {
return errors.Wrap(err, "error parsing send_asset in path_payment operation")
}
pp.SendAsset = sendAsset
pp.Path = []Asset{}
for _, p := range result.Path {
pathAsset, err := assetFromXDR(p)
if err != nil {
return errors.Wrap(err, "error parsing paths in path_payment operation")
}
pp.Path = append(pp.Path, pathAsset)
}
return nil
}
// Validate for PathPaymentStrictReceive validates the required struct fields. It returns an error if any
// of the fields are invalid. Otherwise, it returns nil.
func (pp *PathPaymentStrictReceive) Validate() error {
_, err := xdr.AddressToMuxedAccount(pp.Destination)
if err != nil {
return NewValidationError("Destination", err.Error())
}
err = validateStellarAsset(pp.SendAsset)
if err != nil {
return NewValidationError("SendAsset", err.Error())
}
err = validateStellarAsset(pp.DestAsset)
if err != nil {
return NewValidationError("DestAsset", err.Error())
}
err = validateAmount(pp.SendMax)
if err != nil {
return NewValidationError("SendMax", err.Error())
}
err = validateAmount(pp.DestAmount)
if err != nil {
return NewValidationError("DestAmount", err.Error())
}
return nil
}
// GetSourceAccount returns the source account of the operation, or the empty string if not
// set.
func (pp *PathPaymentStrictReceive) GetSourceAccount() string {
return pp.SourceAccount
}