github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/sdk/bank/handler.go (about)

     1  package bank
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/gnolang/gno/tm2/pkg/amino"
     8  	abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types"
     9  	"github.com/gnolang/gno/tm2/pkg/crypto"
    10  	"github.com/gnolang/gno/tm2/pkg/sdk"
    11  	"github.com/gnolang/gno/tm2/pkg/std"
    12  )
    13  
    14  type bankHandler struct {
    15  	bank BankKeeper
    16  }
    17  
    18  // NewHandler returns a handler for "bank" type messages.
    19  func NewHandler(bank BankKeeper) bankHandler {
    20  	return bankHandler{
    21  		bank: bank,
    22  	}
    23  }
    24  
    25  func (bh bankHandler) Process(ctx sdk.Context, msg std.Msg) sdk.Result {
    26  	switch msg := msg.(type) {
    27  	case MsgSend:
    28  		return bh.handleMsgSend(ctx, msg)
    29  
    30  	case MsgMultiSend:
    31  		return bh.handleMsgMultiSend(ctx, msg)
    32  
    33  	default:
    34  		errMsg := fmt.Sprintf("unrecognized bank message type: %T", msg)
    35  		return abciResult(std.ErrUnknownRequest(errMsg))
    36  	}
    37  }
    38  
    39  // Handle MsgSend.
    40  func (bh bankHandler) handleMsgSend(ctx sdk.Context, msg MsgSend) sdk.Result {
    41  	/*
    42  		if !bh.bank.GetSendEnabled(ctx) {
    43  			return abciResult(ErrSendDisabled())
    44  		}
    45  		if bh.bank.BlacklistedAddr(msg.ToAddress) {
    46  			return std.ErrUnauthorized(fmt.Sprintf("%s is not allowed to receive transactions", msg.ToAddress)).Result()
    47  		}
    48  	*/
    49  
    50  	err := bh.bank.SendCoins(ctx, msg.FromAddress, msg.ToAddress, msg.Amount)
    51  	if err != nil {
    52  		return abciResult(err)
    53  	}
    54  
    55  	/*
    56  		ctx.EventManager().EmitEvent(
    57  			sdk.NewEvent(
    58  				sdk.EventTypeMessage,
    59  				sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
    60  			),
    61  		)
    62  	*/
    63  
    64  	return sdk.Result{}
    65  }
    66  
    67  // Handle MsgMultiSend.
    68  func (bh bankHandler) handleMsgMultiSend(ctx sdk.Context, msg MsgMultiSend) sdk.Result {
    69  	// NOTE: totalIn == totalOut should already have been checked
    70  	/*
    71  		if !k.GetSendEnabled(ctx) {
    72  			return abciResult(std.ErrSendDisabled())
    73  		}
    74  		for _, out := range msg.Outputs {
    75  			if bh.bank.BlacklistedAddr(out.Address) {
    76  				return abciResult(std.ErrUnauthorized(fmt.Sprintf("%s is not allowed to receive transactions", out.Address)))
    77  			}
    78  		}
    79  	*/
    80  
    81  	err := bh.bank.InputOutputCoins(ctx, msg.Inputs, msg.Outputs)
    82  	if err != nil {
    83  		return abciResult(err)
    84  	}
    85  
    86  	/*
    87  		ctx.EventManager().EmitEvent(
    88  			sdk.NewEvent(
    89  				sdk.EventTypeMessage,
    90  				sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
    91  			),
    92  		)
    93  	*/
    94  
    95  	return sdk.Result{}
    96  }
    97  
    98  //----------------------------------------
    99  // Query
   100  
   101  // query balance path
   102  const QueryBalance = "balances"
   103  
   104  func (bh bankHandler) Query(ctx sdk.Context, req abci.RequestQuery) (res abci.ResponseQuery) {
   105  	switch secondPart(req.Path) {
   106  	case QueryBalance:
   107  		return bh.queryBalance(ctx, req)
   108  	default:
   109  		res = sdk.ABCIResponseQueryFromError(
   110  			std.ErrUnknownRequest("unknown bank query endpoint"))
   111  		return
   112  	}
   113  }
   114  
   115  // queryBalance fetch an account's balance for the supplied height.
   116  // Account address is passed as path component.
   117  func (bh bankHandler) queryBalance(ctx sdk.Context, req abci.RequestQuery) (res abci.ResponseQuery) {
   118  	// parse addr from path.
   119  	b32addr := thirdPart(req.Path)
   120  	addr, err := crypto.AddressFromBech32(b32addr)
   121  	if err != nil {
   122  		res = sdk.ABCIResponseQueryFromError(
   123  			std.ErrInvalidAddress("invalid query address " + b32addr))
   124  	}
   125  
   126  	// get coins from addr.
   127  	bz, err := amino.MarshalJSONIndent(bh.bank.GetCoins(ctx, addr), "", "  ")
   128  	if err != nil {
   129  		res = sdk.ABCIResponseQueryFromError(
   130  			std.ErrInternal(fmt.Sprintf("could not marshal result to JSON: %s", err.Error())))
   131  		return
   132  	}
   133  
   134  	res.Data = bz
   135  	return
   136  }
   137  
   138  //----------------------------------------
   139  // misc
   140  
   141  func abciResult(err error) sdk.Result {
   142  	return sdk.ABCIResultFromError(err)
   143  }
   144  
   145  // returns the second component of a path.
   146  func secondPart(path string) string {
   147  	parts := strings.Split(path, "/")
   148  	if len(parts) < 2 {
   149  		return ""
   150  	} else {
   151  		return parts[1]
   152  	}
   153  }
   154  
   155  // returns the third component of a path.
   156  func thirdPart(path string) string {
   157  	parts := strings.Split(path, "/")
   158  	if len(parts) < 3 {
   159  		return ""
   160  	} else {
   161  		return parts[2]
   162  	}
   163  }