Skip to content

Commit

Permalink
Fix transferFrom function so that we only delete token balances after…
Browse files Browse the repository at this point in the history
… we've verified the funds are available first - not before

Signed-off-by: Rob Evans <[email protected]>
  • Loading branch information
robevansuk committed Jun 26, 2023
1 parent 7671bdd commit 074c5dc
Showing 1 changed file with 42 additions and 22 deletions.
64 changes: 42 additions & 22 deletions token-erc-1155/chaincode-go/chaincode/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package chaincode
import (
"encoding/json"
"fmt"
"github.com/hyperledger/fabric-protos-go/ledger/queryresult"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -949,6 +950,8 @@ func removeBalance(ctx contractapi.TransactionContextInterface, sender string, i
}
defer balanceIterator.Close()

var deferredDeletions = []func() error{}

// Iterate over keys that store balances and add them to partialBalance until
// either the necessary amount is reached or the keys ended
for balanceIterator.HasNext() && partialBalance < neededAmount {
Expand All @@ -972,47 +975,64 @@ func removeBalance(ctx contractapi.TransactionContextInterface, sender string, i
selfRecipientKeyNeedsToBeRemoved = true
selfRecipientKey = queryResponse.Key
} else {
err = ctx.GetStub().DelState(queryResponse.Key)
if err != nil {
return fmt.Errorf("failed to delete the state of %v: %v", queryResponse.Key, err)
}
deferredDeletions = append(deferredDeletions, deferredDelete(ctx, queryResponse))
}
}

if partialBalance < neededAmount {
return fmt.Errorf("sender has insufficient funds for token %v, needed funds: %v, available fund: %v", tokenId, neededAmount, partialBalance)
} else if partialBalance > neededAmount {
// Send the remainder back to the sender
remainder, err := sub(partialBalance, neededAmount)
if err != nil {
return err
}

if selfRecipientKeyNeedsToBeRemoved {
// Set balance for the key that has the same address for sender and recipient
err = setBalance(ctx, sender, sender, tokenId, remainder)
} else {
// enough token funds have been found to perform the update
// now we can delete the token entries to supply updated token balances
for _, deleteFn := range deferredDeletions {
err := deleteFn()
if err != nil {
return err
}
} else {
err = addBalance(ctx, sender, sender, tokenId, remainder)
}
if partialBalance > neededAmount {
// Send the remainder back to the sender
remainder, err := sub(partialBalance, neededAmount)
if err != nil {
return err
}
}

} else {
// Delete self recipient key
err = ctx.GetStub().DelState(selfRecipientKey)
if err != nil {
return fmt.Errorf("failed to delete the state of %v: %v", selfRecipientKey, err)
if selfRecipientKeyNeedsToBeRemoved {
// Set balance for the key that has the same address for sender and recipient
err = setBalance(ctx, sender, sender, tokenId, remainder)
if err != nil {
return err
}
} else {
err = addBalance(ctx, sender, sender, tokenId, remainder)
if err != nil {
return err
}
}

} else {
// Delete self recipient key
err = ctx.GetStub().DelState(selfRecipientKey)
if err != nil {
return fmt.Errorf("failed to delete the state of %v: %v", selfRecipientKey, err)
}
}
}
}

return nil
}

func deferredDelete(ctx contractapi.TransactionContextInterface, queryResponse *queryresult.KV) func() error {
return func() error {
err := ctx.GetStub().DelState(queryResponse.Key)
if err != nil {
return fmt.Errorf("failed to delete the state of %v: %v", queryResponse.Key, err)
}
return nil
}
}

func emitTransferSingle(ctx contractapi.TransactionContextInterface, transferSingleEvent TransferSingle) error {
transferSingleEventJSON, err := json.Marshal(transferSingleEvent)
if err != nil {
Expand Down

0 comments on commit 074c5dc

Please sign in to comment.