@@ -7,22 +7,18 @@ SPDX-License-Identifier: Apache-2.0
77package plain
88
99import (
10+ "bytes"
1011 "fmt"
1112 "strconv"
1213 "strings"
1314
1415 "github.com/golang/protobuf/proto"
15- "github.com/hyperledger/fabric/core/ledger/customtx"
1616 "github.com/hyperledger/fabric/protos/ledger/queryresult"
1717 "github.com/hyperledger/fabric/protos/token"
1818 "github.com/hyperledger/fabric/token/ledger"
1919 "github.com/pkg/errors"
2020)
2121
22- var namespace = "tms"
23-
24- const tokenInput = "tokenInput"
25-
2622// A Transactor that can transfer tokens.
2723type Transactor struct {
2824 PublicCredential []byte
@@ -128,41 +124,45 @@ func (t *Transactor) getInputsFromTokenIds(tokenIds [][]byte) ([]*token.InputId,
128124 // check whether the composite key conforms to the composite key of an output
129125 namespace , components , err := splitCompositeKey (inKey )
130126 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 ))
132128 }
133129 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 ))
135131 }
136132 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 ))
138134 }
139135 txID := components [0 ]
140136 index , err := strconv .Atoi (components [1 ])
141137 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 ))
143139 }
144140
145141 // make sure the output exists in the ledger
146- inBytes , err := t .Ledger .GetState (tokenNamespace , inKey )
142+ inBytes , err := t .Ledger .GetState (tokenNameSpace , inKey )
147143 if err != nil {
148144 return nil , "" , 0 , err
149145 }
150146 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 ))
152148 }
153149 input := & token.PlainOutput {}
154150 err = proto .Unmarshal (inBytes , input )
155151 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" ))
157158 }
158159
159160 // check the token type - only one type allowed per transfer
160161 if tokenType == "" {
161162 tokenType = input .Type
162163 } 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 ))
164165 }
165-
166166 // add input to list of inputs
167167 inputs = append (inputs , & token.InputId {TxId : txID , Index : uint32 (index )})
168168
@@ -175,7 +175,7 @@ func (t *Transactor) getInputsFromTokenIds(tokenIds [][]byte) ([]*token.InputId,
175175
176176// ListTokens creates a TokenTransaction that lists the unspent tokens owned by owner.
177177func (t * Transactor ) ListTokens () (* token.UnspentTokens , error ) {
178- iterator , err := t .Ledger .GetStateRangeScanIterator (namespace , "" , "" )
178+ iterator , err := t .Ledger .GetStateRangeScanIterator (tokenNameSpace , "" , "" )
179179 if err != nil {
180180 return nil , err
181181 }
@@ -228,7 +228,67 @@ func (t *Transactor) ListTokens() (*token.UnspentTokens, error) {
228228}
229229
230230func (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
232292}
233293
234294// isSpent checks whether an output token with identifier outputID has been spent.
@@ -237,7 +297,7 @@ func (t *Transactor) isSpent(outputID string) (bool, error) {
237297 if err != nil {
238298 return false , err
239299 }
240- result , err := t .Ledger .GetState (namespace , key )
300+ result , err := t .Ledger .GetState (tokenNameSpace , key )
241301 if err != nil {
242302 return false , err
243303 }
0 commit comments