Skip to content
Open
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
2 changes: 1 addition & 1 deletion migrations/1_initial_migration.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ const Migrations = artifacts.require("Migrations");

module.exports = function(deployer) {
deployer.deploy(Migrations);
};
};
15 changes: 15 additions & 0 deletions migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const Token = artifacts.require("Token");
const EthSwap = artifacts.require("EthSwap");

module.exports = async function(deployer) {
//deploy Token
await deployer.deploy(Token);
const token = await Token.deployed();

//deploy EthSwap
await deployer.deploy(EthSwap, token.address);
const ethSwap = await EthSwap.deployed();

//transfer all tokens to EthSwap (1 million)
token.transfer(ethSwap.address, "1000000000000000000000000");
};
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "eth-marketplace",
"name": "eth-swap",
"version": "0.1.0",
"description": "An Ethereum Marketplace",
"description": "An instant ERC20 crypto exchange",
"author": "gregory@dappuniversity.com",
"dependencies": {
"babel-polyfill": "6.26.0",
Expand All @@ -14,11 +14,12 @@
"chai": "4.2.0",
"chai-as-promised": "7.1.1",
"chai-bignumber": "3.0.0",
"identicon.js": "^2.3.3",
"react": "16.8.4",
"react-bootstrap": "1.0.0-beta.5",
"react-dom": "16.8.4",
"react-scripts": "2.1.3",
"truffle": "5.0.5",
"truffle": "^5.1.66",
"web3": "1.0.0-beta.55"
},
"scripts": {
Expand Down
4,259 changes: 4,259 additions & 0 deletions src/abis/EthSwap.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.

5,150 changes: 5,150 additions & 0 deletions src/abis/Token.json

Large diffs are not rendered by default.

186 changes: 140 additions & 46 deletions src/components/App.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,145 @@
import React, { Component } from 'react';
import logo from '../logo.png';
import './App.css';

class App extends Component {
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"
import React, { useEffect, useState } from "react";
import Web3 from "web3";

import Token from "../abis/Token.json";
import EthSwap from "../abis/EthSwap.json";

import Navbar from "./Navbar";
import Main from "./Main";
import "./App.css";

const App = () => {
const [state, setState] = useState({
account: "",
ethBalance: "0",
token: {},
tokenBalance: "0",
ethSwap: {},
isLoading: true,
hash: "",
});

useEffect(() => {
(async () => {
await loadWeb3();
await loadBlockchainData();
})();
}, [state.hash]);

const loadBlockchainData = async () => {
const account = (await window.web3.eth.getAccounts())[0];
const ethBalance = await window.web3.eth.getBalance(account);
const networkId = await window.web3.eth.net.getId();

//Load token data
const tokenData = Token.networks[networkId];
if (tokenData) {
const token = new window.web3.eth.Contract(Token.abi, tokenData.address);
const tokenBalance = await token.methods.balanceOf(account).call();
setState((prev) => ({
...prev,
account,
ethBalance,
token,
tokenBalance: tokenBalance.toString(),
}));
} else {
window.alert("Token contract not deployed to detected network");
}
//Load ethSwap data
const ethSwapData = EthSwap.networks[networkId];
if (ethSwapData) {
const ethSwap = new window.web3.eth.Contract(
EthSwap.abi,
ethSwapData.address
);
setState((prev) => ({
...prev,
account,
ethBalance,
ethSwap,
isLoading: false,
}));
} else {
window.alert("EthSwap contract not deployed to detected network");
}
};
const loadWeb3 = async () => {
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("Your browser does not support ethereum");
}
};

const buyTokens = (etherAmount) => {
state.ethSwap.methods
.buyTokens()
.send({ value: etherAmount, from: state.account })
.on("transactionHash", (hash) => {
setState((prev) => ({ ...prev, isLoading: false, hash }));
});
setState((prev) => ({ ...prev, isLoading: true }));
};

const sellTokens = (tokenAmount) => {
setState({ ...state, loading: true });
state.token.methods
.approve(state.ethSwap.address, tokenAmount)
.send({ from: state.account })
.on("transactionHash", (hash) => {
state.ethSwap.methods
.sellTokens(tokenAmount)
.send({ from: state.account })
.on("transactionHash", (hash) => {
setState({ ...state, loading: false });
});
});
};

let content;
if (state.isLoading) {
content = (
<p id="loader" className="text-center">
Loading...
</p>
);
} else {
content = (
<Main
ethBalance={state.ethBalance}
tokenBalance={state.tokenBalance}
buyTokens={buyTokens}
sellTokens={sellTokens}
/>
);
}
return (
<div>
<Navbar account={state.account} />
<div className="container-fluid mt-5">
<div className="row">
<main
role="main"
className="col-lg-12 d-flex ml-auto mr-auto"
style={{ maxWidth: "600px" }}
>
Dapp University
</a>
</nav>
<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>
</div>
<div className="content mr-auto ml-auto">
<a
href="http://www.dappuniversity.com/bootcamp"
target="_blank"
rel="noopener noreferrer"
></a>
{content}
</div>
</main>
</div>
</div>
);
}
}
</div>
);
};

