Documented contract

This commit is contained in:
Richard Ramos 2018-07-02 13:20:05 -04:00
parent 7ec80a2270
commit a3cba3d034
2 changed files with 60 additions and 38 deletions

View File

@ -4,6 +4,7 @@ import "./SpaceshipToken.sol";
import "zeppelin-solidity/contracts/token/ERC721/ERC721Holder.sol"; import "zeppelin-solidity/contracts/token/ERC721/ERC721Holder.sol";
/// @title Escrow para compra venta del token
contract SpaceshipMarketplace is ERC721Holder { contract SpaceshipMarketplace is ERC721Holder {
// Esta estructura guarda informacion sobre las ventas // Esta estructura guarda informacion sobre las ventas
@ -13,27 +14,32 @@ contract SpaceshipMarketplace is ERC721Holder {
address owner; address owner;
} }
SpaceshipToken token; SpaceshipToken public token;
Sale[] public sales; Sale[] public sales;
mapping(uint => uint) spaceshipToSale; mapping(uint => uint) public spaceshipToSale;
event NewSale(uint indexed spaceshipId, uint price, uint saleId); event NewSale(uint indexed spaceshipId, uint price, uint saleId);
event ShipSold(uint indexed spaceshipId, uint price, address indexed oldOwner, address indexed newOwner); event ShipSold(uint indexed spaceshipId, uint price, address indexed oldOwner, address indexed newOwner);
/// @notice Constructor
constructor(SpaceshipToken _token) public { /// @param _token Direccion del token
token = _token; constructor(address _token) public {
token = SpaceshipToken(_token);
} }
function buy(uint _saleId) payable { /// @notice Comprar token
/// @param _saleId Id de la venta que se desea
function buy(uint _saleId) public payable {
Sale storage s = sales[_saleId]; Sale storage s = sales[_saleId];
// TODO: descomentar esto para evitar que el dueno compre su propia nave // TODO: descomentar esto para evitar que el dueno compre su propia nave
// require(s.owner != msg.sender); // require(s.owner != msg.sender);
require(msg.value >= s.price); require(msg.value >= s.price);
// Devolvemos el sobrante
uint refund = msg.value - s.price; uint refund = msg.value - s.price;
if(refund > 0) if(refund > 0)
msg.sender.transfer(refund); msg.sender.transfer(refund);
@ -47,14 +53,16 @@ contract SpaceshipMarketplace is ERC721Holder {
token.approve(msg.sender, s.spaceshipId); token.approve(msg.sender, s.spaceshipId);
token.safeTransferFrom(address(this), msg.sender, s.spaceshipId); token.safeTransferFrom(address(this), msg.sender, s.spaceshipId);
// Eliminamos la venta // TODO: reorder // Eliminamos la venta
delete spaceshipToSale[s.spaceshipId]; delete spaceshipToSale[s.spaceshipId];
Sale replacer = sales[sales.length - 1]; Sale replacer = sales[sales.length - 1];
sales[_saleId] = replacer; sales[_saleId] = replacer;
sales.length--; sales.length--;
} }
/// @notice Publicar token para venta
/// @param _spaceshipId Id del token
/// @param _price Precio de venta
function forSale(uint _spaceshipId, uint _price){ function forSale(uint _spaceshipId, uint _price){
// Solo se pueden vender tus propias naves // Solo se pueden vender tus propias naves
require(token.ownerOf(_spaceshipId) == msg.sender); require(token.ownerOf(_spaceshipId) == msg.sender);
@ -68,6 +76,7 @@ contract SpaceshipMarketplace is ERC721Holder {
owner: msg.sender owner: msg.sender
}); });
// Agregamos el token a la lista de vtokens en venta
uint saleId = sales.push(s) - 1; uint saleId = sales.push(s) - 1;
spaceshipToSale[_spaceshipId] = saleId; spaceshipToSale[_spaceshipId] = saleId;
@ -75,6 +84,8 @@ contract SpaceshipMarketplace is ERC721Holder {
emit NewSale(_spaceshipId, _price, saleId); emit NewSale(_spaceshipId, _price, saleId);
} }
/// @notice Retirar token de listado de venta
/// @param _spaceshipId Id del token
function withdraw(uint _spaceshipId){ function withdraw(uint _spaceshipId){
require(sales[spaceshipToSale[_spaceshipId]].owner == msg.sender); require(sales[spaceshipToSale[_spaceshipId]].owner == msg.sender);
@ -86,6 +97,7 @@ contract SpaceshipMarketplace is ERC721Holder {
token.safeTransferFrom(address(this), msg.sender, _spaceshipId); token.safeTransferFrom(address(this), msg.sender, _spaceshipId);
} }
/// @notice Cantidad de tokens a la venta
function nSale() public view returns(uint) { function nSale() public view returns(uint) {
return sales.length; return sales.length;
} }

View File

@ -1,15 +1,14 @@
pragma solidity 0.4.24; pragma solidity 0.4.24;
import "zeppelin-solidity/contracts/token/ERC721/ERC721Token.sol"; import "zeppelin-solidity/contracts/token/ERC721/ERC721Token.sol";
import 'zeppelin-solidity/contracts/ownership/Ownable.sol'; import "zeppelin-solidity/contracts/ownership/Ownable.sol";
/**
@title Contrato base para Mexico Workshop /// @title Contrato base para Mexico Workshop
@dev En Status tambien hablamos espanol ;) /// @dev En Status tambien hablamos espanol ;)
*/
contract SpaceshipToken is ERC721Token("CryptoSpaceships", "CST"), Ownable { contract SpaceshipToken is ERC721Token("CryptoSpaceships", "CST"), Ownable {
/// @dev Estructura que representa nuestra nave spacial // Estructura que representa nuestra nave spacial
struct Spaceship { struct Spaceship {
bytes metadataHash; // IPFS Hash bytes metadataHash; // IPFS Hash
uint8 energy; uint8 energy;
@ -23,8 +22,13 @@ contract SpaceshipToken is ERC721Token("CryptoSpaceships", "CST"), Ownable {
// Precio de las naves // Precio de las naves
mapping(uint => uint) public spaceshipPrices; mapping(uint => uint) public spaceshipPrices;
uint[] public shipsForSale; uint[] public shipsForSale;
mapping(uint => uint) indexes; // shipId => shipForSale mapping(uint => uint) public indexes; // shipId => shipForSale
/// @notice Crear un tocken
/// @param _metadataHash IPFS hash que contiene la metadata del token
/// @param _energy Atributo: Energia
/// @param _lasers Atributo: Lasers
/// @param _price Precio de venta del token
function mint(bytes _metadataHash, function mint(bytes _metadataHash,
uint8 _energy, uint8 _energy,
uint8 _lasers, uint8 _lasers,
@ -52,10 +56,14 @@ contract SpaceshipToken is ERC721Token("CryptoSpaceships", "CST"), Ownable {
_mint(address(this), spaceshipId); _mint(address(this), spaceshipId);
} }
/// @notice Obtener cantidad de naves a la venta
/// @return Cantidad
function shipsForSaleN() public view returns(uint) { function shipsForSaleN() public view returns(uint) {
return shipsForSale.length; return shipsForSale.length;
} }
/// @notice Comprar nave
/// @param _spaceshipId Id del token a comprar
function buySpaceship(uint _spaceshipId) public payable { function buySpaceship(uint _spaceshipId) public payable {
// Solo se pueden comprar las naves cuyo dueno sea el contrato // Solo se pueden comprar las naves cuyo dueno sea el contrato
require(ownerOf(_spaceshipId) == address(this)); require(ownerOf(_spaceshipId) == address(this));
@ -63,55 +71,57 @@ contract SpaceshipToken is ERC721Token("CryptoSpaceships", "CST"), Ownable {
// Se debe enviar al menos el precio de la nave // Se debe enviar al menos el precio de la nave
require(msg.value != 0); require(msg.value != 0);
// Transferimos la // Approvamos directamente para evitar tener que crear una transaccion extra
// Approbamos directamente para evitar tener que crear una transaccion extra // y luego enviamos la nave a quien origino la transaccion
tokenApprovals[_spaceshipId] = msg.sender; tokenApprovals[_spaceshipId] = msg.sender;
safeTransferFrom(address(this), msg.sender, _spaceshipId); safeTransferFrom(address(this), msg.sender, _spaceshipId);
// La eliminamos de la lista para venta // La eliminamos de la lista para venta
// Esto se ve un poco mas complicado de lo necesario,
// Pero es para borrar elementos del arreglo de forma eficiente
uint256 replacer = shipsForSale[shipsForSale.length - 1]; uint256 replacer = shipsForSale[shipsForSale.length - 1];
uint256 pos = indexes[_spaceshipId]; uint256 pos = indexes[_spaceshipId];
shipsForSale[pos] = replacer; shipsForSale[pos] = replacer;
indexes[replacer] = pos; indexes[replacer] = pos;
shipsForSale.length--; shipsForSale.length--;
// Reembolsamos el sobrante
uint refund = msg.value - spaceshipPrices[_spaceshipId]; uint refund = msg.value - spaceshipPrices[_spaceshipId];
if (refund > 0) if (refund > 0)
msg.sender.transfer(refund); msg.sender.transfer(refund);
} }
function withdrawBalance() external onlyOwner { /// @notice Retirar balance por compras hechas
function withdrawBalance() public onlyOwner {
owner.transfer(address(this).balance); owner.transfer(address(this).balance);
} }
function getAttributes(uint _spaceshipId) public view returns ( /// @notice Obtener metadata
uint8 energy, /// @param _spaceshipId Id del token
uint8 lasers, /// @return Direccion desde donde obtener la metadata
uint8 shield
){
Spaceship storage s = spaceships[_spaceshipId];
energy = s.energy;
lasers = s.lasers;
shield = s.shield;
}
// Obtain metadata
function tokenURI(uint256 _spaceshipId) public view returns (string) { function tokenURI(uint256 _spaceshipId) public view returns (string) {
Spaceship storage s = spaceships[_spaceshipId]; Spaceship storage s = spaceships[_spaceshipId];
return strConcat("https://ipfs.io/ipfs/", string(s.metadataHash)); return strConcat("https://ipfs.io/ipfs/", string(s.metadataHash));
} }
/// @notice Concatenar strings
/// @dev La concatenacion por strings por ahora debe hacerse manual o usando librerias
/// @param _a Primer string
/// @param _b Segundo string
/// @return String concatenado
function strConcat(string _a, string _b) private returns (string) { function strConcat(string _a, string _b) private returns (string) {
bytes memory _ba = bytes(_a); bytes memory _ba = bytes(_a);
bytes memory _bb = bytes(_b); bytes memory _bb = bytes(_b);
string memory ab = new string(_ba.length + _bb.length); string memory ab = new string(_ba.length + _bb.length);
bytes memory bab = bytes(ab); bytes memory bab = bytes(ab);
uint k = 0; uint k = 0;
for (uint i = 0; i < _ba.length; i++) bab[k++] = _ba[i];
for (i = 0; i < _bb.length; i++) bab[k++] = _bb[i]; for (uint i = 0; i < _ba.length; i++)
bab[k++] = _ba[i];
for (i = 0; i < _bb.length; i++)
bab[k++] = _bb[i];
return string(bab); return string(bab);
} }