Part four in our series demonstrating how we are building the NgRx powered DApp for the FleaMarket Smart Contract

Alex Yevseyevich
Jul 20 · 7 min read
Image by Stefan Keller from Pixabay

In the previous piece, we talked about how to employ the IPFS to store the seller’s product images. In this piece, we will focus on creating the SafeRemotePurchase contract instances by utilizing the NgRx entity state adapter.

The source code for this module is located in this GitHub.

Refactoring the Solidity FleaMarket Smart Contract

On every new product we’re putting up for sale, the FleaMarket smart contract will spawn a new child product contract represented by the SafeRemotePurchase smart contract. We deal with the implementation of the Solidity CRUD pattern with the following requirements:

  • Each product has a unique key;
  • Ensure key uniqueness;
  • Insert a product with a key identifier;
  • Retrieve a product by its key identifier;
  • Obtain a count of the products that exist; and
  • Iterating over the products.

Fortunately, a general-purpose library HitchensUnorderedKeySet that tackles this task has been introduced by Rob Hitchens in his great post Solidity CRUD- Epilogue.

After applying this pattern to the FleaMarket smart contract, the portion responsible for managing the instances of SafeRemotePurchase will look like this:

NgRx: Having Fun with Material Snackbar

When we are dealing with DApps, it often involves some time for a transaction to return from the state-changing operations on the Ethereum blockchain. From the user experience point of view, we should give some visible indication of the result of these operations. In Part I, we already implemented the loading and error states, a part of the NgRx global store. In this section, we are going to look at how to add the snackbar notification state also.

We start with defining a custom snackbar component that could receive the notification data.

The snackbar state is managed by dispatching the following action to the store:

This action is being handled by Effect:

The immediate advantage of managing the snackbar state globally is that we can trigger the snackbar notification both from a component or directly from a side effect. For example, in case of the error effect:

The result may look like this:

Seeding the Feature Module

We are planning to use the NgRx entity state library @ngrx/entity to manage a collection of the purchase contract entities. Let’s bundle all related functionality in a separate lazy-loaded feature module calledP2pBazaarModule.

Building the Smart Contract Services

The first service is responsible for communication with the FleaMarket smart contract. Start by defining the injectable contract token:

Here we store the address of the deployed FleaMarket contract in the environment object. We are also taking advantage of the Human-Readable ABI of the ethers.js library. We only have to specify functions and events signatures we are going to use. By having the contract address and the ABI definition, that’s all we need to identify our smart contract on the Ethereum blockchain.

Now that we have the injectable contract token, we can define the FleaMarketContract service.

The service method createPurchaseContract is responsible for creating SafeRemotePurchase smart contract entities defined in the FleaMarket.sol smart contract. One of the features of the ethers.js is that the transaction we send to a node becomes available to us even before it is mined. While waiting for a transaction to be mined, we may choose to implement some other side effects, such as to store some transaction details in an external database. Once a new contract has been created and mined, we should receive the transaction receipt txReceipt, that contains, among other things, the last emitted event,logNewPurchaseContract(address contractAddress). We can use this event object to retrieve the contract address value passed to it as an argument: txEvent.args[‘contractAddress’].

Our next service will provide the functionality to communicate with the SafeRemotePurchase child contracts.

Currently, it has only one method that takes the contract address, connects to the contract, reads its properties, and flattens them into the purchase contract model.

Note that instead of the module P2pBazaarModule, in both contract token and contract services, we specify the providedIn dependency injection to a lazy dummy module called P2pBazaarAnchorModule. This is to avoid a circular dependencies warning.

Define the Entity State

The purchase contract model has the following type definition:

We manage the collection of the purchase contract entities with the following entity state adapter:

It also specifies the entity unique identifier and the default entity sort order. We then hook up the entity state into the purchase contract feature state:

Creating a New Purchase Contract in Actions

To wire up the new purchase contract logic, we need to enter the contract details into the angular material reactive form:

We entered the amount of ETH worth two times the value because we want the purchase price to be 0.03 ETH. We also selected the product image and added it to the IPFS file system and received the corresponding hash code.

Once we satisfy the reactive form validation requirements, the button labeled Create Contractbecomes active, and we can trigger the store action that carries the reactive form fields values in its payload.

The action is dispatched to the store effect createProduct$:

We use the exhaustMapoperator to retrieve the action payload data object. The advantage of using this mapping operator is that it will ignore sequential requests while the current one is still ongoing. We then pass the payload as a parameter into thecreatePurchaseContract service method. Because we are trying to alter the state of the FleaMarket smart contract, it will create a transaction on the Ethereum blockchain and we have to pay the gas fee for it in Ethers. At that moment the MetaMask will pop up, asking to confirm the transaction:

Once we approve the transaction, we are waiting for a successful purchase contract execution. The method createPurchaseContract gets resolved with a new purchase contract address. We pipe this value to the switchMap operator and dispatch the createPurchaseContractSuccess action to the store.

We also dispatch the getBalance action to update the current account balance displayed on the toolbar.

The action that carries the new purchase contract address continues the journey through the feature store and gets picked up by the two store effects. First one is the showSnackbar$:

The showSnackbar$ pops up the success notification message to the user.

The second one is the addProduct$ effect.

This effect strips the new purchase contract address from the action payload and passes it to the service method loadPurchaseContract as a parameter. The method then reads the purchase contract properties from the blockchain and wraps them up in the corresponding PurchaseContractModel. We dispatch the addProduct action to add this new entry to the entity state collection of the PurchaseContractMode objects.

We can confirm that the new purchase contract has been added to the store state collection by opening the Redux DevTools Chrome extension.

The new purchase contract can be viewed also if we open the Remix IDE, connect to the Robsten network, and enter the contract address in “Add Address” field:

Better Programming

Advice for programmers.

Thanks to Daniel Yevseyevich

Alex Yevseyevich

Written by

Enjoy studying modern web and blockchain smart contract technologies. The current focus of interest: Angular, NgRx, Ethereum DApps

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade