/
request.go
132 lines (118 loc) · 3.03 KB
/
request.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
package swap
import (
"fmt"
tdexv1 "github.com/tdex-network/tdex-daemon/api-spec/protobuf/gen/tdex/v1"
tdexv2 "github.com/tdex-network/tdex-daemon/api-spec/protobuf/gen/tdex/v2"
"github.com/thanhpk/randstr"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
)
type UnblindedInput struct {
Index uint32
Asset string
Amount uint64
AssetBlinder string
AmountBlinder string
}
// RequestOpts is the struct to be given to the Request method
type RequestOpts struct {
Id string
AssetToSend string
AmountToSend uint64
AssetToReceive string
AmountToReceive uint64
Transaction string
InputBlindingKeys map[string][]byte
OutputBlindingKeys map[string][]byte
UnblindedInputs []UnblindedInput
// Fee asset and amount are not (de)serialized, they're used only to check
// that the amounts of the swap request match those of the PSETv2 tx.
FeeAsset string
FeeAmount uint64
}
func (o RequestOpts) validate() error {
if isPsetV0(o.Transaction) {
return validateSwapTxV0(
o.Transaction,
o.InputBlindingKeys,
o.OutputBlindingKeys,
)
}
if isPsetV2(o.Transaction) {
if len(o.UnblindedInputs) <= 0 {
return fmt.Errorf("missing unblinded inputs")
}
return validateSwapRequestTx(o)
}
return fmt.Errorf("invalid swap transaction format")
}
func (o RequestOpts) forV1() bool {
return isPsetV0(o.Transaction)
}
func (o RequestOpts) forV2() bool {
return isPsetV2(o.Transaction)
}
func (o RequestOpts) id() string {
if o.Id != "" {
return o.Id
}
return randstr.Hex(8)
}
func (o RequestOpts) unblindedIns() []*tdexv2.UnblindedInput {
if len(o.UnblindedInputs) <= 0 {
return nil
}
list := make([]*tdexv2.UnblindedInput, 0, len(o.UnblindedInputs))
for _, in := range o.UnblindedInputs {
list = append(list, &tdexv2.UnblindedInput{
Index: in.Index,
Asset: in.Asset,
Amount: in.Amount,
AssetBlinder: in.AssetBlinder,
AmountBlinder: in.AmountBlinder,
})
}
return list
}
// Request takes a RequestOpts struct and returns a serialized protobuf message.
func Request(opts RequestOpts) ([]byte, error) {
if err := opts.validate(); err != nil {
return nil, err
}
id := opts.id()
var message protoreflect.ProtoMessage
switch {
case opts.forV1():
message = &tdexv1.SwapRequest{
Id: id,
// Proposer
AssetP: opts.AssetToSend,
AmountP: opts.AmountToSend,
// Receiver
AssetR: opts.AssetToReceive,
AmountR: opts.AmountToReceive,
// PSETv0
Transaction: opts.Transaction,
// Blinding keys
InputBlindingKey: opts.InputBlindingKeys,
OutputBlindingKey: opts.InputBlindingKeys,
}
case opts.forV2():
fallthrough
default:
message = &tdexv2.SwapRequest{
Id: id,
// Proposer
AssetP: opts.AssetToSend,
AmountP: opts.AmountToSend,
// Receiver
AssetR: opts.AssetToReceive,
AmountR: opts.AmountToReceive,
// PSETv2
Transaction: opts.Transaction,
// Unblinded inputs
UnblindedInputs: opts.unblindedIns(),
}
}
return proto.Marshal(message)
}