---
# System prepended metadata

title: Privacy-Preserving Transactions Module
tags: [Devx tutorial ignite cli, Expand your Blockchain App]

---

# Privacy-Preserving Transactions Module

## Introduction

In this tutorial, we'll create a module for privacy-preserving transactions using the Ignite CLI. This module will allow users to perform transactions while ensuring their details remain confidential.

## Step 1: Scaffold the Blockchain

First, scaffold a new blockchain. We'll call it privacynet:

```bash
ignite scaffold chain privacynet --no-module && cd privacynet
```

## Step 2: Scaffold the Privacy Module

```bash
ignite scaffold module privacy --dep bank
````

This command creates a new module named privacy and ensures it has dependencies on the bank module.


## Step 3: Define the Transaction Type

We need a type to represent a private transaction. Scaffold a `privateTx` type:

```bash
ignite scaffold type privateTx sender receiver amount hash --module privacy
```

## Step 4: Implementing Privacy Logic

**Scaffold the CreatePrivateTx Message**

```bash
ignite scaffold message createPrivateTx sender receiver amount --module privacy
```

**Add the `PrivateTxCountKey`**

In your `x/privacy/types/keys.go` file, add the `PrivateTxCountKey` to the constants:

```go=
const (
    PrivateTxCountKey = "PrivateTxCount-value-"
)
```

**Hashing Transactions**

For privacy, the actual transaction details will be hashed. In `x/privacy/keeper/msg_server_create_private_tx.go`:

```go
package keeper

import (
    "crypto/sha256"
    "encoding/hex"
    "fmt"

    sdk "github.com/cosmos/cosmos-sdk/types"
    banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
    "privacynet/x/privacy/types"
)

func (k Keeper) CreatePrivateTx(ctx sdk.Context, sender, receiver, amount string) error {
    // Hash transaction details
    hash := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%d", sender, receiver, amount)))
    hashStr := hex.EncodeToString(hash[:])

    // Create PrivateTx object
    privateTx := types.PrivateTx{
        Sender: sender,
        Receiver: receiver,
        Amount: amount,
        Hash: hashStr,
    }
    
    // Get the sender's address
    sender, err := sdk.AccAddressFromBech32(msg.Sender)
    if err != nil {
        return nil, err
    }

    // Get the receiver's address
    receiver, err := sdk.AccAddressFromBech32(msg.Receiver)
    if err != nil {
        return nil, err
    }

    // Create the coin amount to be transferred
    amount := sdk.NewCoins(sdk.NewInt64Coin("token", msg.Amount))

    // Use the bank keeper to send coins from the sender to the receiver
    if err := k.bankKeeper.SendCoins(ctx, sender, receiver, amount); err != nil {
        return nil, err
    }

    // Store PrivateTx
    id := k.AppendPrivateTx(ctx, privateTx)

    // Emit an event
    ctx.EventManager().EmitEvent(
        sdk.NewEvent(types.EventTypePrivateTx,
            sdk.NewAttribute(types.AttributeKeyHash, hashStr),
            sdk.NewAttribute(types.AttributeKeyPrivateTxID, fmt.Sprintf("%d", id)),
        ),
    )

    return nil
}
```

Add the `SendCoins` function to your `x/privacy/types/expected_keepers.go` BankKeeper Interfac:

```go
// BankKeeper defines the expected interface for the Bank module.
type BankKeeper interface {
	SpendableCoins(context.Context, sdk.AccAddress) sdk.Coins
	SendCoins(ctx context.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error
	// Methods imported from bank should be defined here
}
```

**Privacy Keeper Methods**

In `x/privacy/keeper/keeper.go`, implement keeper methods to handle private transactions:

```go
package keeper

import (
    "privacynet/x/privacy/types"
)

func (k Keeper) GetPrivateTxCount(ctx sdk.Context) uint64 {
	storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx))
	store := prefix.NewStore(storeAdapter, []byte{})
	byteKey := types.KeyPrefix(types.PrivateTxCountKey)
	bz := store.Get(byteKey)
	if bz == nil {
		return 0
	}
	return binary.BigEndian.Uint64(bz)
}

func (k Keeper) SetPrivateTxCount(ctx sdk.Context, count uint64) {
	storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx))
	store := prefix.NewStore(storeAdapter, []byte{})
	byteKey := types.KeyPrefix(types.PrivateTxCountKey)
	bz := make([]byte, 8)
	binary.BigEndian.PutUint64(bz, count)
	store.Set(byteKey, bz)
}

func (k Keeper) AppendPrivateTx(ctx sdk.Context, privateTx types.PrivateTx) uint64 {
	// Create the store
	storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx))
	store := prefix.NewStore(storeAdapter, types.KeyPrefix(types.PrivateTxCountKey))

	// Convert the PrivateTx ID to bytes
	byteKey := make([]byte, 8)
	binary.BigEndian.PutUint64(byteKey, k.GetPrivateTxCount(ctx))

	// Marshal the PrivateTx
	appenedValue := k.cdc.MustMarshal(&privateTx)

	// Insert the PrivateTx in the store
	store.Set(byteKey, appenedValue)

	// Update the PrivateTx count
	k.SetPrivateTxCount(ctx, k.GetPrivateTxCount(ctx)+1)

	return k.GetPrivateTxCount(ctx) - 1
}

// Other necessary keeper methods
```

This method will store each private transaction in the module's store and maintain a count of all private transactions. It uses a binary encoding to store the transaction IDs.

The module is now capable of creating private transactions, where the details are hashed for confidentiality.