Commit a9b87407 authored by Callil Capuozzo's avatar Callil Capuozzo

Initial design & interactions

Began porting some function and state names to more generic descriptors
like inputToken & outputToken thats align more closely with the
proposed UX model in this design. Needs discussion.
parent 1086f4c9
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "uniswap",
"homepage": ".",
"version": "0.1.0",
"private": true,
"dependencies": {
"metamask-logo": "^2.1.3",
"ramda": "^0.25.0",
"react": "^16.1.1",
"react-dom": "^16.1.1",
"react-scripts": "1.0.14",
"react-web3": "^0.4.3",
"web3": "^1.0.0-beta.26"
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-helmet": "^5.2.0",
"react-scripts": "1.1.0",
"react-select": "^1.2.1",
"react-web3": "^0.4.4",
"web3": "1.0.0-beta.18"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"deploy": "npm run build&&gh-pages -d build"
},
"devDependencies": {
"gh-pages": "^1.0.0"
"eject": "react-scripts eject"
}
}
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
......@@ -8,12 +8,8 @@
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="./favicon.ico">
<!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> -->
<!-- <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> -->
<link rel="shortcut icon" href="%PUBLIC_URL%/🦄.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
......
......@@ -4,8 +4,8 @@
"icons": [
{
"src": "favicon.ico",
"sizes": "192x192",
"type": "image/png"
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
......
pragma solidity 0.4.18;
/// @title SafeMath
/// @dev Math operations with safety checks that throw on error
library SafeMath {
/// @dev Multiplies a times b
function mul(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
/// @dev Divides a by b
function div(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/// @dev Subtracts a from b
function sub(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
assert(b <= a);
return a - b;
}
/// @dev Adds a to b
function add(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
uint256 c = a + b;
assert(c >= a);
return c;
}
}
pragma solidity ^0.4.18;
contract ERC20Token {
uint256 public totalSupply;
function balanceOf(address who) public constant returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
function allowance(address owner, address spender) public constant returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
}
library SafeMath {
function mul(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal constant returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal constant returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract StandardToken is ERC20Token {
using SafeMath for uint256;
mapping(address => uint256) balances;
mapping (address => mapping (address => uint256)) internal allowed;
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
Transfer(_from, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
function increaseApproval (address _spender, uint _addedValue) public returns (bool success) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function decreaseApproval (address _spender, uint _subtractedValue) public returns (bool success) {
uint oldValue = allowed[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function balanceOf(address _owner) public constant returns (uint256 balance) {
return balances[_owner];
}
}
contract Ownable {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
address public owner;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function Ownable() {
owner = msg.sender;
}
function transferOwnership(address newOwner) onlyOwner public {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
contract MintableToken is StandardToken, Ownable {
event Mint(address indexed to, uint256 amount);
event MintFinished();
bool public mintingFinished = false;
modifier canMint() {
require(!mintingFinished);
_;
}
/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
totalSupply = totalSupply.add(_amount);
balances[_to] = balances[_to].add(_amount);
Mint(_to, _amount);
Transfer(0x0, _to, _amount);
return true;
}
/**
* @dev Function to stop minting new tokens.
* @return True if the operation was successful.
*/
function finishMinting() onlyOwner public returns (bool) {
mintingFinished = true;
MintFinished();
return true;
}
}
contract uniTestToken is MintableToken {
string public constant name = "UNI Test Token";
string public constant symbol = "UNT";
uint8 public constant decimals = 6;
}
pragma solidity ^0.4.18;
/// @title SafeMath
/// @dev Math operations with safety checks that throw on error
library SafeMath {
/// @dev Multiplies a times b
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
/// @dev Divides a by b
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/// @dev Subtracts a from b
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/// @dev Adds a to b
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract Ownable {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
address public owner;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function Ownable() public {
owner = msg.sender;
}
function transferOwnership(address newOwner) onlyOwner public {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
contract ERC20Token {
uint256 public totalSupply;
function balanceOf(address who) public constant returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
function allowance(address owner, address spender) public constant returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
}
contract uniswap is Ownable{
using SafeMath for uint256;
event TokenPurchase(address indexed buyer, uint256 tokensPurchased, uint256 ethSpent);
event EthPurchase(address indexed buyer, uint256 ethPurchased, uint256 tokensSpent);
uint256 public totalEthQuantity;
uint256 public totalTokenQuantity;
uint256 public invariant = 0;
address public tokenAddress;
ERC20Token token;
function uniswap(address _tokenAddress) public payable {
tokenAddress = _tokenAddress;
token = ERC20Token(tokenAddress);
totalEthQuantity = msg.value;
}
function initiateUniswap(uint256 initialTokenQuantity) public onlyOwner {
require(invariant == 0);
token.transferFrom(msg.sender, address(this), initialTokenQuantity);
totalTokenQuantity = initialTokenQuantity;
invariant = initialTokenQuantity.mul(totalEthQuantity);
require(invariant > 0);
}
function ethToTokens(uint256 minimumTokens, uint256 timeout) public payable {
require(msg.value != 0 && timeout != 0);
uint256 fee = msg.value/500;
uint256 ethInPurchase = msg.value.sub(fee);
uint256 newTotalEth = totalEthQuantity.add(ethInPurchase);
uint256 newTotalTokens = invariant/newTotalEth;
uint256 purchasedTokens = totalTokenQuantity.sub(newTotalTokens);
require(purchasedTokens >= minimumTokens);
require(now < timeout);
token.transfer(msg.sender, purchasedTokens);
totalEthQuantity = newTotalEth;
totalTokenQuantity = newTotalTokens;
TokenPurchase(msg.sender, purchasedTokens, ethInPurchase);
}
function tokenToEth(uint256 sellQuantity, uint256 minimumEth, uint256 timeout) public {
require(sellQuantity!=0 && minimumEth != 0 && timeout != 0);
token.transferFrom(msg.sender, address(this), sellQuantity);
uint256 fee = sellQuantity/500;
uint256 tokensInPurchase = sellQuantity - fee;
uint256 newTotalTokens = totalTokenQuantity.add(tokensInPurchase);
uint256 newTotalEth = invariant/newTotalTokens;
uint256 purchasedEth = totalEthQuantity.sub(newTotalEth);
require(purchasedEth >= minimumEth);
require(now < timeout);
msg.sender.transfer(purchasedEth);
totalTokenQuantity = newTotalTokens;
totalEthQuantity = newTotalEth;
EthPurchase(msg.sender, purchasedEth, tokensInPurchase);
}
function ownerTokenDeposit(uint256 tokenAmount) public onlyOwner {
require(tokenAmount !=0);
token.transferFrom(msg.sender, address(this), tokenAmount);
totalTokenQuantity = totalTokenQuantity.add(tokenAmount);
invariant = totalTokenQuantity.mul(totalEthQuantity);
}
function ownerEthDeposit() public payable onlyOwner {
require(msg.value != 0);
totalEthQuantity = totalEthQuantity.add(msg.value);
invariant = totalEthQuantity.mul(totalTokenQuantity);
}
function ownerTokenWithdraw(uint256 tokenAmount) public onlyOwner {
require(tokenAmount !=0);
token.transfer(msg.sender, tokenAmount);
totalTokenQuantity = totalTokenQuantity.sub(tokenAmount);
invariant = totalTokenQuantity.mul(totalEthQuantity);
}
function ownerEthWithdraw(uint256 ethAmount) public onlyOwner {
require(ethAmount !=0);
msg.sender.transfer(ethAmount);
totalEthQuantity = totalEthQuantity.sub(ethAmount);
invariant = totalEthQuantity.mul(totalTokenQuantity);
}
}
@font-face {
font-family: 'LeveloLineBold'; /*a name to be used later*/
src: url('./fonts/LoveloLineBold.otf'); /*URL to font*/
}
@keyframes blinker {
50% { opacity: 0.55; }
}
.App {
text-align: center;
background-size: 100%;
height:100vh;
background-image: url('./images/background.jpg');
background-repeat: repeat-y;
font-family: Optima, sans-serif;
}
.noICO {
position:fixed;
font-size: 14px;
top:3vh;
left: 40vw;
right: 28vw;
color: rgb(216, 169, 236);
text-shadow: 1px 1px 5px #ff69f0;
}
.ethLogo {
position: fixed;
right: 22vh;
position: fixed;
height: 10vh;
z-index: 1;
margin-top: 1vh;
margin-right: 5vh;
opacity: 0.6;
-webkit-filter: invert(.8);
filter: invert(.8);
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
-o-user-select: none;
user-select: none;
}.ethLogo:hover {
opacity: 1;
}
.unicorn {
position: fixed;
right: 0;
clear: both;
z-index: 1;
height:25vh;
opacity: 0.9;
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
-o-user-select: none;
user-select: none;
}.unicorn:hover {
opacity: 1;
}
.Warning {
position: fixed;
z-index: 3;
text-align: center;
left: 35vw;
color: rgb(238, 0, 0);
text-shadow: 2px 2px 10px #2daae0;
animation: blinker 1s linear infinite;
}
.Account-info {
position: fixed;
z-index: 2;
text-align: left;
font-size: 14px;
top: 13vh;
left: 40vw;
color: rgb(122, 251, 255);
text-shadow: 1px 1px 5px #2daae0;
body{
margin: 0;
padding: 0;
font-family: "Inter UI", sans-serif;
font-size: 24px;
line-height: 1.2;
}
input{
font-size: 24px;
line-height: 1.2;
}
p{
margin: 0px;
}
/* .app{
margin: 10rem;
margin-top: 5rem;
} */
.pa2 {
padding: 3rem;
}
.title{
display: flex;
flex-direction: row;
}
.border{
border: 1px solid #f2f2f2;
}
.title {
width: 100%;
}
.logo{
/* width: 10vw; */
display: flex;
justify-content: center;
align-items: center;
}
.connection{
display: flex;
justify-content: space-between;
align-items: center;
color: #27AE60;
flex: 1;
}
.connection a{
text-decoration: none;
color: #27AE60;
}
.order {
width: 100%;
display: flex;
flex-direction: row;
/* justify-content: space-between; */
}
.arrow{
max-width: 100vw;
display: flex;
justify-content: center;
align-items: center;
flex: 1;
}
.value{
width: 35vw;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: auto;
text-overflow: ellipsis;
-webkit-transition-duration: 0.5s;
transition-duration: 0.5s;
}.Account-info:hover{
color: rgb(209, 151, 245);
text-shadow: 1px 1px 5px #ff69f0;
}
.pinkText {
position: fixed;
font-size: 16px;
z-index: 3;
color: rgb(216, 169, 236);
text-shadow: 1px 1px 5px #ff69f0;
text-align: left;
-webkit-transition-duration: 0.5s;
transition-duration: 0.5s;
/*overflow-x: auto;*/
}.pinkText:hover{
color: rgb(122, 251, 255);
text-shadow: 1px 1px 5px #2daae0;
}
.approveButtonContainer{
position:fixed;
z-index: 3;
right: 10vw;
top: 30vh;
}
.approveButton {
position: fixed;
font-family: Optima, sans-serif;
font-size: 18px;
font-weight: bolder;
border-radius: 8px;
padding: 4px 8px;
color: rgb(220, 160, 245);
background-color: rgba(126, 228, 255, 0.25);
border: 2px solid rgba(180, 81, 179, 0.55);
-webkit-transition-duration: 0.5s;
transition-duration: 0.5s;
}.approveButton:hover {
color: rgb(122, 251, 255);
border: 2px solid rgb(122, 251, 255);
text-shadow: 1px 1px 5px #2daae0;
cursor: pointer;
}
.exchange {
position: fixed;
font-family: Optima, sans-serif;
font-size: 18px;
color: rgb(122, 251, 255);
text-shadow: 1px 1px 5px #2daae0;
}
.exchange-buyTokens {
margin-left: 35vw;
}
.exchange-buyEth {
margin-left: 60vw;
}
.exchange-buyEth, .exchange-buyTokens {
position: fixed;
float: left;
bottom: 72vh;
}
.exchange-buyEthInput, .exchange-buyTokensInput{
width: 10vw;
height: 4.2vh;
text-align: center;
color: rgb(209, 151, 245);
vertical-align: middle;
border: 1px solid rgba(180, 81, 179, 0.55);
border-radius: 8px 0 0 8px;
background-color: rgba(122, 251, 255, 0.15);
font-size: 18px;
font-family: Optima, sans-serif;
-webkit-transition-duration: 0.8s;
transition-duration: 0.8s;
}.exchange-buyEthInput:hover, .exchange-buyTokensInput:hover{
border: 1px solid rgb(122, 251, 255);
}
.exchange-buyEthButton, .exchange-buyTokensButton{
position: fixed;
font-size: 1.55vw;
width: 7vw;
text-shadow: 3px 3px 10px #1c5f7c;
margin-top: 10px;
height: 4.2vh;
text-align: center;
color: rgb(220, 160, 245);
text-shadow: 1px 1px 5px #ff69f0;
background-color: rgba(126, 228, 255, 0.25);
vertical-align: middle;
margin-top: 0px;
border: 1px solid rgb(180, 81, 179);
border-radius: 0 8px 8px 0;
font-family: Optima, sans-serif;
-webkit-transition-duration: 0.8s;
transition-duration: 0.8s;
}.exchange-buyEthButton:hover, .exchange-buyTokensButton:hover{
cursor: pointer;
color: rgb(122, 251, 255);
text-shadow: 2px 2px 10px #1c5f7c;
border: 1px solid rgb(122, 251, 255);
display: flex;
justify-content: space-between;
align-items: center;
}
.value input, select{
width: 100%;
height: 100%;
border: none;
}
.value input:focus{
outline: none;
}
.dropdown{
transform: rotate(-90deg);
opacity: .4;
position: relative;
z-index: -99;
left: -5px;
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
.rate-info{
display: flex;
flex-direction: row;
justify-content: space-between;
}
.info{
display: flex;
flex-direction: row;
justify-content: space-between;
}
.links{
display: flex;
flex-direction: row;
justify-content: center;
}
.link{
display: flex;
flex-direction: row;
justify-content: space-between;
flex: 1;
text-decoration: none;
color: black;
}
.link:hover .underline{
text-decoration: underline;
}
.swap{
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: #f2f2f2;
color: blue;
height: 48px;
transition: height .3s ease;
}
.red{
color: red;
}
.dim .order, .rate{
opacity: .4;
}
.hidden{
padding: 0px;
height: 0px;
border: 0px solid #f2f2f2;
}
import React, { Component } from 'react';
import Web3 from 'web3';
import Head from './components/Head'
import NetworkStatus from './components/NetworkStatus'
import HelperMessages from './components/HelperMessages'
import SelectToken from './components/SelectToken'
import './App.css';
import Title from './components/misc/Title';
import Instructions from './components/menus/Instructions';
import unicorn from './images/unicornNoBackground.png';
import ethLogo from './images/ethLogo.png';
var localweb3;
import {uniswapABI, tokenABI} from './helpers/abi.js'
var localweb3;
class App extends Component {
constructor(props){
constructor (props) {
super(props)
if (typeof props.metamask !== 'undefined'){
localweb3 = new Web3(window.web3.currentProvider)
} else {
localweb3 = null
}
localweb3 = new Web3(window.web3.currentProvider);
var uniswapABI = [{"constant":false,"inputs":[{"name":"tokenAmount","type":"uint256"}],"name":"ownerTokenWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tokenAmount","type":"uint256"}],"name":"ownerTokenDeposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ethAmount","type":"uint256"}],"name":"ownerEthWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"sellQuantity","type":"uint256"},{"name":"minimumEth","type":"uint256"},{"name":"timeout","type":"uint256"}],"name":"tokenToEth","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalTokenQuantity","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"minimumTokens","type":"uint256"},{"name":"timeout","type":"uint256"}],"name":"ethToTokens","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"initialTokenQuantity","type":"uint256"}],"name":"initiateUniswap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalEthQuantity","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"invariant","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"ownerEthDeposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_tokenAddress","type":"address"}],"payable":true,"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"buyer","type":"address"},{"indexed":false,"name":"tokensPurchased","type":"uint256"},{"indexed":false,"name":"ethSpent","type":"uint256"}],"name":"TokenPurchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"buyer","type":"address"},{"indexed":false,"name":"ethPurchased","type":"uint256"},{"indexed":false,"name":"tokensSpent","type":"uint256"}],"name":"EthPurchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]
const uniswapAddress = '0x60e5f3cd0381c501971b6fbbddaa49cfd58a4fa1';
const uniContract = new localweb3.eth.Contract(uniswapABI, uniswapAddress);
var tokenABI = [{"constant":true,"inputs":[],"name":"mintingFinished","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"finishMinting","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[],"name":"MintFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]
const tokenAddress = '0xca9901076d02f89794262869aad1340bd45d8489';
const tokContract = new localweb3.eth.Contract(tokenABI, tokenAddress);
this.state = {uniswapAddress: '0x60e5f3cd0381c501971b6fbbddaa49cfd58a4fa1',
tokenAddress: '0xca9901076d02f89794262869aad1340bd45d8489',
uniswapContract: uniContract,
tokenContract: tokContract,
ethBalance: 0,
tokenBalance: 0,
tokenAllowance: null,
currentMaskAddress: '0x0000000000000000000000000000000000000000',
minimumTokensPurchased: null,
minimumEthPurchased: null,
invariant: 0,
marketEth: 0,
marketTokens: 0,
tokenBuyRate: 0,
ethBuyRate: 0,
tokenCost: 0, //eth price of tokens
ethCost: 0, //token price of eth
tokenFee: 0,
ethFee: 0,
networkMessage: '',
locked: false
const tokenContract = new localweb3.eth.Contract(tokenABI, tokenAddress);
this.state = {
uniswapAddress: '0x60e5f3cd0381c501971b6fbbddaa49cfd58a4fa1',
tokenAddress: '0xca9901076d02f89794262869aad1340bd45d8489',
uniswapContract: uniContract,
tokenContract: tokenContract,
ethBalance: 0,
tokenBalance: 0,
tokenAllowance: null,
currentMaskAddress: '0x0000000000000000000000000000000000000000',
minimumTokensPurchased: null,
minimumEthPurchased: null,
invariant: 0,
marketEth: 0,
marketTokens: 0,
tokenBuyRate: 0,
ethBuyRate: 0,
tokenCost: 0, //eth price of tokens
ethCost: 0, //token price of eth
tokenFee: 0,
ethFee: 0,
networkMessage: '',
locked: false,
connected: false,
interaction: 'disconnected',
input: 0,
output: 0,
inputToken: { value: 'ETH', label: 'ETH', clearableValue: false },
outputToken: { value: 'OMG', label: 'OMG', clearableValue: false }
}
this.onBuyEthInputChange = this.onBuyEthInputChange.bind(this);
this.onBuyTokensInputChange = this.onBuyTokensInputChange.bind(this);
this.tokenBuyRate = this.tokenBuyRate.bind(this);
this.ethBuyRate = this.ethBuyRate.bind(this);
// this.isMetaMaskLocked = this.isMetaMaskLocked.bind(this);
}
componentWillMount(){
......@@ -87,54 +90,18 @@ class App extends Component {
}, 1000);
}
checkNetwork() {
var self = this;
localweb3.eth.net.getNetworkType((err, netId) => {
switch (netId) {
case "main":
self.setState({networkMessage: 'MetaMask connected to Ethereum Mainet. Switch to Rinkeby and refresh!'});
break
case "morden":
self.setState({networkMessage: 'MetaMask connected to Morden testnet. Switch to Rinkeby and refresh!'});
break
case "kovan":
self.setState({networkMessage: 'MetaMask connected to Kovan testnet. Switch to Rinkeby and refresh!'});
break
case "ropsten":
self.setState({networkMessage: 'MetaMask connected to Ropstein testnet. Switch to Rinkeby and refresh!'})
break
default:
console.log('Connected to ' + netId);
}
})
}
approveAllowance(value) {
this.state.tokenContract.methods.approve(this.uniswapAddress, value).send(
{from: this.state.currentMaskAddress},
function(err, txHash) {})
}
getMetaMaskAddress() {
var self = this;
localweb3.eth.getAccounts().then(function(result, error){
var address = result[0];
if (address === undefined) {
console.log('MetaMask locked');
alert('Found MetaMask but no account. Please unlock MetaMask and refresh')
}
else {
self.setState({currentMaskAddress: address})
}
});
localweb3.eth.getAccounts(function(error, result){
if(!error)
self.setState({currentMaskAddress: result[0]})
else
self.setState({locked: true})
})
}
getEthBalance() {
var self = this;
localweb3.eth.getBalance(this.state.currentMaskAddress, function(error, balance) {
var ethValue = (balance/10**18);
var roundedValue=Math.round(ethValue*10000)/10000;
......@@ -144,13 +111,6 @@ class App extends Component {
getTokenBalance() {
var self = this;
// tokenContract.methods.balanceOf(this.state.currentMaskAddress).call().then(function(result, error){
// var amount = result/10**6
// console.log(result);
// self.setState({tokenBalance: amount});
// })
this.state.tokenContract.methods.balanceOf(this.state.currentMaskAddress).call(function(error, balance) {
var amount = balance/10**6;
self.setState({tokenBalance: amount});
......@@ -159,37 +119,116 @@ class App extends Component {
getAllowance() {
var self = this;
// this.state.tokenContract.methods.allowance(this.state.currentMaskAddress, this.uniswapAddress).call().then(function(result, error){
// var amount = result/10**6
// self.setState({tokenAllowance: amount});
// })
}
checkNetwork() {
var self = this;
this.state.tokenContract.methods.allowance(this.state.currentMaskAddress, this.uniswapAddress).call().then(function(result, error){
var amount = result/10**6
self.setState({tokenAllowance: amount});
localweb3.eth.net.getNetworkType((err, networkId) => {
console.log(networkId)
switch (networkId) {
case "main":
self.setState({networkMessage: 'Ethereum Mainet', connected: false, interaction: 'disconnected'});
break;
case "morden":
self.setState({networkMessage: 'Morden testnet', connected: false, interaction: 'disconnected'});
break;
case "ropsten":
self.setState({networkMessage: 'Ropsten testnet', connected: false, interaction: 'disconnected'});
break;
case "rinkeby":
self.setState({networkMessage: '', connected: true, interaction: 'connected'});
break;
case "kovan":
self.setState({networkMessage: 'Kovan testnet', connected: false, interaction: 'disconnected'});
break;
default:
self.setState({networkMessage: 'an Unknown network', connected: false, interaction: 'disconnected'});
}
})
}
getInvarient() {
var self = this;
this.state.uniswapContract.methods.invariant().call().then(function(result, error){
self.setState({invariant: result});
})
}
getMarketEth() {
var self = this
this.state.uniswapContract.methods.totalEthQuantity().call().then(function(result, error){
self.setState({marketEth: result});
})
}
getMarketTokens() {
var self = this
this.state.uniswapContract.methods.totalTokenQuantity().call().then(function(result, error){
self.setState({marketTokens: result});
})
}
tokenBuyRate(buyTokensInput) {
if(buyTokensInput >= this.state.marketTokens/10**6) {
this.setState(
{tokenBuyRate: 0,
tokenCost: 0,
tokenFee: 0,
tokenBuyError: 'Not enough tokens'
});
}
else{
var tokensPurchased = buyTokensInput;
var invar = this.state.invariant/10**24;
var totalTokens = this.state.marketTokens/10**6;
var totalEth = this.state.marketEth/10**18;
var newTotalEth = invar/(totalTokens-tokensPurchased);
var fee = (newTotalEth - totalEth)/500;
var ethRequired = newTotalEth - totalEth + fee;
var rate = tokensPurchased/ethRequired;
//add 1% to cost displayed, some people will get more tokens than purchased
//less TX's will fail the minTokens smart contract check
var adjustedTokenCost = ethRequired*1.01;
this.setState(
{tokenBuyRate: rate,
tokenCost: adjustedTokenCost,
tokenFee: fee
});
}
}
ethBuyRate(buyEthInput) {
if(buyEthInput >= this.state.marketEth/10**18) {
this.setState(
{ethBuyRate: 0,
ethCost: 0,
ethFee: 0,
ethBuyError: 'Not enough tokens'
});
}
else{
var ethPurchased = buyEthInput;
var invar = this.state.invariant/10**24;
var totalEth = this.state.marketEth/10**18;
var totalTokens = this.state.marketTokens/10**6;
var newTotalTokens = invar/(totalEth-ethPurchased);
var fee = (newTotalTokens - totalTokens)/500;
var tokensRequired = newTotalTokens - totalTokens + fee;
var rate = ethPurchased/(tokensRequired);
//add 1% to cost displayed, some people will get more eth than purchased
//less TX's will fail the minEth smart contract check
var adjustedEthCost = tokensRequired*1.01;
this.setState(
{ethBuyRate: rate,
ethCost: adjustedEthCost,
ethFee: fee
});
}
}
buyTokens() {
var self = this;
var minTokens = this.state.minimumTokensPurchased
......@@ -220,7 +259,19 @@ class App extends Component {
});
}
onBuyTokensInputChange(event) {
onSelectToken = (selected, type) => {
console.log(selected)
console.log(type)
if (type === 'input'){
this.setState({inputToken: selected});
// do something here to update invariants and values
} else if (type === 'output'){
this.setState({outputToken: selected});
// do something here to update invariants and values
}
}
onBuyTokensInputChange = (event) => {
var buyTokensInput = event.target.value;
if(buyTokensInput && buyTokensInput !== 0){
this.setState({ minimumTokensPurchased: buyTokensInput });
......@@ -228,117 +279,79 @@ class App extends Component {
}
}
onBuyEthInputChange(event) {
onBuyEthInputChange = (event) => {
var buyEthInput = event.target.value;
if(buyEthInput && buyEthInput !== 0){
this.setState({ minimumEthPurchased: buyEthInput });
this.setState({ minimumEthPurchased: buyEthInput, input: buyEthInput, output: this.state.tokenBuyRate.toFixed(3)*buyEthInput, interaction: 'input'});
this.ethBuyRate(buyEthInput);
} else {
this.setState({input: buyEthInput, output: this.state.tokenBuyRate.toFixed(3)*buyEthInput, interaction: 'connected'});
}
}
tokenBuyRate(buyTokensInput) {
if(buyTokensInput >= this.state.marketTokens/10**6) {
this.setState({tokenBuyRate: 0,
tokenCost: 0,
tokenFee: 0,
tokenBuyError: 'Not enough tokens'
});
}
else{
var tokensPurchased = buyTokensInput;
var invar = this.state.invariant/10**24;
var totalTokens = this.state.marketTokens/10**6;
var totalEth = this.state.marketEth/10**18;
var newTotalEth = invar/(totalTokens-tokensPurchased);
var fee = (newTotalEth - totalEth)/500;
var ethRequired = newTotalEth - totalEth + fee;
var rate = tokensPurchased/ethRequired;
//add 1% to cost displayed, some people will get more tokens than purchased
//less TX's will fail the minTokens smart contract check
var adjustedTokenCost = ethRequired*1.01;
this.setState({tokenBuyRate: rate,
tokenCost: adjustedTokenCost,
tokenFee: fee
});
}
}
ethBuyRate(buyEthInput) {
if(buyEthInput >= this.state.marketEth/10**18) {
this.setState({ethBuyRate: 0,
ethCost: 0,
ethFee: 0,
ethBuyError: 'Not enough tokens'
});
}
else{
var ethPurchased = buyEthInput;
var invar = this.state.invariant/10**24;
var totalEth = this.state.marketEth/10**18;
var totalTokens = this.state.marketTokens/10**6;
var newTotalTokens = invar/(totalEth-ethPurchased);
var fee = (newTotalTokens - totalTokens)/500;
var tokensRequired = newTotalTokens - totalTokens + fee;
var rate = ethPurchased/(tokensRequired);
//add 1% to cost displayed, some people will get more eth than purchased
//less TX's will fail the minEth smart contract check
var adjustedEthCost = tokensRequired*1.01;
this.setState({ethBuyRate: rate,
ethCost: adjustedEthCost,
ethFee: fee
});
}
}
render() {
console.log(localweb3)
return (
<div className="App">
<Title />
<div className="noICO">UNI is an ERC20 test token. This is not an ICO.</div>
<img src={unicorn} className="unicorn" alt="unicorn"/>
<img src={ethLogo} className="ethLogo" alt = "ethLogo"/>
<div className="Warning">{this.state.networkMessage}</div>
<div className="Account-info">
Account Detected:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{this.state.ethBalance} ETH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{this.state.tokenBalance.toFixed(2)} UNI<br/>
{this.state.currentMaskAddress}
&nbsp;&nbsp;
<br/>
</div>
<Instructions />
<div className="approveButtonContainer">
<button className="approveButton" onClick={() => {this.approveAllowance(20000*10**6) }}>Approve</button><br/><br/>
{/*Tokens approved: {this.state.tokenAllowance}&nbsp;&nbsp;&nbsp;*/}
</div>
<div className="exchange">
<div className="exchange-buyTokens">
<input
className="exchange-buyTokensInput"
//value={this.state.value}
onChange={this.onBuyTokensInputChange}
/>
<input className="exchange-buyTokensButton" type="exchange-button" defaultValue="Buy UNI" readOnly="readOnly" onClick={() => {this.buyTokens() }}/>
<p className="pinkText">
&nbsp;&nbsp;Rate :&nbsp;&nbsp;{this.state.tokenBuyRate.toFixed(3)} UNI/ETH<br/>
&nbsp;&nbsp;Cost :&nbsp;&nbsp;{this.state.tokenCost.toFixed(5)} ETH<br/>
&nbsp;&nbsp;Fee :&nbsp;&nbsp;&nbsp;&nbsp;{this.state.tokenFee.toFixed(5)} ETH<br/>
</p>
<div className={this.state.connected ? "App" : "App dim"}>
<Head />
<section className="title">
<div className="logo border pa2">
<span role="img" aria-label="Unicorn">🦄</span>
</div>
<NetworkStatus network={this.state.networkMessage} connected={this.state.connected} address={this.state.currentMaskAddress}/>
</section>
<HelperMessages interaction={this.state.interaction} inputToken={this.state.inputToken} outputToken={this.state.outputToken}/>
<section className="order">
<div className="value border pa2">
<input type="number" value={this.state.input} placeholder="0" onChange={this.onBuyEthInputChange} onChange={this.onBuyEthInputChange} />
<SelectToken token={this.state.inputToken} onSelectToken={this.onSelectToken} type="input" />
<p className="dropdown">{'<'}</p>
</div>
<div className="arrow border pa2">
<p></p>
</div>
<div className="exchange-buyEth">
<input
className="exchange-buyEthInput"
//value={this.state.value}
onChange={this.onBuyEthInputChange}
/>
<input className="exchange-buyEthButton" type="exchange-button" defaultValue="Buy ETH" readOnly="readOnly" onClick={() => {this.buyEth() }}/>
<p className="pinkText">
&nbsp;&nbsp;Rate :&nbsp;&nbsp;{this.state.ethBuyRate.toFixed(4)} ETH/UNI<br/>
&nbsp;&nbsp;Cost :&nbsp;&nbsp;{this.state.ethCost.toFixed(5)} UNI<br/>
&nbsp;&nbsp;Fee :&nbsp;&nbsp;&nbsp;&nbsp;{this.state.ethFee.toFixed(5)} UNI
</p>
<div className="value border pa2">
<input type="number" value={this.state.output} placeholder="0" onChange={this.onBuyTokensInputChange}/>
<SelectToken token={this.state.outputToken} onSelectToken={this.onSelectToken} type="output"/>
<p className="dropdown">{'<'}</p>
</div>
</div>
</section>
<section className="rate border pa2">
<span className="rate-info">
<p>Rate</p>
<p>{this.state.tokenBuyRate.toFixed(3)} UNI/ETH</p>
</span>
<span className="rate-info">
<p>Cost</p>
<p>{this.state.tokenCost.toFixed(5)} ETH</p>
</span>
<span className="rate-info">
<p>Fee</p>
<p>{this.state.tokenFee.toFixed(5)} ETH</p>
</span>
</section>
{this.state.interaction === 'input' ?
<section className="swap border pa2">
<a href="">{"I want to swap " + this.state.input + " " + this.state.inputToken.value + " for " + this.state.output + " " + this.state.outputToken.value}</a>
</section>
: <section className="swap hidden border pa2"></section>}
<section className="links">
<a href="" className="link border pa2">
<p className="underline">Provide Liquidity to collect fees</p>
<p>+</p>
</a>
<a href="" className="link border pa2">
<p className="underline">Add a new token</p>
<p>+</p>
</a>
</section>
<section className="links">
<a href="" className="link border pa2">
<p className="underline">About</p>
<p></p>
</a>
</section>
</div>
);
}
......
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
import React from 'react';
import {Helmet} from "react-helmet";
import unicorn from '../images/🦄.png'
function Head(props) {
return (
<Helmet>
<meta charSet="utf-8" />
<link rel="icon" href={unicorn} sizes="32x32" type="image/png" />
<title>Uniswap - ERC20 Market Maker</title>
</Helmet>
);
}
export default Head;
import React from 'react';
function HelperMessages(props) {
let message = ''
switch (props.interaction) {
case 'connected':
message = "Nice! You're connected. Enter a value below to get started."
break;
case 'input':
message = "You're swapping " + props.inputToken.value + " for " + props.outputToken.value + ". Want to know more about how the prices are determined?"
// message = "Oops, looks like this address doesn't have a enough " + props.inputToken.value + " to make this trade. Add more funds to make this swap."
break;
default:
message = "Hi there! This site helps you swap ERC20 tokens. Looks like you aren't connected. Need help?"
}
return (
<section className="info border pa2">
<p>{message}</p>
<p></p>
</section>
)
}
export default HelperMessages;
import React from 'react';
function NetworkStatus(props) {
let isConnected = props.connected
if (isConnected){
return (
<div className="connection border pa2">
<a href={'https://etherscan.io/search?q=' + props.address}>{props.address}</a>
<p></p>
</div>
)
} else {
return (
<div className="connection red border pa2">
<p>{'MetaMask connected to ' + props.network + ' Switch to Rinkeby and refresh!'}</p>
<p></p>
</div>
)
}
}
export default NetworkStatus;
/**
* React Select
* ============
* Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
* https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
* MIT License: https://github.com/JedWatson/react-select
*/
.Select-input {
overflow: hidden;
max-width: calc(100% - 20px);
}
.Select {
position: relative;
/* width: 100%; */
}
.Select-control{
width: 5rem;
}
.Select-clear-zone{
display: none;
}
.Select-value{
position: absolute;
width: 5rem;
margin-top: 1px;
}
.Select-input{
width: 5rem;
}
.Select-menu-outer {
background-color: #fff;
border: 1px solid #ccc;
border-top-color: #e6e6e6;
box-sizing: border-box;
margin-top: -1px;
max-height: 200px;
position: absolute;
right: 0;
top: 100%;
width: 100%;
width: 200px;
z-index: 1;
-webkit-overflow-scrolling: touch;
}
.Select-menu {
max-height: 198px;
overflow-y: auto;
}
.Select-option {
box-sizing: border-box;
background-color: #fff;
color: #666666;
cursor: pointer;
display: block;
padding: 8px 10px;
}
.Select .Select-aria-only {
position: absolute;
display: inline-block;
height: 1px;
width: 1px;
clip: rect(0, 0, 0, 0);
overflow: hidden;
float: left;
}
.Select-option {
box-sizing: border-box;
background-color: #fff;
color: #666666;
cursor: pointer;
display: block;
padding: 8px 10px;
}
.Select-option.is-selected {
background-color: #f5faff;
background-color: rgba(0, 126, 255, 0.04);
color: #333;
}
.Select-option.is-focused {
background-color: #ebf5ff;
background-color: rgba(0, 126, 255, 0.08);
color: #333;
}
.Select-option.is-disabled {
color: #cccccc;
cursor: default;
}
.Select-noresults {
box-sizing: border-box;
color: #999999;
cursor: default;
display: block;
padding: 8px 10px;
}
.Select--multi .Select-input {
vertical-align: middle;
margin-left: 10px;
padding: 0;
}
.Select--multi.Select--rtl .Select-input {
margin-left: 0;
margin-right: 10px;
}
.Select--multi.has-value .Select-input {
margin-left: 5px;
}
.Select--multi .Select-value {
background-color: #ebf5ff;
background-color: rgba(0, 126, 255, 0.08);
/* border: 1px solid #c2e0ff;
border: 1px solid rgba(0, 126, 255, 0.24); */
color: #007eff;
display: inline-block;
font-size: 0.9em;
line-height: 1.4;
margin-left: 5px;
margin-top: 5px;
vertical-align: top;
}
.Select--multi .Select-value-icon,
.Select--multi .Select-value-label {
display: inline-block;
vertical-align: middle;
}
.Select--multi .Select-value-label {
border-bottom-right-radius: 2px;
border-top-right-radius: 2px;
cursor: default;
padding: 2px 5px;
}
.Select--multi a.Select-value-label {
color: #007eff;
cursor: pointer;
text-decoration: none;
}
.Select--multi a.Select-value-label:hover {
text-decoration: underline;
}
.Select--multi .Select-value-icon {
cursor: pointer;
border-bottom-left-radius: 2px;
border-top-left-radius: 2px;
border-right: 1px solid #c2e0ff;
border-right: 1px solid rgba(0, 126, 255, 0.24);
padding: 1px 5px 3px;
}
.Select--multi .Select-value-icon:hover,
.Select--multi .Select-value-icon:focus {
background-color: #d8eafd;
background-color: rgba(0, 113, 230, 0.08);
color: #0071e6;
}
.Select--multi .Select-value-icon:active {
background-color: #c2e0ff;
background-color: rgba(0, 126, 255, 0.24);
}
.Select--multi.Select--rtl .Select-value {
margin-left: 0;
margin-right: 5px;
}
.Select--multi.Select--rtl .Select-value-icon {
border-right: none;
border-left: 1px solid #c2e0ff;
border-left: 1px solid rgba(0, 126, 255, 0.24);
}
.Select--multi.is-disabled .Select-value {
background-color: #fcfcfc;
border: 1px solid #e3e3e3;
color: #333;
}
.Select--multi.is-disabled .Select-value-icon {
cursor: not-allowed;
border-right: 1px solid #e3e3e3;
}
.Select--multi.is-disabled .Select-value-icon:hover,
.Select--multi.is-disabled .Select-value-icon:focus,
.Select--multi.is-disabled .Select-value-icon:active {
background-color: #fcfcfc;
}
.Select input::-webkit-contacts-auto-fill-button,
.Select input::-webkit-credentials-auto-fill-button {
display: none !important;
}
.Select input::-ms-clear {
display: none !important;
}
.Select input::-ms-reveal {
display: none !important;
}
.Select,
.Select div,
.Select input,
.Select span {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.Select input:focus{
/* outline: none; */
}
.Select.is-searchable.is-open > .Select-control {
cursor: text;
}
.Select.is-searchable.is-focused:not(.is-open) > .Select-control {
cursor: text;
}
.Select.Select--rtl {
direction: rtl;
text-align: right;
}
.Select.is-open .Select-input {
padding: 0 !important;
}
.Select.is-open .Select-input,
.Select.is-open .Select-input input {
width: 100% !important;
}
.Select.is-open .Select-input input {
text-indent: 1px;
}
import React, { Component } from 'react'
import Select from 'react-select'
import './SelectToken.css'
class SelectToken extends Component {
constructor (props) {
super(props)
this.state = {
selectedOption: this.props.token,
}
}
handleChange = (selectedOption) => {
this.setState({ selectedOption })
this.props.onSelectToken(selectedOption, this.props.type)
console.log(`Selected: ${selectedOption.label}`)
}
render () {
const { selectedOption } = this.state
const value = selectedOption && selectedOption.value
return (
<Select
name="form-field-name"
value={value}
onChange={this.handleChange}
className="select"
options={[
{ value: 'OMG', label: 'OMG', clearableValue: false },
{ value: 'ETH', label: 'ETH', clearableValue: false },
{ value: 'BNT', label: 'BNT', clearableValue: false },
{ value: 'FOM', label: 'FOAM', clearableValue: false },
]}
/>
)
}
}
export default SelectToken;
.instructions {
position: fixed;
background-color: rgba(0,0,0,0.4);
bottom: 1vh;
border-radius: 15px;
border: 1px solid;
border-color: rgb(122, 251, 255);
color: rgb(122, 251, 255);
text-shadow: 2px 2px 10px #2daae0;
margin-left: 35vw;
margin-right: 1vw;
max-height: 55vh;
-webkit-transition-duration: 0.5s;
transition-duration: 0.5s;
overflow-y: scroll;
} .instructions:hover{
color: rgb(216, 169, 236);
text-shadow: 1px 1px 5px #ff69f0;
border-color: rgb(180, 81, 179);
background-color: rgba(0,0,0,0.55);
}
.instructions-title {
text-align: left;
padding-left: 40px;
padding-top: 10px;
font-size: 22px;
}
.instructions-text {
font-size: 15px;
padding-top: 10px;
text-align: left;
padding-left: 25px;
padding-right: 15px;
}
.instructions a:link, .instructions a:visited, .instructions-highlight {
color: rgb(122, 251, 255);
text-shadow: 2px 2px 10px #2daae0;
}
.instructions a:hover, .instructions-highlight:hover {
text-shadow: none;
}
.instructions-approve {
font-size: 12px;
color: rgb(122, 251, 255);
border: 1px solid;
border-color: rgb(122, 251, 255);
border-radius: 4px;
padding: 1px 2px;
text-shadow: none;
}.instructions-approve:hover {
cursor: default;
}
import React, { Component } from 'react';
import './Instructions.css';
class Instructions extends Component{
render() {
return (
<div className="instructions">
<div className="instructions-title">Instructions and Info</div>
<div className="instructions-text">
1) Add UNI test token address to MetaMask (first time only)<br/>
&nbsp;&nbsp;&nbsp;&nbsp;Token Address: <span className="instructions-highlight">0xca9901076d02f89794262869aad1340bd45d8489</span><br/><br/>
2) Check that MetaMask is connected to the Rinkeby Testnet<br/><br/>
3) You can now buy UNI test tokens with ETH! Visit the&nbsp;
<a href= "https://faucet.rinkeby.io/">Rinkeby faucet</a> to aquire testnet ETH <br/><br/>
4) To buy ETH with UNI you must approve the Uniswap smart contract to transfer UNI tokens on your behalf. Click the&nbsp;
<span className="instructions-approve"><b>Approve</b></span> button now! (first time only)<br/><br/>
5) Rate is variable based on token availiblity, enter number of tokens to see rate and cost.<br/><br/>
6) This is a proof-of-concept for a decentralized Market Maker exchange. Stay tuned for ENS support, token-to-token pairs, the ability to become a liquidity provider and collect fees,
and a Mainet launch! :) <br/> <br/>
7) This demo was hastily programmed by a single developer <i>(Hi, my name is Hayden!)</i>. Please reach out to me with any questions, comments, complaints, or bug reports.<br/><br/>
&nbsp;&nbsp;Email: <span className="instructions-highlight">hayden@uniswap.io</span>&nbsp;&nbsp;
GitHub: <a href= "https://github.com/haydenadams/uniswap">https://github.com/haydenadams/uniswap<br/></a>
&nbsp;&nbsp;ETH Address: <span className="instructions-highlight">0x4779721CaC18A46DbCF148f2Dd7A8E6cc1F90078</span><br/><br/>
</div>
</div>
);
}
}
export default Instructions;
.install-metamask {
width: 100vw;
top: 70vh;
position: fixed;
font-family: Optima, sans-serif;
font-size: 26px;
text-align: center;
}
.install-metamask a {
}
import React, { Component } from 'react';
import './Splashscreen.css';
var ModelViewer = require('metamask-logo')
// To render with fixed dimensions:
var viewer = ModelViewer({
// Dictates whether width & height are px or multiplied
// pxNotRatio: true,
// width: 500,
// height: 400,
pxNotRatio: false,
width: 1,
height: 0.7,
// To make the face follow the mouse.
followMouse: true,
// head should slowly drift (overrides lookAt)
// slowDrift: true,
})
var metamaskLink = 'https://metamask.io';
class Splashscreen extends Component{
render() {
return (
<div className="install-metamask">
Uniswap requires MetaMask to connect to the Ethereum blockchain.<br/><br/>
<a href="https://metamask.io"> {metamaskLink} </a>
</div>
);
}
}
export default Splashscreen;
@font-face {
font-family: 'LeveloLineBold'; /*a name to be used later*/
src: url('../../fonts/LoveloLineBold.otf'); /*URL to font*/
}
.title {
font-family: 'LeveloLineBold';
/*font-family: Optima, sans-serif;*/
position: fixed;
font-size: 10vh;
margin-top: 2vh;
margin-left: 2vh;
float: left;
text-shadow: 3px 3px 10px #f29ae1;
color: rgb(220, 173, 247);
font-weight: bold;
-webkit-text-stroke-width: 1px;
-webkit-text-stroke-color: rgb(180, 81, 179);
cursor: default;
}
/* entire container, keeps perspective */
.titled-container {
position: fixed;
perspective: 800px;
/*border: 2px solid rgb(207, 9, 158);*/
}
/* flip the pane when hovered */
.titled-container:hover > .title{
transform: rotateX(180deg);
color: rgb(122, 251, 255);
text-shadow: 3px 3px 10px #2daae0;
font-weight: bold;
-webkit-text-stroke-width: 2px;
-webkit-text-stroke-color: rgb(22, 177, 210);
}
.titled-container, .front, .back {
width: 26vw;
height: 11vh;
}
.front, .back {
width: 0.1vh;
height: 0.001vh;
}
/* flip speed goes here */
.title {
transition: 2.5s;
transform-style: preserve-3d;
position: relative;
}
/* hide back of pane during swap */
.front, .back {
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
/* front pane, placed above back */
.front {
z-index: 2;
/* for firefox 31 */
transform: rotateX(0deg);
}
/* back, initially hidden pane */
.back {
transform: rotateX(180deg);
}
import React, { Component } from 'react';
import './Title.css';
class Title extends Component{
render() {
return (
<div className="titled-container">
<div className="title">
<div className="front">UNISWAP</div>
<div className="back">UNISWAP</div>
</div>
</div>
);
}
}
export default Title;
module.exports.uniswapABI = [{"constant":false,"inputs":[{"name":"tokenAmount","type":"uint256"}],"name":"ownerTokenWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tokenAmount","type":"uint256"}],"name":"ownerTokenDeposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ethAmount","type":"uint256"}],"name":"ownerEthWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"sellQuantity","type":"uint256"},{"name":"minimumEth","type":"uint256"},{"name":"timeout","type":"uint256"}],"name":"tokenToEth","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalTokenQuantity","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"minimumTokens","type":"uint256"},{"name":"timeout","type":"uint256"}],"name":"ethToTokens","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"initialTokenQuantity","type":"uint256"}],"name":"initiateUniswap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalEthQuantity","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"invariant","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"ownerEthDeposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_tokenAddress","type":"address"}],"payable":true,"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"buyer","type":"address"},{"indexed":false,"name":"tokensPurchased","type":"uint256"},{"indexed":false,"name":"ethSpent","type":"uint256"}],"name":"TokenPurchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"buyer","type":"address"},{"indexed":false,"name":"ethPurchased","type":"uint256"},{"indexed":false,"name":"tokensSpent","type":"uint256"}],"name":"EthPurchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]
module.exports.tokenABI = [{"constant":true,"inputs":[],"name":"mintingFinished","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"finishMinting","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[],"name":"MintFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]
......@@ -2,5 +2,4 @@ body {
margin: 0;
padding: 0;
font-family: sans-serif;
overflow: hidden;
}
......@@ -2,20 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import Splashscreen from './components/misc/Splashscreen'
import registerServiceWorker from './registerServiceWorker';
function Detect(props) {
const metamask = props.metamask;
if(typeof metamask === 'undefined') {
return <Splashscreen />
}
else {
return <App />
}
}
ReactDOM.render(
<Detect metamask={window.web3} />, document.getElementById('root')
);
ReactDOM.render(<App metamask={window.web3} />, document.getElementById('root'));
registerServiceWorker();
......@@ -32,12 +32,21 @@ export default function register() {
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (!isLocalhost) {
// Is not local host. Just register service worker
registerValidSW(swUrl);
} else {
if (isLocalhost) {
// This is running on localhost. Lets check if a service worker still exists or not.
checkValidServiceWorker(swUrl);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://goo.gl/SC7cgQ'
);
});
} else {
// Is not local host. Just register service worker
registerValidSW(swUrl);
}
});
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment