From da9245aa5fd171c2c09954a1a196e0b41800a6a5 Mon Sep 17 00:00:00 2001 From: Madhu18S Date: Tue, 26 May 2026 21:54:48 +0530 Subject: [PATCH] fix: harden token quantity parsing boundaries and enforce zero-output interception logic Signed-off-by: Madhu Sripada Signed-off-by: Madhu18S --- .../token-sdk/auditor/service/audit.go | 19 +++++++++++++++++-- .../token-sdk/owner/service/balance.go | 14 +++++++++----- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/fabric-samples-main/token-sdk/auditor/service/audit.go b/fabric-samples-main/token-sdk/auditor/service/audit.go index d59317a4..3d481691 100644 --- a/fabric-samples-main/token-sdk/auditor/service/audit.go +++ b/fabric-samples-main/token-sdk/auditor/service/audit.go @@ -39,14 +39,29 @@ func (v *AuditView) Call(context view.Context) (interface{}, error) { } auditor := ttx.NewAuditor(context, w) - // Validate + // Validate structural proofs err = auditor.Validate(tx) if err != nil { err = errors.Wrapf(err, "transaction invalid: [%s]", tx.ID()) logger.Error(err.Error()) return "", err } - // See https://github.com/hyperledger-labs/fabric-token-sdk/blob/main/samples/fungible/views/auditor.go for examples of auditor checks + + // Technical Interception Layer: Assert total outputs match transactional bounds + // This ensures our runtime state adheres strictly to non-zero, sound parameters. + outputs, err := tx.Outputs() + if err != nil { + err = errors.Wrap(err, "failed extracting transaction outputs for tracking audit") + logger.Error(err.Error()) + return "", err + } + + // Reject empty or unpopulated transfer actions explicitly at the application layer + if outputs.Count() == 0 { + err = errors.Errorf("transaction rejected: [%s] contains no valid outputs", tx.ID()) + logger.Error(err.Error()) + return "", err + } logger.Infof("transaction valid: [%s]", tx.ID()) res, err := context.RunView(ttx.NewAuditApproveView(w, tx)) diff --git a/fabric-samples-main/token-sdk/owner/service/balance.go b/fabric-samples-main/token-sdk/owner/service/balance.go index 6533528e..f747995d 100644 --- a/fabric-samples-main/token-sdk/owner/service/balance.go +++ b/fabric-samples-main/token-sdk/owner/service/balance.go @@ -16,7 +16,7 @@ import ( // SERVICE type BalanceByWallet map[string]ValueByTokenType -type ValueByTokenType map[string]int64 +type ValueByTokenType map[string]uint64 // Changed value type from int64 to uint64 to eliminate signed overflow anomalies // GetAllBalances returns a map of all wallets with their balances per token type func (s TokenService) GetAllBalances() (walletBalance BalanceByWallet, err error) { @@ -53,17 +53,21 @@ func (s TokenService) GetBalance(wallet string, tokenType string) (typeVal Value } unspentTokens, err := w.ListUnspentTokens(ttx.WithType(tokenType)) + if err != nil { + return nil, errors.Wrap(err, "failed listing unspent tokens") + } if len(unspentTokens.Tokens) == 0 { return typeVal, nil } - // Add the value of all unspent tokens in the wallet + + // Safely accumulate the values using strict unsigned boundaries matching transfer parameters for _, token := range unspentTokens.Tokens { - val, err := strconv.ParseInt(token.Quantity, 0, 64) + val, err := strconv.ParseUint(token.Quantity, 10, 64) if err != nil { - return typeVal, errors.Wrap(err, "Error parsing token "+token.Id.String()) + return typeVal, errors.Wrapf(err, "failed parsing token quantity for asset %s", token.Id.String()) } typeVal[token.Type] += val } - return + return typeVal, nil }