@@ -7,22 +7,18 @@ SPDX-License-Identifier: Apache-2.0
7
7
package plain
8
8
9
9
import (
10
+ "bytes"
10
11
"fmt"
11
12
"strconv"
12
13
"strings"
13
14
14
15
"github.com/golang/protobuf/proto"
15
- "github.com/hyperledger/fabric/core/ledger/customtx"
16
16
"github.com/hyperledger/fabric/protos/ledger/queryresult"
17
17
"github.com/hyperledger/fabric/protos/token"
18
18
"github.com/hyperledger/fabric/token/ledger"
19
19
"github.com/pkg/errors"
20
20
)
21
21
22
- var namespace = "tms"
23
-
24
- const tokenInput = "tokenInput"
25
-
26
22
// A Transactor that can transfer tokens.
27
23
type Transactor struct {
28
24
PublicCredential []byte
@@ -128,41 +124,45 @@ func (t *Transactor) getInputsFromTokenIds(tokenIds [][]byte) ([]*token.InputId,
128
124
// check whether the composite key conforms to the composite key of an output
129
125
namespace , components , err := splitCompositeKey (inKey )
130
126
if err != nil {
131
- return nil , "" , 0 , & customtx. InvalidTxError { Msg : fmt .Sprintf ("error splitting input composite key: '%s'" , err )}
127
+ return nil , "" , 0 , errors . New ( fmt .Sprintf ("error splitting input composite key: '%s'" , err ))
132
128
}
133
129
if namespace != tokenOutput {
134
- return nil , "" , 0 , & customtx. InvalidTxError { Msg : fmt .Sprintf ("namespace not '%s': '%s'" , tokenOutput , namespace )}
130
+ return nil , "" , 0 , errors . New ( fmt .Sprintf ("namespace not '%s': '%s'" , tokenOutput , namespace ))
135
131
}
136
132
if len (components ) != 2 {
137
- return nil , "" , 0 , & customtx. InvalidTxError { Msg : fmt .Sprintf ("not enough components in output ID composite key; expected 2, received '%s'" , components )}
133
+ return nil , "" , 0 , errors . New ( fmt .Sprintf ("not enough components in output ID composite key; expected 2, received '%s'" , components ))
138
134
}
139
135
txID := components [0 ]
140
136
index , err := strconv .Atoi (components [1 ])
141
137
if err != nil {
142
- return nil , "" , 0 , & customtx. InvalidTxError { Msg : fmt .Sprintf ("error parsing output index '%s': '%s'" , components [1 ], err )}
138
+ return nil , "" , 0 , errors . New ( fmt .Sprintf ("error parsing output index '%s': '%s'" , components [1 ], err ))
143
139
}
144
140
145
141
// make sure the output exists in the ledger
146
- inBytes , err := t .Ledger .GetState (tokenNamespace , inKey )
142
+ inBytes , err := t .Ledger .GetState (tokenNameSpace , inKey )
147
143
if err != nil {
148
144
return nil , "" , 0 , err
149
145
}
150
146
if inBytes == nil {
151
- return nil , "" , 0 , & customtx. InvalidTxError { Msg : fmt .Sprintf ("input '%s' does not exist" , inKey )}
147
+ return nil , "" , 0 , errors . New ( fmt .Sprintf ("input '%s' does not exist" , inKey ))
152
148
}
153
149
input := & token.PlainOutput {}
154
150
err = proto .Unmarshal (inBytes , input )
155
151
if err != nil {
156
- return nil , "" , 0 , & customtx.InvalidTxError {Msg : fmt .Sprintf ("error unmarshaling input bytes: '%s'" , err )}
152
+ return nil , "" , 0 , errors .New (fmt .Sprintf ("error unmarshaling input bytes: '%s'" , err ))
153
+ }
154
+
155
+ // check the owner of the token
156
+ if ! bytes .Equal (t .PublicCredential , input .Owner ) {
157
+ return nil , "" , 0 , errors .New (fmt .Sprintf ("the requestor does not own inputs" ))
157
158
}
158
159
159
160
// check the token type - only one type allowed per transfer
160
161
if tokenType == "" {
161
162
tokenType = input .Type
162
163
} else if tokenType != input .Type {
163
- return nil , "" , 0 , & customtx. InvalidTxError { Msg : fmt .Sprintf ("two or more token types specified in input: '%s', '%s'" , tokenType , input .Type )}
164
+ return nil , "" , 0 , errors . New ( fmt .Sprintf ("two or more token types specified in input: '%s', '%s'" , tokenType , input .Type ))
164
165
}
165
-
166
166
// add input to list of inputs
167
167
inputs = append (inputs , & token.InputId {TxId : txID , Index : uint32 (index )})
168
168
@@ -175,7 +175,7 @@ func (t *Transactor) getInputsFromTokenIds(tokenIds [][]byte) ([]*token.InputId,
175
175
176
176
// ListTokens creates a TokenTransaction that lists the unspent tokens owned by owner.
177
177
func (t * Transactor ) ListTokens () (* token.UnspentTokens , error ) {
178
- iterator , err := t .Ledger .GetStateRangeScanIterator (namespace , "" , "" )
178
+ iterator , err := t .Ledger .GetStateRangeScanIterator (tokenNameSpace , "" , "" )
179
179
if err != nil {
180
180
return nil , err
181
181
}
@@ -228,7 +228,67 @@ func (t *Transactor) ListTokens() (*token.UnspentTokens, error) {
228
228
}
229
229
230
230
func (t * Transactor ) RequestApprove (request * token.ApproveRequest ) (* token.TokenTransaction , error ) {
231
- panic ("implement me!" )
231
+ if len (request .GetTokenIds ()) == 0 {
232
+ return nil , errors .New ("no token ids in ApproveAllowanceRequest" )
233
+ }
234
+
235
+ if len (request .AllowanceShares ) == 0 {
236
+ return nil , errors .New ("no recipient shares in ApproveAllowanceRequest" )
237
+ }
238
+
239
+ var delegatedOutputs []* token.PlainDelegatedOutput
240
+
241
+ inputs , tokenType , sumQuantity , err := t .getInputsFromTokenIds (request .GetTokenIds ())
242
+ if err != nil {
243
+ return nil , err
244
+ }
245
+
246
+ // prepare approve tx
247
+
248
+ delegatedQuantity := uint64 (0 )
249
+ for _ , share := range request .GetAllowanceShares () {
250
+ if len (share .Recipient ) == 0 {
251
+ return nil , errors .Errorf ("the recipient in approve must be specified" )
252
+ }
253
+ if share .Quantity <= 0 {
254
+ return nil , errors .Errorf ("the quantity to approve [%d] must be greater than 0" , share .GetQuantity ())
255
+ }
256
+ delegatedOutputs = append (delegatedOutputs , & token.PlainDelegatedOutput {
257
+ Owner : []byte (request .Credential ),
258
+ Delegatees : [][]byte {share .Recipient },
259
+ Type : tokenType ,
260
+ Quantity : share .Quantity ,
261
+ })
262
+ delegatedQuantity = delegatedQuantity + share .Quantity
263
+ }
264
+ if sumQuantity < delegatedQuantity {
265
+ return nil , errors .Errorf ("insufficient funds: %v < %v" , sumQuantity , delegatedQuantity )
266
+
267
+ }
268
+ var output * token.PlainOutput
269
+ if sumQuantity != delegatedQuantity {
270
+ output = & token.PlainOutput {
271
+ Owner : request .Credential ,
272
+ Type : tokenType ,
273
+ Quantity : sumQuantity - delegatedQuantity ,
274
+ }
275
+ }
276
+
277
+ transaction := & token.TokenTransaction {
278
+ Action : & token.TokenTransaction_PlainAction {
279
+ PlainAction : & token.PlainTokenAction {
280
+ Data : & token.PlainTokenAction_PlainApprove {
281
+ PlainApprove : & token.PlainApprove {
282
+ Inputs : inputs ,
283
+ DelegatedOutputs : delegatedOutputs ,
284
+ Output : output ,
285
+ },
286
+ },
287
+ },
288
+ },
289
+ }
290
+
291
+ return transaction , nil
232
292
}
233
293
234
294
// isSpent checks whether an output token with identifier outputID has been spent.
@@ -237,7 +297,7 @@ func (t *Transactor) isSpent(outputID string) (bool, error) {
237
297
if err != nil {
238
298
return false , err
239
299
}
240
- result , err := t .Ledger .GetState (namespace , key )
300
+ result , err := t .Ledger .GetState (tokenNameSpace , key )
241
301
if err != nil {
242
302
return false , err
243
303
}
0 commit comments