Tabula Rasa

This commit is contained in:
Richard Ramos 2018-07-03 13:20:41 -04:00
parent ddec5b3b76
commit 94a63ab4f9
7 changed files with 116 additions and 317 deletions

BIN
app/images/sampleShip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -1,7 +1,5 @@
import EmbarkJS from 'Embark/EmbarkJS';
import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';
import SpaceshipToken from 'Embark/contracts/SpaceshipToken';
import { Form, FormGroup, FormControl, InputGroup, Button, Grid, Row, Col, ControlLabel} from 'react-bootstrap';
import Spinner from 'react-spinkit';
@ -29,74 +27,14 @@ class AddToken extends Component {
handleClick(e){
e.preventDefault();
const { mint } = SpaceshipToken.methods;
this.setState({isSubmitting: true});
let attributes = {
"name": "Nave Espacial",
"image": "",
"attributes": {
"energy": this.state.energy,
"lasers": this.state.lasers,
"shield": this.state.shield
}
}
let toSend;
// Cargamos la imagen a IPFS
EmbarkJS.Storage.uploadFile(this.state.fileToUpload)
.then(fileHash => {
// Agregamos los datos a la lista de atributos
attributes.imageHash = fileHash;
attributes.image = 'https://ipfs.io/ipfs/' + fileHash;
// Guardamos la lista de atributos
return EmbarkJS.Storage.saveText(JSON.stringify(attributes))
})
.then(attrHash => {
// El hash que retorna IPFS se almacenara dentro de los datos del token
// El precio lo convertimos de ether a wei
toSend = mint(web3.utils.toHex(attrHash),
this.state.energy,
this.state.lasers,
this.state.shield,
web3.utils.toWei(this.state.price, "ether"));
return toSend.estimateGas();
})
.then(estimatedGas => {
return toSend.send({from: web3.eth.defaultAccount,
gas: estimatedGas + 1000});
})
.then(receipt => {
console.log(receipt);
// Vaciar formulario
this.setState({
fileToUpload: [],
energy: '',
lasers: '',
shield: '',
price: ''
});
this.props.loadShipsForSale();
// TODO: show success
return true;
})
.catch((err) => {
console.error(err);
// TODO: show error blockchain / ipfs
})
.finally(() => {
this.setState({isSubmitting: false});
});
// TODO: Implementar llamada al contrato para crear el token
// Un token espera los siguientes atributos: energy, lasers, shield and price
// al igual que una imagen
// La siguiente funcion se puede llamar para actualizar la lista de tokens
this.props.loadShipsForSale();
this.setState({isSubmitting: false});
}
render(){

View File

@ -1,8 +1,6 @@
import EmbarkJS from 'Embark/EmbarkJS';
import React, { Fragment, Component } from 'react';
import Toggle from 'react-toggle'
import SpaceshipToken from 'Embark/contracts/SpaceshipToken';
import SpaceshipMarketplace from 'Embark/contracts/SpaceshipMarketplace';
import ShipList from './shipList.js'
class MarketPlace extends Component {

View File

@ -1,10 +1,6 @@
import React, { Component, Fragment } from 'react';
import ReactDOM from 'react-dom';
import EmbarkJS from 'Embark/EmbarkJS';
import web3 from "Embark/web3"
import { Button, FormControl, InputGroup } from 'react-bootstrap';
import SpaceshipToken from 'Embark/contracts/SpaceshipToken';
import SpaceshipMarketplace from 'Embark/contracts/SpaceshipMarketplace';
import Spinner from 'react-spinkit';
import MarketPlace from './marketplace';
@ -27,25 +23,17 @@ class Ship extends Component {
}
componentDidMount(){
EmbarkJS.onReady((err) => {
this._loadAttributes();
});
// TODO: cuando se carga el componente se deben buscar los atributos del token
this._loadAttributes();
}
_loadAttributes(){
// Cargar los atributos involucra leer la metadata
EmbarkJS.Storage.get(web3.utils.toAscii(this.props.metadataHash))
.then(content => {
const jsonMetadata = JSON.parse(content);
// Podemos usar este metodo
const _url = EmbarkJS.Storage.getUrl(jsonMetadata.imageHash);
// o leer el url que grabamos en la metadata
// const _url = jsonMetadata.image
this.setState({image: _url})
});
// TODO: implementar carga de atributos aca
// El unico atributo interesante es la imagen
// Guardar el url en this.state.image
// Ejemplo
this.setState({image: "./images/sampleShip.png"});
}
showSellForm = (show) => {
@ -53,93 +41,34 @@ class Ship extends Component {
}
sellShip = () => {
const { forSale } = SpaceshipMarketplace.methods;
const { sellPrice } = this.state;
const { id } = this.props;
// TODO: vender una nave para que otro usuario la pueda comprar
// En props esta el atributo 'id', que podemos usar para determinar el id del token
// El precio esta en el estado this.state.sellPrice
this.setState({isSubmitting: true});
const toSend = forSale(id, web3.utils.toWei(sellPrice, 'ether'))
toSend.estimateGas()
.then(estimatedGas => {
return toSend.send({from: web3.eth.defaultAccount,
gas: estimatedGas + 1000});
})
.then(receipt => {
console.log(receipt);
this.props.onAction();
// TODO: show success
return true;
})
.catch((err) => {
console.error(err);
// TODO: show error blockchain
})
.finally(() => {
this.setState({isSubmitting: false});
});
// Llamar la siguiente funcion para refrescar las listas
this.props.onAction();
this.setState({isSubmitting: false});
}
buyFromStore = () => {
const { buySpaceship } = SpaceshipToken.methods;
const toSend = buySpaceship(this.props.id)
// TODO: comprar token recien creado
// En props esta el atributo 'id' y 'price', que podemos usar para determinar el id del token
this.setState({isSubmitting: true});
toSend.estimateGas({value: this.props.price })
.then(estimatedGas => {
return toSend.send({from: web3.eth.defaultAccount,
value: this.props.price,
gas: estimatedGas + 1000000});
})
.then(receipt => {
console.log(receipt);
console.log("Updating ships");
this.props.onAction();
// TODO: show success
return true;
})
.catch((err) => {
console.error(err);
// TODO: show error blockchain
})
.finally(() => {
this.setState({isSubmitting: false});
});
// Llamar la siguiente funcion para refrescar las listas
this.props.onAction();
this.setState({isSubmitting: false});
}
buyFromMarket = () => {
const { buy } = SpaceshipMarketplace.methods;
const toSend = buy(this.props.saleId);
// TODO: comprar tokens puestos a la venta por otra persona
// En props esta el 'saleId' y 'price' para poder comprarlo
this.setState({isSubmitting: true});
toSend.estimateGas({value: this.props.price })
.then(estimatedGas => {
return toSend.send({from: web3.eth.defaultAccount,
value: this.props.price,
gas: estimatedGas + 1000000});
})
.then(receipt => {
console.log(receipt);
this.props.onAction();
// TODO: show success
return true;
})
.catch((err) => {
console.error(err);
// TODO: show error blockchain
})
.finally(() => {
this.setState({isSubmitting: false});
});
// Llamar la siguiente funcion para refrescar las listas
this.props.onAction();
this.setState({isSubmitting: false});
}
render(){
@ -164,7 +93,7 @@ class Ship extends Component {
: '')
}
{ showSellForm
{ showSellForm && salesEnabled
? <Fragment>
<InputGroup>
<FormControl

View File

@ -17,41 +17,20 @@ class ShipList extends Component {
}
componentDidMount(){
EmbarkJS.onReady((err) => {
// Al cargar la lista de naves, determinamos si estan aprobadas para la venta
const { isApprovedForAll } = SpaceshipToken.methods;
isApprovedForAll(web3.eth.defaultAccount, SpaceshipMarketplace.options.address)
.call()
.then(isApproved => {
this.setState({salesEnabled: isApproved});
});
});
// TODO: nos interesa saber si las ventas estan habilidatas o no para los tokens
// El estado que maneja esto es 'salesEnabled'.
// Aqui lo seteamos en true, solo para ver que funcione, pero debe venir del contrato
this.setState({salesEnabled: false});
}
enableMarketplace = () => {
const { setApprovalForAll } = SpaceshipToken.methods;
// TODO: esta funcion la llama el toggle de mas abajo cuando se clickea
// Debe setear siempre el valor de 'salesEnabled'
// Las siguientes lineas solo muestran el funcionamiento en el UI
// pero debe implementarse creando una transaccion
this.setState({isSubmitting: true});
const toSend = setApprovalForAll(SpaceshipMarketplace.options.address, !this.state.salesEnabled);
toSend.estimateGas()
.then(estimatedGas => {
return toSend.send({from: web3.eth.defaultAccount,
gas: estimatedGas + 1000});
})
.then(receipt => {
this.setState({salesEnabled: !this.state.salesEnabled});
console.log(receipt);
})
.catch((err) => {
console.error(err);
// TODO: show error blockchain
})
.finally(() => {
this.setState({isSubmitting: false});
});
this.setState({salesEnabled: !this.state.salesEnabled});
this.setState({isSubmitting: false});
}
render = () => {

View File

@ -16,55 +16,25 @@ class WithdrawBalance extends Component {
}
componentDidMount(){
EmbarkJS.onReady((err) => {
// Al cargar el componente, obtenemos el balance
this._getBalance();
});
// TODO: Al cargar el componente, debemos obtener el balance
// podemos hacerlo llamando a this._getBalance();
}
_getBalance(){
// Se consulta el balance del contrato
web3.eth.getBalance(SpaceshipToken.options.address)
.then(newBalance => {
this.setState({
balance: web3.utils.fromWei(newBalance, "ether")
});
});
// TODO: implementar, el estado a actualizar es 'balance'
}
handleClick(e){
const { withdrawBalance } = SpaceshipToken.methods;
e.preventDefault();
// TODO: este metodo se debe llamar al hacer click en retirar fondos
// Debe extraer el balance total del contrato del token, y actualizar el UI
// para mostrar que no hay balance disponible
this.setState({isSubmitting: true});
// Retiramos el balance total del contrato
// Estimamos primero el gas para saber cuanto gas enviar
const toSend = withdrawBalance();
toSend.estimateGas()
.then(estimatedGas => {
// Es una buena practica mandar siempre algo mas del gas estimado
return toSend.send({from: web3.eth.defaultAccount,
gas: estimatedGas + 1000});
})
.then(receipt => {
console.log(receipt);
this._getBalance();
// TODO mostrar info
return true;
})
.catch((err) => {
console.error(err);
// TODO: mostrar error
})
.finally(() => {
this.setState({isSubmitting: false});
});
this._getBalance();
this.setState({isSubmitting: false});
}
render(){

View File

@ -1,8 +1,5 @@
import EmbarkJS from 'Embark/EmbarkJS';
import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';
import SpaceshipToken from 'Embark/contracts/SpaceshipToken';
import SpaceshipMarketplace from 'Embark/contracts/SpaceshipMarketplace';
import ShipList from './components/shipList.js';
import WithdrawBalance from './components/withdrawBalance.js';
import AddToken from './components/addToken.js';
@ -22,96 +19,84 @@ class App extends Component {
}
componentDidMount(){
EmbarkJS.onReady((err) => {
this._isOwner();
this._loadEverything();
});
// TODO: Debemos determinar si la cuenta que estamos usando es la del dueno del token
// y cargar tambien las naves
this._isOwner();
this._loadEverything();
}
_loadEverything(){
// Cargamos todas las naves que estan a la venta, que estan en mi wallet y en el mercado
this._loadShipsForSale();
this._loadMyShips();
this._loadMarketPlace();
}
_isOwner(){
// Nos interesa saber si somos el dueno del contrato para mostrar el formulario de tokens
SpaceshipToken.methods.owner()
.call()
.then(owner => {
this.setState({isOwner: owner == web3.eth.defaultAccount});
return true;
});
}
_loadMarketPlace = async () => {
const { nSale, sales, saleInformation } = SpaceshipMarketplace.methods;
const { spaceships } = SpaceshipToken.methods;
const total = await nSale().call();
const list = [];
if(total){
for (let i = total-1; i >= 0; i--) {
const sale = await sales(i).call();
const _info = await spaceships(sale.spaceshipId).call();
const ship = {
owner: sale.owner,
price: sale.price,
id: sale.spaceshipId,
saleId: i,
..._info
};
list.push(ship);
}
}
this.setState({marketPlaceShips: list.reverse()});
}
_loadShipsForSale = async () => {
const { shipsForSaleN, shipsForSale, spaceshipPrices, spaceships } = SpaceshipToken.methods;
const total = await shipsForSaleN().call();
const list = [];
if(total){
for (let i = total-1; i >= 0; i--) {
const shipId = await shipsForSale(i).call();
const _info = await spaceships(shipId).call();
const _price = await spaceshipPrices(shipId).call();
const ship = {
price: _price,
id: shipId,
..._info
};
list.push(ship);
}
}
this.setState({shipsForSale: list.reverse()});
// TODO: Nos interesa saber si somos el dueno del contrato para mostrar el formulario de tokens
// Debemos actualizar el estado isOwner con la informacion del contrato
this.setState({isOwner: true});
}
_loadMyShips = async () => {
const { balanceOf, tokenOfOwnerByIndex, spaceships } = SpaceshipToken.methods;
const total = await balanceOf(web3.eth.defaultAccount).call();
const list = [];
if(total){
for (let i = total-1; i >= 0; i--) {
const myShipId = await tokenOfOwnerByIndex(web3.eth.defaultAccount, i).call();
const _info = await spaceships(myShipId).call();
const ship = {
id: myShipId,
..._info
};
list.push(ship);
}
}
// TODO: aqui nos interesa cargar la lista de naves que posee el usuario
// se espera un array de objetos en el estado myShips
// cada objeto debe tener los siguientes atributos:
// {
// id: "id del token",
// energy: "Atributo del token",
// lasers: "Atributo del token",
// shield: "Atributo del token",
// metadataHash: "Atributo del token",
// }
// Ejemplo:
const myShip = {
id: 1,
energy: 10,
lasers: 5,
shield: 7,
metadataHash: "METADATA"
};
const list = [ myShip ];
this.setState({myShips: list.reverse()});
}
}
_loadShipsForSale = async () => {
// TODO: aqui nos interesa cargar la lista de naves a la venta cuando generamos el token
// se espera un array de objetos en el estado shipsForSale
// cada objeto debe tener los siguientes atributos:
// {
// price: "precio de venta",
// id: "id del token",
// energy: "Atributo del token",
// lasers: "Atributo del token",
// shield: "Atributo del token",
// metadataHash: "Atributo del token",
// }
let list = [];
this.setState({shipsForSale: list.reverse()});
}
_loadMarketPlace = async () => {
// TODO: debemos cargar la lista de naves que estan a la venta en el marketplace
// se espera un array de objetos en el estado marketPlaceShips
// cada objeto debe tener los siguientes atributos:
// {
// owner: "dueno de la nave en venta",
// price: "precio de venta",
// id: "id del token",
// saleId: "id de la venta",
// energy: "Atributo del token",
// lasers: "Atributo del token",
// shield: "Atributo del token",
// metadataHash: "Atributo del token",
// }
let list = [];
this.setState({marketPlaceShips: list.reverse()});
}
render(){
const { isOwner, hidePanel, shipsForSale, myShips, marketPlaceShips } = this.state;