This is the second of a 2-part article that explains the codes behind Smart Contract Explained by Demonstration. You may read part one here.
In this part, I will focus on the UI for the buyer. The StartEscrow smart contract used by the DApp can be found here and I have previously written an article about how it works here.
You may find the complete buyer's source codes in my Github repository here. In the sections that follow, I will refer to the line numbers from my codes in Github.
Initializations
Here's where I perform the initializations.
var currentContractAddress;
var Purchase;
$(document).ready( function () {
$("#confirmpurchasediv").hide();
$("#confirmdeliverdiv").hide();
} );
In lines 71 to 77, the currentContractAddress
variable is declared to keep the address of my Contract. The Purchase
variable will store the Purchase contract. I also hide the confirmpurchasediv and confirmdeliverdiv panels. Read lines 44-56 and 58-68 to understand what the panels do. These panels draw the user interfaces for the buyer to interact with the contract. They are initially hidden until the buyer loads the item that he wishes to purchase.
if (typeof web3 !== 'undefined') {
web3 = new Web3(web3.currentProvider);
} else {
// set the provider you want from Web3.providers
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}
Lines 79 to 84 initialize web3. Here, the web3 library checks if the UI is executed from a web browser that has a web3 provider. If you have MetaMask installed on your Chrome browser or are running this page within Status, the mobile app for Dapps execute, this will work. Or else, web3 will attempt to look for a running Web3 provider in your machine to use.
web3.eth.defaultAccount = web3.eth.accounts[0];
var PurchaseContract = web3.eth.contract(
[
{
"constant": true,
"inputs": [],
"name": "seller",
"outputs": [
{
.... <truncated>
]
);
Loading Contract
Lines 86 to 221 states the Application Binary Interface (ABI) for PurchaseContract
. The ABI of a Smart Contract can be obtained by copying and pasting the Smart Contract codes into Remix and compiling your contract.
$("#button").click(function() {
currentContractAddress = $("#contractAddress").val();
$("#contractaddress").html("Contract: " + $("#contractAddress").val());
loadContractDetail($("#contractAddress").val());
});
Lines 223 to 228 declare what happens when the buyer presses the [Get Contract] button. The buyer enters the address of the Smart Contract address for the item that the seller is selling. This contract will then be loaded by the loadContractDetail function.
function loadContractDetail(address){
Purchase = PurchaseContract.at(address);
Purchase.value(function(error, result){
if(!error){
console.log(JSON.stringify(result));
$("#itemvalue").html("Price: " + Number(result)/1000000000000000000);
}
else{
console.error(error);
}
})/18;
Purchase.seller(function(error, result){
if(!error){
console.log(JSON.stringify(result));
$("#seller").html("Seller: " + result);
}
else{
console.error(error);
}
});
Purchase.buyer(function(error, result){
if(!error){
console.log(JSON.stringify(result));
$("#buyer").html("Buyer: " + result);
}
else{
console.error(error);
}
});
Purchase.ipfsHash(function(error, result){
if(!error){
console.log(JSON.stringify(result));
$("#ipfshash").html("IPFS Hash: " + result);
$("#ipfsimage").html("<img src=https://gateway.ipfs.io/ipfs/" + result + " width='400'>");
}
else{
console.error(error);
}
});
Purchase.state(function(error, result){
if(!error){
console.log(JSON.stringify(result));
if (Number(result) === 0){
$("#state").html('<span class="badge progress-bar-success">Created</span>');
$("#confirmpurchasediv").show();
$("#confirmdeliverdiv").hide();
}
else if (Number(result) === 1){
$("#state").html('<span class="badge progress-bar-info">Locked</span>');
$("#confirmpurchasediv").hide();
$("#confirmdeliverdiv").show();
}
else {
$("#state").html('<span class="badge progress-bar-danger">Inactive</span>');
$("#confirmpurchasediv").hide();
$("#confirmdeliverdiv").hide();
}
}
else{
console.error(error);
}
});
}
The loadContractDetail
function is declared between lines 280 and 347. It calls the getter functions of the Purchase
contract and displays the corresponding information on the screen.
Purchase.value
: This displays the value that the seller is selling this item for. Notice that I converted the value of the item from wei to ether. 118 wei gives you one ether.Purchase.seller
: This displays the wallet address of the seller.Purchase.buyer
: This displays the wallet address of the buyer. If this item has no buyer, then it stays empty until a buyer comes along.Purchase.ipfsHash
: This displays the ipfsHash value of the item's image. Item images are stored in ipfs. Here, I take the ipfs hash value of the image and displays the image using an ipfs gateway.Purchase.state
: I display the state of this purchase contract here. A purchase contract can have 3 possible states: created, when it is available for sale, locked, when it is in the middle of a purchase process, and inactive, when it has been sold. I also turns on and off theconfirmpurchasediv
andconfirmdeliverdiv
panels depending on whether the user should or should not be able to interact with them. For example, an item in its "created" status will have itsconfirmpurchasediv
turned on andconfirmdeliverdiv
turned off.
Confirming Purchase
var newConfirmPurchaseEvent;
$("#purchaseButton").click(function() {
$("#loader").show();
Purchase.confirmPurchase({value: $("#price").val()*1000000000000000000, gas: 1000000, gasPrice: web3.toWei(2, 'gwei')}, function(error, result){
if(!error){
console.log(JSON.stringify(result));
newConfirmPurchaseEvent = Purchase.PurchaseConfirmed();
newConfirmPurchaseEvent.watch(function(error, result){
if (!error)
{
$("#loader").hide();
loadContractDetail(currentContractAddress);
}
else {
$("#loader").hide();
console.log(error);
}
});
}
else{
console.error(error);
}
});
});
Lines 229 to 252 process what happens when the buy hits [Purchase].
I run Purchase.confirmPurchase
on the smart contract and watch and wait for the Smart contract to emit a confirmation event using newConfirmPurchaseEvent.watch(function(error, result)
. Once emitted, I run loadContractDetail() again to refresh this contract's information on the page.
Confirming Delivery
var newConfirmDeliverEvent;
$("#deliverButton").click(function() {
$("#loaderdeliver").show();
Purchase.confirmReceived({gas: 1000000, gasPrice: web3.toWei(2, 'gwei')}, function(error, result){
if(!error){
console.log(JSON.stringify(result));
newConfirmDeliverEvent = Purchase.ItemReceived();
newConfirmDeliverEvent.watch(function(error, result){
if (!error)
{
$("#loaderdeliver").hide();
loadContractDetail(currentContractAddress);
}
else {
$("#loaderdeliver").hide();
console.log(error);
}
});
}
else{
console.error(error);
}
});
});
Lines 254 to 277 processes what happens when the user presses [Deliver].
I run Purchase.confirmReceived()
on the smart contract and watch and wait for the contract to emit newConfirmDeliverEvent.watch(function(error, result))
when it is done executing.
Once emitted, I run loadContractDetail()
again to refresh this contract's information on the page.
Finishing Off
I wrote several articles about Escrow Services Smart Contracts throughout 2018 because I believed that there ought to be more well illustrated use cases for Smart Contracts on the Blockchain platforms. The world of cryptocurrencies and blockchain needs more well documented business cases with executable examples and less whitepapers and ICOs.
Here's a summary of everything I have written so far:
- Smart Contract Explained by Demonstration: This is a step-by-step demonstration of how a Smart Contract works by having you pretending to be a seller and a buyer.
- Escrow Service as a Smart Contract Series: The Business Logic walks you through the thoughts that could have gone through the folks who wrote the original contract. The Execution lets you run the Solidity Smart Contract to execute the contracts directly using the Remix IDE.
- Creating Smart Contracts with Smart Contract extends the Safe Remote Purchase contract by letting the user spawn new purchase smart contracts.
- Finally, this article and Smart Contract Escrow Dapp - Seller View explains the HTML and JavaScript codes that gives you a user interface so that the layman can use it like a regular web app.
Photo by Clark Young on Unsplash