export default App;
79 changes: 79 additions & 0 deletions src/components/BuyForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useRef, useState } from "react";
import tokenLogo from "../token-logo.png";
import ethLogo from "../eth-logo.png";

function BuyForm(props) {
const ref = useRef({ input: null });
const [state, setState] = useState({ input: "0" });

return (
<form
className="mb-3"
onSubmit={(event) => {
event.preventDefault();
let etherAmount;
etherAmount = ref.current.input.value.toString();
etherAmount = window.web3.utils.toWei(etherAmount, "Ether");
props.buyTokens(etherAmount);
}}
>
<div>
<label className="float-left">
<b>Input</b>
</label>
<span className="float-right text-muted">
Balance: {window.web3.utils.fromWei(props.ethBalance, "Ether")}
</span>
</div>
<div className="input-group mb-4">
<input
type="text"
onChange={(event) => {
const etherAmount = ref.current.input.value.toString();
setState({ ...state, output: etherAmount * 100 });
}}
ref={(input) => {
ref.current.input = input;
}}
className="form-control form-control-lg"
placeholder="0"
required
/>
<div className="input-group-append">
<img src={ethLogo} height={32} alt="" />
<div className="input-group-text">&nbsp;&nbsp;&nbsp; ETH</div>
</div>
</div>
<div>
<label className="float-left">
<b>Output</b>
</label>
<span className="float-right text-muted">
Balance: {window.web3.utils.fromWei(props.tokenBalance, "Ether")}
</span>
</div>
<div className="input-group mb-2">
<input
type="text"
className="form-control form-control-lg"
placeholder="0"
value={state.output}
disabled
/>
<div className="input-group-append">
<img src={tokenLogo} height={32} alt="" />
<div className="input-group-text">&nbsp; DApp</div>
</div>
</div>
<div className="mb-5">
<span className="float-left text-muted">Exchange Rate</span>
<span className="float-right text-muted">1 ETH = 100 DApp</span>
</div>
<button type="submit" className="btn btn-primary btn-block btn-lg">
SWAP!
</button>
</form>
);
}

export default BuyForm;
56 changes: 56 additions & 0 deletions src/components/Main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useState, useRef } from "react";
import BuyForm from "./BuyForm";
import SellForm from "./SellForm";

function Main(props) {
const [state, setState] = useState({ currentForm: "buy" });

let content;
if (state.currentForm === "buy") {
content = (
<BuyForm
ethBalance={props.ethBalance}
tokenBalance={props.tokenBalance}
buyTokens={props.buyTokens}
/>
);
} else {
content = (
<SellForm
ethBalance={props.ethBalance}
tokenBalance={props.tokenBalance}
sellTokens={props.sellTokens}
/>
);
}

return (
<div id="content" className="mt-3">
<div className="d-flex justify-content-between mb-3">
<button
className="btn btn-light"
onClick={(event) => {
setState({ ...state, currentForm: "buy" });
}}
>
Buy
</button>
<span className="text-muted">&lt; &nbsp; &gt;</span>
<button
className="btn btn-light"
onClick={(event) => {
setState({ ...state, currentForm: "sell" });
}}
>
Sell
</button>
</div>

<div className="card mb-4">
<div className="card-body">{content}</div>
</div>
</div>
);
}

export default Main;
Loading