Skip to main content
Version: v28

Approve a loan

After a loan request has been made, it is possible for another account to approve the loan and accept the terms proposed by the borrower. This process involves the transfer of the requested funds from the lender to the borrower.

To be eligible for approval, a loan must have a status of "requested." This means that the borrower has made a request for a loan and is waiting for a lender to agree to the terms and provide the funds. Once a lender has decided to approve the loan, they can initiate the transfer of the funds to the borrower.

Upon loan approval, the status of the loan is changed to "approved." This signifies that the funds have been successfully transferred and that the loan agreement is now in effect.

Keeper method

package keeper

import (

errorsmod ""
sdk ""
sdkerrors ""


func (k msgServer) ApproveLoan(goCtx context.Context, msg *types.MsgApproveLoan) (*types.MsgApproveLoanResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
loan, found := k.GetLoan(ctx, msg.Id)
if !found {
return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "key %d doesn't exist", msg.Id)
if loan.State != "requested" {
return nil, errorsmod.Wrapf(types.ErrWrongLoanState, "%v", loan.State)
lender, _ := sdk.AccAddressFromBech32(msg.Creator)
borrower, _ := sdk.AccAddressFromBech32(loan.Borrower)
amount, err := sdk.ParseCoinsNormalized(loan.Amount)
if err != nil {
return nil, errorsmod.Wrap(types.ErrWrongLoanState, "Cannot parse coins in loan amount")
err = k.bankKeeper.SendCoins(ctx, lender, borrower, amount)
if err != nil {
return nil, err
loan.Lender = msg.Creator
loan.State = "approved"
k.SetLoan(ctx, loan)
return &types.MsgApproveLoanResponse{}, nil

ApproveLoan takes a context and a message of type *types.MsgApproveLoan as input, and returns a pointer to a types.MsgApproveLoanResponse and an error.

The function first retrieves a loan object by calling k.GetLoan(ctx, msg.Id), where ctx is a context object, k is the msgServer object, GetLoan is a method on k, and msg.Id is a field of the msg object passed as an argument. If the loan is not found, it returns nil and an error wrapped with sdkerrors.ErrKeyNotFound.

Next, the function checks if the loan's state is "requested". If it is not, it returns nil and an error wrapped with types.ErrWrongLoanState.

If the loan's state is "requested", the function parses the addresses of the lender and borrower from bech32 strings, and then parses the amount of the loan from a string. If there is an error parsing the coins in the loan amount, it returns nil and an error wrapped with types.ErrWrongLoanState.

Otherwise, the function calls the SendCoins method on the k.bankKeeper object, passing it the context, the lender and borrower addresses, and the amount of the loan. It then updates the lender field of the loan object and sets its state to "approved". Finally, it stores the updated loan object by calling k.SetLoan(ctx, loan).

At the end, the function returns a types.MsgApproveLoanResponse object and nil for the error.

Register a custom error

To register the custom error ErrWrongLoanState that is used in the ApproveLoan function, modify the "errors.go" file:

package types

import (
sdkerrors ""

var (
ErrWrongLoanState = sdkerrors.Register(ModuleName, 2, "wrong loan state")