forked from scorum/bitshares-go
/
operations.go
237 lines (199 loc) · 5.61 KB
/
operations.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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
package types
import (
"encoding/json"
"reflect"
"github.com/MixinNetwork/bitshares-go/encoding/transaction"
"github.com/pkg/errors"
)
type Operation interface {
Type() OpType
}
type Operations []Operation
func (ops *Operations) UnmarshalJSON(b []byte) (err error) {
// unmarshal array
var o []json.RawMessage
if err := json.Unmarshal(b, &o); err != nil {
return err
}
// foreach operation
for _, op := range o {
var kv []json.RawMessage
if err := json.Unmarshal(op, &kv); err != nil {
return err
}
if len(kv) != 2 {
return errors.New("invalid operation format: should be name, value")
}
var opType uint16
if err := json.Unmarshal(kv[0], &opType); err != nil {
return err
}
val, err := unmarshalOperation(OpType(opType), kv[1])
if err != nil {
return err
}
*ops = append(*ops, val)
}
return nil
}
type operationTuple struct {
Type OpType
Data Operation
}
func (op *operationTuple) MarshalJSON() ([]byte, error) {
return json.Marshal([]interface{}{
op.Type,
op.Data,
})
}
func (ops Operations) MarshalJSON() ([]byte, error) {
tuples := make([]*operationTuple, 0, len(ops))
for _, op := range ops {
tuples = append(tuples, &operationTuple{
Type: op.Type(),
Data: op,
})
}
return json.Marshal(tuples)
}
func unmarshalOperation(opType OpType, obj json.RawMessage) (Operation, error) {
op, ok := knownOperations[opType]
if !ok {
// operation is unknown wrap it as an unknown operation
val := UnknownOperation{
kind: opType,
Data: obj,
}
return &val, nil
} else {
val := reflect.New(op).Interface()
if err := json.Unmarshal(obj, val); err != nil {
return nil, err
}
return val.(Operation), nil
}
}
var knownOperations = map[OpType]reflect.Type{
TransferOpType: reflect.TypeOf(TransferOperation{}),
LimitOrderCreateOpType: reflect.TypeOf(LimitOrderCreateOperation{}),
LimitOrderCancelOpType: reflect.TypeOf(LimitOrderCancelOperation{}),
}
// UnknownOperation
type UnknownOperation struct {
kind OpType
Data json.RawMessage
}
func (op *UnknownOperation) Type() OpType { return op.kind }
// NewTransferOperation returns a new instance of TransferOperation
func NewTransferOperation(from, to ObjectID, amount, fee AssetAmount) *TransferOperation {
op := &TransferOperation{
From: from,
To: to,
Amount: amount,
Fee: fee,
Extensions: []json.RawMessage{},
}
return op
}
// TransferOperation
type TransferOperation struct {
From ObjectID `json:"from"`
To ObjectID `json:"to"`
Amount AssetAmount `json:"amount"`
Fee AssetAmount `json:"fee"`
Memo *Memo `json:"memo,omitempty"`
Extensions []json.RawMessage `json:"extensions"`
}
type Memo struct {
From PublicKey `json:"from"`
To PublicKey `json:"to"`
Nonce uint64 `json:"nonce"`
Message Buffer `json:"message"`
}
func (p Memo) MarshalTransaction(enc *transaction.Encoder) error {
if err := enc.Encode(p.From); err != nil {
return errors.Wrap(err, "encode from")
}
if err := enc.Encode(p.To); err != nil {
return errors.Wrap(err, "encode to")
}
if err := enc.Encode(p.Nonce); err != nil {
return errors.Wrap(err, "encode nonce")
}
if err := enc.Encode(p.Message); err != nil {
return errors.Wrap(err, "encode Message")
}
return nil
}
func (op *TransferOperation) Type() OpType { return TransferOpType }
func (op *TransferOperation) MarshalTransaction(encoder *transaction.Encoder) error {
enc := transaction.NewRollingEncoder(encoder)
enc.EncodeUVarint(uint64(op.Type()))
enc.Encode(op.Fee)
enc.Encode(op.From)
enc.Encode(op.To)
enc.Encode(op.Amount)
if op.Memo != nil && len(op.Memo.Message) > 0 {
enc.EncodeUVarint(1)
enc.Encode(op.Memo)
} else {
//Memo?
enc.EncodeUVarint(0)
}
//Extensions
enc.EncodeUVarint(0)
return enc.Err()
}
// LimitOrderCreateOperation
type LimitOrderCreateOperation struct {
Fee AssetAmount `json:"fee"`
Seller ObjectID `json:"seller"`
AmountToSell AssetAmount `json:"amount_to_sell"`
MinToReceive AssetAmount `json:"min_to_receive"`
Expiration Time `json:"expiration"`
FillOrKill bool `json:"fill_or_kill"`
Extensions []json.RawMessage `json:"extensions"`
}
func (op *LimitOrderCreateOperation) MarshalTransaction(encoder *transaction.Encoder) error {
enc := transaction.NewRollingEncoder(encoder)
enc.EncodeUVarint(uint64(op.Type()))
enc.Encode(op.Fee)
enc.Encode(op.Seller)
enc.Encode(op.AmountToSell)
enc.Encode(op.MinToReceive)
enc.Encode(op.Expiration)
enc.EncodeBool(op.FillOrKill)
//extensions
enc.EncodeUVarint(0)
return enc.Err()
}
func (op *LimitOrderCreateOperation) Type() OpType { return LimitOrderCreateOpType }
// LimitOrderCancelOpType
type LimitOrderCancelOperation struct {
Fee AssetAmount `json:"fee"`
FeePayingAccount ObjectID `json:"fee_paying_account"`
Order ObjectID `json:"order"`
Extensions []json.RawMessage `json:"extensions"`
}
func (op *LimitOrderCancelOperation) MarshalTransaction(encoder *transaction.Encoder) error {
enc := transaction.NewRollingEncoder(encoder)
enc.EncodeUVarint(uint64(op.Type()))
enc.Encode(op.Fee)
enc.Encode(op.FeePayingAccount)
enc.Encode(op.Order)
// extensions
enc.EncodeUVarint(0)
return enc.Err()
}
func (op *LimitOrderCancelOperation) Type() OpType { return LimitOrderCancelOpType }
// FillOrderOpType
type FillOrderOperation struct {
Order ObjectID
Account ObjectID
Pays AssetAmount
Recives AssetAmount
Fee AssetAmount
Price Price
IsMaker bool
}
func (op *FillOrderOperation) Type() OpType { return FillOrderOpType }