Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Main #20

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Main #20

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# blockwaiter
19 changes: 19 additions & 0 deletions contracts/Migrations.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

contract Migrations {
address public owner = msg.sender;
uint public last_completed_migration;

modifier restricted() {
require(
msg.sender == owner,
"This function is restricted to the contract's owner"
);
_;
}

function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
}
5 changes: 5 additions & 0 deletions migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const Marketplace = artifacts.require("Marketplace");

module.exports = function(deployer) {
deployer.deploy(Marketplace);
};
9,336 changes: 4,687 additions & 4,649 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "eth-marketplace",
"version": "0.1.0",
"description": "An Ethereum Marketplace",
"author": "gregory@dappuniversity.com",
"description": "A Food Marketplace",
"author": "jordan.lugenbeel@gmail.com",
"dependencies": {
"babel-polyfill": "6.26.0",
"babel-preset-env": "1.7.0",
Expand Down
4 changes: 2 additions & 2 deletions public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"short_name": "Starter Kit",
"name": "Dapp University Starter Kit",
"short_name": "Blockwaiter",
"name": "Blockchain Waiter",
"icons": [
{
"src": "favicon.ico",
Expand Down
5,624 changes: 5,624 additions & 0 deletions src/abis/Marketplace.json

Large diffs are not rendered by default.

1,491 changes: 1,491 additions & 0 deletions src/abis/Migrations.json

Large diffs are not rendered by default.

116 changes: 83 additions & 33 deletions src/components/App.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,96 @@
import React, { Component } from 'react';
import Web3 from 'web3'
import logo from '../logo.png';
import './App.css';
import Marketplace from '../abis/Marketplace.json'
import Navbar from './Navbar'
import Main from './Main'

class App extends Component {

async componentWillMount() {
await this.loadWeb3()
await this.loadBlockchainData()
}

async loadWeb3() {
if (window.ethereum) {
window.web3 = new Web3(window.ethereum)
await window.ethereum.enable()
}
else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider)
}
else {
window.alert('Non-Ethereum browser detected. You should consider trying MetaMask!')
}
}

async loadBlockchainData() {
const web3 = window.web3
// Load account
const accounts = await web3.eth.getAccounts()
this.setState({ account: accounts[0] })
const networkId = await web3.eth.net.getId()
const networkData = Marketplace.networks[networkId]
if(networkData) {
const marketplace = web3.eth.Contract(Marketplace.abi, networkData.address)
this.setState({ marketplace })
const productCount = await marketplace.methods.productCount().call()
this.setState({ productCount })
// Load products
for (var i = 1; i <= productCount; i++) {
const product = await marketplace.methods.products(i).call()
this.setState({
products: [...this.state.products, product]
})
}
this.setState({ loading: false})
} else {
window.alert('Marketplace contract not deployed to detected network.')
}
}
constructor(props) {
super(props)
this.state = {
account: '',
productCount: 0,
products: [],
loading: true
}
this.createProduct = this.createProduct.bind(this)
this.purchaseProduct = this.purchaseProduct.bind(this)
}
createProduct(name, price) {
this.setState({ loading: true })
this.state.marketplace.methods.createProduct(name, price).send({ from: this.state.account })
.once('receipt', (receipt) => {
this.setState({ loading: false })
})
}
purchaseProduct(id, price) {
this.setState({ loading: true })
this.state.marketplace.methods.purchaseProduct(id).send({ from: this.state.account, value: price })
.once('receipt', (receipt) => {
this.setState({ loading: false })
})
}

render() {
return (
<div>
<nav className="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow">
<a
className="navbar-brand col-sm-3 col-md-2 mr-0"
href="http://www.dappuniversity.com/bootcamp"
target="_blank"
rel="noopener noreferrer"
>
Dapp University
</a>
</nav>
<Navbar account={this.state.account} />
<div className="container-fluid mt-5">
<div className="row">
<main role="main" className="col-lg-12 d-flex text-center">
<div className="content mr-auto ml-auto">
<a
href="http://www.dappuniversity.com/bootcamp"
target="_blank"
rel="noopener noreferrer"
>
<img src={logo} className="App-logo" alt="logo" />
</a>
<h1>Dapp University Starter Kit</h1>
<p>
Edit <code>src/components/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="http://www.dappuniversity.com/bootcamp"
target="_blank"
rel="noopener noreferrer"
>
LEARN BLOCKCHAIN <u><b>NOW! </b></u>
</a>
</div>
</main>
<main role="main" className="col-lg-12 d-flex">
{ this.state.loading
? <div id="loader" className="text-center"><p className="text-center">Loading...</p></div>
: <Main
products={this.state.products}
createProduct={this.createProduct}
purchaseProduct={this.purchaseProduct} />
}
</main>
</div>
</div>
</div>
Expand Down
79 changes: 79 additions & 0 deletions src/components/Main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { Component } from 'react';

class Main extends Component {

render() {
return (
<div id="content">
<h1>Add Product</h1>
<form onSubmit={(event) => {
event.preventDefault()
const name = this.productName.value
const price = window.web3.utils.toWei(this.productPrice.value.toString(), 'Ether')
this.props.createProduct(name, price)
}}>
<div className="form-group mr-sm-2">
<input
id="productName"
type="text"
ref={(input) => { this.productName = input }}
className="form-control"
placeholder="Product Name"
required />
</div>
<div className="form-group mr-sm-2">
<input
id="productPrice"
type="text"
ref={(input) => { this.productPrice = input }}
className="form-control"
placeholder="Product Price"
required />
</div>
<button type="submit" className="btn btn-primary">Add Product</button>
</form>
<p> </p>
<h2>Buy Product</h2>
<table className="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Price</th>
<th scope="col">Owner</th>
<th scope="col"></th>
</tr>
</thead>
<tbody id="productList">
{ this.props.products.map((product, key) => {
return(
<tr key={key}>
<th scope="row">{product.id.toString()}</th>
<td>{product.name}</td>
<td>{window.web3.utils.fromWei(product.price.toString(), 'Ether')} Eth</td>
<td>{product.owner}</td>
<td>
{!product.purchased
? <button
name={product.id}
value={product.price}
onClick={(event) => {
this.props.purchaseProduct(event.target.name, event.target.value)
}}
>
Buy
</button>
:null
}
</td>
</tr>
)
})}
</tbody>
</table>
</div>
);
}
}

export default Main;
25 changes: 25 additions & 0 deletions src/components/Navbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { Component } from 'react';

class Navbar extends Component {

render() {
return (
<nav className="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow">
<a
className="navbar-brand col-sm-3 col-md-2 mr-0"
href="http://www.dappuniversity.com/bootcamp"
target="_blank"
rel="noopener noreferrer"
>
BlockChain Waiter
</a>
<ul className="navbar-nav px-3">
<li className="nav-item text-nowrap d-none d-sm-none d-sm-block">
<small className="text-white"><span id="account">{this.props.account}</span></small>
</li>
</ul>
</nav>
);
}
}
export default Navbar;
75 changes: 75 additions & 0 deletions src/contracts/Marketplace.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
pragma solidity^0.5.0;

contract Marketplace {
string public name;
uint public productCount = 0;
mapping(uint => Product) public products;

struct Product {
uint id;
string name;
uint price;
address payable owner;
bool purchased;
}

event ProductCreated(
uint id,
string name,
uint price,
address payable owner,
bool purchased

);

event ProductPurchased(
uint id,
string name,
uint price,
address payable owner,
bool purchased

);

constructor() public {
name = "Jrive Market";
}

function createProduct(string memory _name, uint _price) public {
require(bytes(_name).length > 0);

require(_price > 0);

productCount ++;

products[productCount] = Product(productCount, _name, _price, msg.sender, false);

emit ProductCreated(productCount, _name, _price, msg.sender, false);


}
function purchaseProduct(uint _id) public payable {
//Fetch the product
Product memory _product = products[_id];
//Fetch the owner
address payable _seller = _product.owner;
//Make sure the product has valid id
require(_product.id > 0 && _product.id <= productCount);
//Require that there is enough Ether in the transaction
require(msg.value >= _product.price);
//Require that the product has not been purchased already
require(!_product.purchased);
//Require that the buyer is not the seller
require(_seller != msg.sender);
//Transfer ownership to the buyer
_product.owner = msg.sender;
//Mark as purchased
_product.purchased = true;
//Update the product
products[_id] = _product;
//Pay the seller by sending them Ether
address(_seller).transfer(msg.value);
//Trigger on event
emit ProductPurchased(productCount, _product.name, _product.price, msg.sender, true);
}
}
Empty file added test/.gitkeep
Empty file.
Loading