While I am in my first steps on web3 development, I am solving an online marketplace exercise. The smart contract is set and works fine in remix. Now I am trying to build a simple front end. I have figured out how to get and set values via web3.js but how to return values (from transactions and mappings) in the front end.
Here is my HTML:
<html >
<head>
<title>Register information at Blockchain</title>
<link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.8.0/web3.min.js"></script>
</head>
<body class="container">
<h1 class="page-header">Decentralized Market</h1>
<br /><br />
<td>Status: <span id="status">Loading...</span></td>
<div class="row">
<div>
<h3 class="sub-header">Connect Wallet</h3>
<form class="form-inline" role="form">
<a href="#" onclick="accessToMetamask()" class="btn btn-primary">Connect METAMASK</a>
<div class="form-group">
<table>
<tr>
<td> Address : </td>
<td>
<label id="accountArea">
</td>
</tr>
</table>
</div>
</form>
</div>
</div>
<div class="row">
<div>
<h3 class="sub-header">Create a New Product</h3>
<form class="form-inline" role="form">
<div class="form-group">
<table>
<tr>
<td><label for="newInfo">Item Name:</label> </td>
<td>
<input class="form-control" id="newInfo">
</td>
</tr>
</table>
</div>
<a href="#" onclick="createanItem()" class="btn btn-primary">Create</a>
<p id="transaction"></p>
</form>
</div>
</div>
<div class="row">
<div>
<h3 class="sub-header">List for sale</h3>
<form class="form-inline" role="form">
<div class="form-group">
<table>
<tr>
<td><label for="newInfo">Item ID:</label> </td>
<td>
<input class="form-control" id="ItemIdSale">
</td>
</tr>
</table>
</div>
<div class="form-group">
<table>
<tr>
<td><label for="newInfo">Item Price:</label> </td>
<td>
<input class="form-control" id="ItemPrice">
</td>
</tr>
</table>
</div>
<a href="#" onclick="createItemSale()" class="btn btn-primary">Create</a>
<p id="transaction"></p>
</form>
</div>
</div>
<div class="row">
<div>
<h3 class="sub-header">Get Event</h3>
<form class="form-inline" role="form">
<a href="#" onclick="itemreturn()" class="btn btn-primary">Get</a>
<div class="form-group">
<table>
<tr>
<td>Info:</td>
<td>
<label id="itemevent">
</td>
</tr>
</table>
</div>
</form>
</div>
</div>
<div class="row">
<div>
<h3 class="sub-header">Get Current Account</h3>
<form class="form-inline" role="form">
<a href="#" onclick="readFromContract()" class="btn btn-primary">Get</a>
<div class="form-group">
<table>
<tr>
<td>Info:</td>
<td>
<label id="readtArea">
</td>
</tr>
</table>
</div>
</form>
</div>
</div>
<script type="text/javascript">
//If I take accessToMetamask function part out, then the code will still work.
//However I will not be able to call a write method. Because I would not have an
//account to send gas.
const ABI = [HERE I INCLUDE THE ABI]
const Address = "0xD2b53fd8b609854aF054DF9010Ba10e8827Dd42a";
async function loadWeb3() {
if (window.ethereum) {
window.web3 = new Web3('http://localhost:7545');
window.ethereum.enable();
}
}
async function loadContract() {
return await new window.web3.eth.Contract(ABI, Address, {gasPrice: '20000000000'});
}
async function load() {
await loadWeb3();
window.contract = await loadContract();
updateStatus('Ready!');
}
async function getCurrentAccount() {
const accounts = await window.web3.eth.getAccounts();
//return account[0];
//const accounts = await ethereum.request({ method: "eth_requestAccounts"});
account = accounts[0];
return account;
}
async function createanItem() {
//const value = document.getElementById("item").innerHTML.value;
value = $("#newInfo").val();
updateStatus(`Creating item: ${value}`);
const account = await getCurrentAccount();
const item = await window.contract.methods.createItem(value).send({ from: account, gas: '1000000' }).then( function(tx) {
console.log("Transaction: ", tx);
//var txinfo = tx;
});
$("#newInfo").val('');
updateStatus(`Item: ${value} created`);
}
async function createItemSale() {
//const value = document.getElementById("item").innerHTML.value;
value1 = $("#ItemIdSale").val();
value2 = $("#ItemPrice").val();
updateStatus(`Listing item: ${value1}`);
const account = await getCurrentAccount();
const item = await window.contract.methods.listItemForSale(value1,value2).send({ from: account, gas: '1000000' }).then( function(tx) {
console.log("Transaction: ", tx);
});
$("#newInfo").val('');
//document.getElementById("transaction").innerHTML = trans;
updateStatus(`Item with ID: ${value1} was listed for ${value2} ETH`);
}
async function itemreturn(){
const event = await window.contract.event.Item(["latest"]);
document.getElementById("itemevent").innerHTML = event;
}
load();
let account;
//const web3 = new Web3('http://localhost:7545');
//let contract = new web3.eth.Contract( ABI , Address);
const accessToMetamask = async () => {
if(window.ethereum !== "undefined") {
const accounts = await ethereum.request({ method: "eth_requestAccounts"});
account = accounts[0];
document.getElementById("accountArea").innerHTML = account;
}
updateStatus(`Connected`)
}
function updateStatus(status) {
const statusEl = document.getElementById('status');
statusEl.innerHTML = status;
console.log(status);
}
const conGanache = async() =>{
const web3 = new Web3('http://localhost:7545');
console.log("connected");
}
const getAccounts = async () => {
const accounts = web3.eth.getAccounts().then(console.log);
document.getElementById("accounts").innerHTML = accounts;
}
</script>
</body>
</html>
and here is the smart contract:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/**
* @title Ballot
* @dev Implements voting process along with vote delegation
*/
contract Sales {
struct Items {
uint productID;
string productname;
address productOwner;
}
struct ItemsForSale {
uint forSaleID;
uint256 productID;
uint256 productPrice;
}
struct Offers {
uint offerID;
uint256 productID;
uint256 offerPrice;
address offerer;
bool status;
}
uint numItems;
uint numSales;
uint numOffer;
mapping(uint => Items) public item;
mapping(uint => ItemsForSale) public sales;
mapping(uint => Offers) public offers;
event Item(address indexed _owner, string _name, uint _ID);
event Sale(uint _productID, address indexed _newowner, uint256 _value);
event tranfer(uint _productID, address indexed _to);
event Offer(address indexed _offerer, uint _offerID, uint _productID, uint256 _value);
constructor(){
}
function createItem(string memory _productName) public {
Items storage _item = item[numItems];
_item.productID = numItems;
_item.productname = _productName;
_item.productOwner = msg.sender;
numItems++;
emit Item(msg.sender,_productName,numItems);
}
function listItemForSale(uint256 _productID, uint256 _productPrice) public {
sales[numSales] = ItemsForSale(numSales,_productID,_productPrice*1 ether); //*(10**18) store in wei
numSales++;
}
function Tranfer(uint _productID, address _to, uint256 _price) public payable{
Items storage _itembought = item[_productID];
require(_price == msg.value, "Product costs more");
payable(_to).transfer(_price);
_itembought.productOwner = msg.sender;
emit tranfer(_productID,_to);
}
function buyItem(uint _forSaleID) public payable{
Items storage _itembought = item[_forSaleID];
ItemsForSale memory _itemSale = sales[_forSaleID];
Tranfer(_itembought.productID,_itembought.productOwner,_itemSale.productPrice);
emit Sale(_itembought.productID,msg.sender,_itemSale.productPrice);
}
function makeOffer(uint _productID) public payable{
offers[numOffer]=Offers(numOffer,_productID, msg.value,msg.sender, true);
emit Offer(msg.sender,numOffer,_productID, msg.value);
numOffer++;
}
function withdrawalOffer(uint _offerID) public payable{
Offers storage _offer = offers[_offerID];
require(msg.sender == _offer.offerer, "Not The Offer Owner");
payable(msg.sender).transfer(_offer.offerPrice);
_offer.status = false;
}
function acceptOffer(uint _offerID) public payable{
for (uint i = 0; i < numOffer; i++) {
if (offers[i].offerID==_offerID) {
require(item[offers[i].productID].productOwner == msg.sender, "Not The Product Owner");
Tranfer(offers[i].productID,offers[i].offerer,offers[i].offerPrice);
}
}
}
function retrieveItem(uint _productID) public view returns(Items memory) {
return item[_productID];
}
function retrieveItemForSale(uint _productID) public view returns(ItemsForSale memory) {
for (uint i = 0; i < numSales; i++) {
if (sales[i].productID==_productID) {
return sales[i];
}
}
}
function retrieveOffer(uint _productID) public view returns(Offers memory) {
for (uint i = 0; i < numOffer; i++) {
if (offers[i].productID==_productID) {
return offers[i];
}
}
}
}
Although in the front end the console returns as it should the transaction after setting a item or itemForSale as such:
I can't retrieve the transaction info (such tx hash, block no etc.) so i can display it, and most importantly I can't retrieve the auto-setted Id of the product shown in the event "Item".
Lastly, I will also have to figure out how to retrieve and show to the end user the mapping from the retrieve functions in solidity.
Any Input or help will be highly appreciated it. Thank you all in advance!