Last active
December 25, 2017 05:50
-
-
Save computerphysicslab/f362383f9d3fed26becba48b934bbcfc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Watafan asset Smart Contract v2.0 | |
developed by: | |
MarketPay.io , 2017 | |
https://marketpay.io/ | |
http://lnked.in/blockchain | |
v1.0 https://gist.github.com/computerphysicslab/93405f03880b7eb422013cdbbc3d493f | |
+ ERC-20 tokens | |
+ Mobile interface | |
+ Issuable assets and tradable with tokens | |
v2.0 https://gist.github.com/computerphysicslab/f362383f9d3fed26becba48b934bbcfc | |
+ onlyOwner modifier | |
+ Haltable | |
+ safeMath | |
+ Added tokenExchangeRate | |
+ onlyIssuer modifier | |
+ asset state machine | |
*/ | |
pragma solidity ^0.4.6; | |
/* | |
* @title Mortal | |
* | |
* Abstract contract that allows children to implement the functionality of killing the contract and other generic functions. | |
* | |
*/ | |
contract Mortal { | |
address owner; | |
// @notice Constructor sets owner | |
function Mortal() { owner = msg.sender; } | |
// @notice For debugging purposes when using solidity online browser | |
function whoAmI() constant returns (address) { | |
return msg.sender; | |
} | |
// @notice Get the current timestamp from last mined block | |
function timestamp() constant returns (uint256) { | |
return block.timestamp; | |
} | |
// **** EVENTS | |
// @notice A generic error log | |
event Error(string error); | |
// @notice Triggered when owner kills contract | |
event Kill(address killer, uint256 timestamp); | |
// **** MORE FUNCTIONS | |
// @notice To limit functions use to contract owner | |
modifier onlyOwner() { | |
if (msg.sender != owner) { | |
Error('Mortal: onlyOwner function called by user that is not owner'); | |
} else { | |
_; | |
} | |
} | |
// @notice To kill the contract | |
function kill() onlyOwner { | |
Kill(msg.sender, timestamp()); | |
suicide(owner); | |
} | |
} | |
/* | |
* @title Haltable | |
* | |
* Abstract contract that allows children to implement an emergency stop mechanism. | |
* | |
*/ | |
contract Haltable is Mortal { | |
bool public halted; | |
modifier stopInEmergency { | |
if (halted) { | |
Error('Haltable: stopInEmergency function called and contract is halted'); | |
} else { | |
_; | |
} | |
} | |
modifier onlyInEmergency { | |
if (!halted) { | |
Error('Haltable: onlyInEmergency function called and contract is not halted'); | |
} { | |
_; | |
} | |
} | |
// called by the owner on emergency, triggers stopped state | |
function halt() external onlyOwner { | |
halted = true; | |
} | |
// called by the owner on end of emergency, returns to normal state | |
function unhalt() external onlyOwner onlyInEmergency { | |
halted = false; | |
} | |
} | |
/* | |
* @title Safe unsigned int math | |
* | |
* Abstract contract that allows children to implement integer operations without overflow risk | |
* | |
*/ | |
contract SafeMath is Mortal { | |
// Preventing integer overflow at (2^256 - 1) | |
function safeMul(uint a, uint b) returns (uint) { | |
uint c = a * b; | |
if(a != 0 && c/a != b) { | |
Error('safeMul: overflow'); throw; | |
} | |
return c; | |
} | |
// Preventing unsigned integer underflow | |
function safeSub(uint a, uint b) returns (uint) { | |
if(b > a) { | |
Error('safeSub: overflow'); throw; | |
} | |
return a - b; | |
} | |
// Preventing integer overflow at (2^256 - 1) | |
function safeAdd(uint a, uint b) returns (uint) { | |
uint c = a + b; | |
if(c < a) { | |
Error('safeAdd: overflow'); throw; | |
} | |
return c; | |
} | |
} | |
/* | |
* @title Standard Token Contract | |
* | |
* ERC20-compliant tokens => https://github.com/ethereum/EIPs/issues/20 | |
* A token is a fungible virtual good that can be traded. | |
* ERC-20 Tokens comply to the standard described in the Ethereum ERC-20 proposal. | |
* Basic, standardized Token contract. Defines the functions to check token balances | |
* send tokens, send tokens on behalf of a 3rd party and the corresponding approval process. | |
* | |
*/ | |
contract TokenInterface is Haltable { | |
// **** DATA | |
mapping (address => uint256) balances; | |
mapping (address => mapping (address => uint256)) allowed; | |
uint256 public initialSupply; // Initial and total token supply | |
uint256 public totalSupply; | |
bool allocated = false; // True after defining token parameters and initial mint | |
// Public variables of the token, all used for display | |
// HumanStandardToken is a specialisation of ERC20 defining these parameters | |
string public name; | |
string public symbol; | |
uint8 public decimals; | |
string public standard = 'H0.1'; | |
// **** METHODS | |
// Get total amount of tokens, totalSupply is a public var actually | |
// function totalSupply() constant returns (uint256 totalSupply) {} | |
// Get the account balance of another account with address _owner | |
function balanceOf(address _owner) constant returns (uint256 balance); | |
// Send _amount amount of tokens to address _to | |
function transfer(address _to, uint256 _amount) stopInEmergency returns (bool success); | |
// Send _amount amount of tokens from address _from to address _to | |
// The transferFrom method is used for a withdraw workflow, allowing contracts to send | |
// tokens on your behalf, for example to "deposit" to a contract address and/or to charge | |
// fees in sub-currencies; the command should fail unless the _from account has | |
// deliberately authorized the sender of the message via some mechanism | |
function transferFrom(address _from, address _to, uint256 _amount) stopInEmergency returns (bool success); | |
// Allow _spender to withdraw from your account, multiple times, up to the _amount amount. | |
// If this function is called again it overwrites the current allowance with _amount. | |
function approve(address _spender, uint256 _amount) stopInEmergency returns (bool success); | |
// Returns the amount which _spender is still allowed to withdraw from _owner | |
function allowance(address _owner, address _spender) constant returns (uint256 remaining); | |
// **** EVENTS | |
// Triggered when tokens are transferred | |
event Transfer(address indexed _from, address indexed _to, uint256 _amount); | |
// Triggered whenever approve(address _spender, uint256 _amount) is called | |
event Approval(address indexed _owner, address indexed _spender, uint256 _amount); | |
} | |
contract Token is TokenInterface, SafeMath { | |
function balanceOf(address _owner) constant returns (uint256 balance) { | |
return balances[_owner]; | |
} | |
function transfer(address _to, uint256 _amount) stopInEmergency returns (bool success) { | |
if (balances[msg.sender] < _amount) { | |
Error('transfer: the amount to transfer is higher than your token balance'); | |
return false; | |
} | |
balances[msg.sender] = safeSub(balances[msg.sender], _amount); | |
balances[_to] = safeAdd(balances[_to], _amount); | |
Transfer(msg.sender, _to, _amount); | |
return true; | |
} | |
function transferFrom(address _from, address _to, uint256 _amount) stopInEmergency returns (bool success) { | |
if (balances[_from] < _amount) { | |
Error('transfer: the amount to transfer is higher than the token balance of the source'); | |
return false; | |
} | |
if (allowed[_from][msg.sender] < _amount) { | |
Error('transfer: the amount to transfer is higher than the maximum token transfer allowed by the source'); | |
return false; | |
} | |
balances[_from] = safeSub(balances[_from], _amount); | |
balances[_to] = safeAdd(balances[_to], _amount); | |
allowed[_from][msg.sender] = safeSub(allowed[_from][msg.sender], _amount); | |
Transfer(_from, _to, _amount); | |
return true; | |
} | |
function approve(address _spender, uint256 _amount) stopInEmergency returns (bool success) { | |
allowed[msg.sender][_spender] = _amount; | |
Approval(msg.sender, _spender, _amount); | |
return true; | |
} | |
function allowance(address _owner, address _spender) constant returns (uint256 remaining) { | |
return allowed[_owner][_spender]; | |
} | |
// Constructor: set up token properties and owner token balance | |
function Token() { | |
// This is the constructor, so owner should be equal to msg.sender, and this method should be called just once | |
// make sure owner address is configured | |
// if(owner == 0x0) throw; | |
// owner address can call this function | |
// if (msg.sender != owner ) throw; | |
// call this function just once | |
// if (allocated) throw; | |
initialSupply = 1000000000; | |
totalSupply = initialSupply; | |
name = "Watafan"; | |
symbol = "FAN"; | |
decimals = 0; | |
balances[owner] = totalSupply; | |
Transfer(this, owner, totalSupply); | |
allocated = true; | |
} | |
} | |
contract Mobile is Haltable { | |
// **** DATA | |
mapping (address => uint40) phoneNumbers; | |
mapping (uint40 => address) phoneNumbersInverse; | |
mapping (uint40 => bool) issuers; | |
// **** METHODS | |
// User signs up, registering its mobile phone number | |
function signUp(uint40 phoneNumber) stopInEmergency { | |
phoneNumbers[msg.sender] = phoneNumber; | |
phoneNumbersInverse[phoneNumber] = msg.sender; | |
issuers[phoneNumber] = false; | |
SignUp(phoneNumber, msg.sender, timestamp()); // Event log | |
} | |
// Operator checks whether a given user has been registered | |
function hasSignedUp(uint40 phoneNumber) constant returns (bool) { | |
if (phoneNumbersInverse[phoneNumber] == address(0)) { // check if the address is not set | |
return (false); | |
} else { | |
return (true); | |
} | |
} | |
// Checks whether a given user is an authorized issuer | |
function isIssuer(uint40 phoneNumber) constant returns (bool) { | |
return (issuers[phoneNumber]); | |
} | |
// To limit issue functions just to authorized issuers | |
modifier onlyIssuer() { | |
if (!issuers[phoneNumbers[msg.sender]]) { | |
Error('Mobile: onlyIssuer function called by user that is not an authorized issuer'); | |
} else { | |
_; | |
} | |
} | |
function grantIssuer(uint40 phoneNumber) external onlyOwner { | |
issuers[phoneNumber] = true; | |
GrantIssuer(phoneNumber, phoneNumbersInverse[phoneNumber], timestamp()); // Event log | |
} | |
// **** EVENTS | |
// Triggered when a new user signs up from its DApp | |
event SignUp(uint40 phoneNumber, address who, uint256 timestamp); | |
// Triggered when a user is granted to become an issuer | |
event GrantIssuer(uint40 phoneNumber, address who, uint256 timestamp); | |
} | |
contract MobileToken is Token, Mobile { | |
function mobileBalanceOf(uint40 phoneNumber) constant returns (uint256 balance) { | |
if (!hasSignedUp(phoneNumber)) { | |
return (0); | |
} | |
return balances[phoneNumbersInverse[phoneNumber]]; | |
} | |
function mobileTransfer(uint40 toPhoneNumber, uint256 amount) stopInEmergency returns (bool success) { | |
if (!hasSignedUp(toPhoneNumber)) { | |
return (false); | |
} | |
return transfer(phoneNumbersInverse[toPhoneNumber], amount); | |
} | |
function mobileTransferFrom(uint40 fromPhoneNumber, uint40 toPhoneNumber, uint256 amount) stopInEmergency returns (bool success) { | |
if (!hasSignedUp(fromPhoneNumber)) { | |
return (false); | |
} | |
if (!hasSignedUp(toPhoneNumber)) { | |
return (false); | |
} | |
return transferFrom(phoneNumbersInverse[fromPhoneNumber], phoneNumbersInverse[toPhoneNumber], amount); | |
} | |
function mobileApprove(uint40 spenderPhoneNumber, uint256 amount) stopInEmergency returns (bool success) { | |
if (!hasSignedUp(spenderPhoneNumber)) { | |
return (false); | |
} | |
return approve(phoneNumbersInverse[spenderPhoneNumber], amount); | |
} | |
function mobileAllowance(uint40 ownerPhoneNumber, uint40 spenderPhoneNumber) constant returns (uint256 remaining) { | |
if (!hasSignedUp(ownerPhoneNumber)) { | |
return (0); | |
} | |
if (!hasSignedUp(spenderPhoneNumber)) { | |
return (0); | |
} | |
return allowance(phoneNumbersInverse[ownerPhoneNumber], phoneNumbersInverse[spenderPhoneNumber]); | |
} | |
} | |
contract Asset is Token { | |
// **** DATA | |
/** Asset states | |
* | |
* - Released: Once issued the asset stays as released until sent for free to someone specified by issuer | |
* - ForSale: The asset belongs to a user and is open to be sold | |
* - Unfungible: The asset cannot be sold, remaining to the user it belongs to. | |
*/ | |
enum assetStatus { Released, ForSale, Unfungible } | |
// https://ethereum.stackexchange.com/questions/1807/enums-in-solidity | |
struct asst { | |
uint256 assetId; | |
uint256 next; // pointer to link assets by owner, 0 if ain't next | |
uint256 prev; // pointer to link assets by owner, 0 if ain't prev | |
uint256 timestampCreation; | |
address assetOwner; | |
address issuer; | |
string content; // a JSON object containing the image data of the asset and its title | |
uint256 sellPrice; // in Watafan tokens, how many of them for this asset | |
assetStatus status; // behaviour (tradability) of the asset depends upon its status | |
} | |
mapping (uint256 => asst) assetsById; | |
mapping (address => uint256) firstAssetId; // Roots for the linked assets, by address | |
uint256 lastAssetId; // Last assetId | |
uint256 public tokenExchangeRate; // 1,000 means 1 euro per token, 500 means .5 euros per token | |
// Constructor: set up token properties and owner token balance | |
function Asset() { | |
// This is the constructor, so owner should be equal to msg.sender, and this method should be called just once | |
setTokenExchangeRate(1000); // By default sets token exchange rate to 1 euro per token | |
} | |
// **** METHODS | |
// Sets the token exchange rate as thousandths of euros per token | |
function setTokenExchangeRate(uint256 ratio) onlyOwner stopInEmergency { | |
tokenExchangeRate = ratio; | |
} | |
// Queries the asset, knowing the id | |
function getAssetById(uint256 assetId) constant returns (uint256 _assetId, uint256 _next, uint256 _prev, uint256 _timestampCreation, address _assetOwner, address _issuer) { | |
return (assetsById[assetId].assetId, assetsById[assetId].next, assetsById[assetId].prev, assetsById[assetId].timestampCreation, assetsById[assetId].assetOwner, assetsById[assetId].issuer); | |
} | |
// Additional outputs | |
function getAssetById2(uint256 assetId) constant returns (string _content, uint256 _sellPrice, uint256 _status) { | |
return (assetsById[assetId].content, assetsById[assetId].sellPrice, uint256(assetsById[assetId].status)); | |
} | |
/* | |
function getAssetStructById(uint256 assetId) constant returns (asst _asset) { | |
return (assetsById[assetId]); | |
} | |
*/ | |
// Queries the first asset a user owns | |
function getFirstAssetIdOwnedBy(address assetOwner) constant returns (uint256 assetId) { | |
return firstAssetId[assetOwner]; | |
} | |
// Seller sends an owned asset to a buyer, providing its allowance matches token price and transfer the tokens from buyer | |
function sendAssetTo(uint256 assetId, address assetBuyer) stopInEmergency returns (bool) { | |
// assetId must not be zero | |
if (assetId == 0) { | |
Error('sendAssetTo: assetId must not be zero'); | |
return false; | |
} | |
// Check whether the asset belongs to the seller | |
if (assetsById[assetId].assetOwner != msg.sender) { | |
Error('sendAssetTo: the asset does not belong to you, the seller'); | |
return false; | |
} | |
if (assetsById[assetId].sellPrice > 0) { // for non-null token paid transactions | |
// Check whether there is balance enough from the buyer to get its tokens | |
if (balances[assetBuyer] < assetsById[assetId].sellPrice) { | |
Error('sendAssetTo: there is not enough balance from the buyer to get its tokens'); | |
return false; | |
} | |
// Check whether there is allowance enough from the buyer to get its tokens | |
if (allowance(assetBuyer, msg.sender) < assetsById[assetId].sellPrice) { | |
Error('sendAssetTo: there is not enough allowance from the buyer to get its tokens'); | |
return false; | |
} | |
// Get the buyer tokens | |
if (!transferFrom(assetBuyer, msg.sender, assetsById[assetId].sellPrice)) { | |
Error('sendAssetTo: transferFrom failed'); // This shouldn't happen ever, but just in case... | |
return false; | |
} | |
} | |
// Transfer the asset to the buyer | |
assetsById[assetId].assetOwner = assetBuyer; | |
// Rebuild asset linkage for seller, msg.sender, removes the asset | |
if (firstAssetId[msg.sender] == assetId) { // seller root update | |
firstAssetId[msg.sender] = assetsById[assetId].next; | |
} else { | |
assetsById[assetsById[assetId].prev].next = assetsById[assetId].next; // update previous seller asset link | |
if (assetsById[assetId].next > 0) { | |
assetsById[assetsById[assetId].next].prev = assetsById[assetId].prev; // update next seller asset link | |
} | |
} | |
// Rebuild asset linkage for buyer, assetBuyer, adds the asset, and updates asset links and properties | |
if (firstAssetId[assetBuyer] > 0) { | |
assetsById[firstAssetId[assetBuyer]].prev = assetId; // update next buyer asset link | |
} | |
assetsById[assetId].next = firstAssetId[assetBuyer]; | |
firstAssetId[assetBuyer] = assetId; // bought asset becomes first in the buyer linkage | |
assetsById[assetId].prev = 0; | |
assetsById[assetId].assetOwner = assetBuyer; | |
// Event log | |
SendAssetTo(assetId, assetBuyer, timestamp()); | |
return true; | |
} | |
// Buyer gets an asset providing it is in ForSale status, and pays the corresponding tokens to the seller/owner. amount must match assetPrice to have a deal. | |
function buyAsset(uint256 assetId, uint256 amount) stopInEmergency returns (bool) { | |
// assetId must not be zero | |
if (assetId == 0) { | |
Error('buyAsset: assetId must not be zero'); | |
return false; | |
} | |
// Check whether the asset is in ForSale status | |
if (assetsById[assetId].status != assetStatus.ForSale) { | |
Error('buyAsset: the asset is not for sale'); | |
return false; | |
} | |
// Check whether the asset price is the same as amount | |
if (assetsById[assetId].sellPrice != amount) { | |
Error('buyAsset: the asset price does not match the specified amount'); | |
return false; | |
} | |
if (assetsById[assetId].sellPrice > 0) { // for non-null token paid transactions | |
// Check whether there is balance enough from the buyer to pay the asset | |
if (balances[msg.sender] < assetsById[assetId].sellPrice) { | |
Error('buyAsset: there is not enough token balance to buy this asset'); | |
return false; | |
} | |
// Send the buyer's tokens to the seller | |
if (!transfer(assetsById[assetId].assetOwner, assetsById[assetId].sellPrice)) { | |
Error('buyAsset: transfer failed'); // This shouldn't happen ever, but just in case... | |
return false; | |
} | |
} | |
address assetSeller = assetsById[assetId].assetOwner; | |
// Transfer the asset to the buyer | |
assetsById[assetId].assetOwner = msg.sender; | |
// Set the asset status to Unfungible | |
assetsById[assetId].status = assetStatus.Unfungible; | |
// Rebuild asset linkage for seller, assetSeller, removes the asset | |
if (firstAssetId[assetSeller] == assetId) { // seller root update | |
firstAssetId[assetSeller] = assetsById[assetId].next; | |
} else { | |
assetsById[assetsById[assetId].prev].next = assetsById[assetId].next; // update previous seller asset link | |
if (assetsById[assetId].next > 0) { | |
assetsById[assetsById[assetId].next].prev = assetsById[assetId].prev; // update next seller asset link | |
} | |
} | |
// Rebuild asset linkage for buyer, msg.sender, adds the asset, and updates asset links and properties | |
if (firstAssetId[msg.sender] > 0) { | |
assetsById[firstAssetId[msg.sender]].prev = assetId; // update next buyer asset link | |
} | |
assetsById[assetId].next = firstAssetId[msg.sender]; | |
firstAssetId[msg.sender] = assetId; // bought asset becomes first in the buyer linkage | |
assetsById[assetId].prev = 0; | |
assetsById[assetId].assetOwner = msg.sender; | |
// Event log | |
BuyAsset(assetId, amount, timestamp()); | |
return true; | |
} | |
// To be called by mobile interface and properly authorized issuers | |
function issueAsset(string content, uint256 sellPrice) stopInEmergency internal returns (uint256 nextAssetId) { | |
// Check whether user is allowed to issue a new asset | |
// Deprecated: user authentication is now performed on the mobile interface, checking user is an issuer | |
// if (msg.sender != owner ) { | |
// Error('issueAsset: only SC owner is allowed to issue new assets'); | |
// return 0; | |
// } | |
// Find out next asset Id | |
nextAssetId = lastAssetId + 1; | |
assetsById[nextAssetId].assetId = nextAssetId; | |
assetsById[nextAssetId].next = firstAssetId[msg.sender]; | |
assetsById[nextAssetId].prev = 0; | |
assetsById[nextAssetId].timestampCreation = timestamp(); | |
assetsById[nextAssetId].assetOwner = msg.sender; | |
assetsById[nextAssetId].issuer = msg.sender; | |
assetsById[nextAssetId].content = content; | |
assetsById[nextAssetId].sellPrice = sellPrice; | |
assetsById[nextAssetId].status = assetStatus.Released; | |
// Update linkage | |
firstAssetId[msg.sender] = nextAssetId; // new asset becomes first in the issuer linkage | |
if (assetsById[nextAssetId].next > 0) { | |
assetsById[assetsById[nextAssetId].next].prev = nextAssetId; | |
} | |
// Update lastAssetId | |
lastAssetId++; | |
// Event log | |
IssueAsset(nextAssetId, msg.sender, sellPrice, timestamp()); | |
return nextAssetId; | |
} | |
// Seller can block tradability of its assets | |
function setAssetUnfungible(uint256 assetId) returns (bool) { | |
// assetId must not be zero | |
if (assetId == 0) { | |
Error('setAssetUnfungible: assetId must not be zero'); | |
return false; | |
} | |
// Check whether the asset belongs to the caller | |
if (assetsById[assetId].assetOwner != msg.sender) { | |
Error('setAssetUnfungible: only owners of the asset are allowed to update its status'); | |
return false; | |
} | |
assetsById[assetId].status = assetStatus.Unfungible; | |
// Event log | |
SetAssetUnfungible(assetId, msg.sender, timestamp()); | |
return true; | |
} | |
// Seller updates the price of its assets and its status to ForSale | |
function setAssetPrice(uint256 assetId, uint256 sellPrice) returns (bool) { | |
// assetId must not be zero | |
if (assetId == 0) { | |
Error('setAssetPrice: assetId must not be zero'); | |
return false; | |
} | |
// Check whether the asset belongs to the caller | |
if (assetsById[assetId].assetOwner != msg.sender) { | |
Error('setAssetPrice: only owners of the asset are allowed to set its price and update its status'); | |
return false; | |
} | |
assetsById[assetId].sellPrice = sellPrice; | |
assetsById[assetId].status = assetStatus.ForSale; | |
// Event log | |
SetAssetPrice(assetId, msg.sender, sellPrice, timestamp()); | |
return true; | |
} | |
// **** EVENTS | |
// Triggered when a seller sends its asset to a buyer and receives the corresponding tokens | |
event SendAssetTo(uint256 assetId, address assetBuyer, uint256 timestamp); | |
// Triggered when a buyer sends its tokens to a seller and receives the specified asset | |
event BuyAsset(uint256 assetId, uint256 amount, uint256 timestamp); | |
// Triggered when the admin issues a new asset | |
event IssueAsset(uint256 nextAssetId, address assetOwner, uint256 sellPrice, uint256 timestamp); | |
// Triggered when the user updates its asset status to Unfungible | |
event SetAssetUnfungible(uint256 assetId, address assetOwner, uint256 timestamp); | |
// Triggered when the user updates its asset price and status to ForSale | |
event SetAssetPrice(uint256 assetId, address assetOwner, uint256 sellPrice, uint256 timestamp); | |
} | |
contract MobileAsset is Asset, MobileToken { | |
function mobileGetAssetById(uint256 assetId) constant returns (uint256 _assetId, uint256 _next, uint256 _prev, uint256 _timestampCreation, uint40 _assetOwnerPhoneNumber, uint40 _assetIssuerPhoneNumber) { | |
address assetOwner = assetsById[assetId].assetOwner; | |
address assetIssuer = assetsById[assetId].issuer; | |
return (assetsById[assetId].assetId, assetsById[assetId].next, assetsById[assetId].prev, assetsById[assetId].timestampCreation, phoneNumbers[assetOwner], phoneNumbers[assetIssuer]); | |
} | |
function mobileGetAssetById2(uint256 assetId) constant returns (string _content, uint256 _sellPrice, uint256 _status) { | |
return (assetsById[assetId].content, assetsById[assetId].sellPrice, uint256(assetsById[assetId].status)); | |
} | |
function mobileGetFirstAssetIdOwnedBy(uint40 assetOwnerPhoneNumber) constant returns (uint256 assetId) { | |
if (!hasSignedUp(assetOwnerPhoneNumber)) { | |
Error('mobileGetFirstAssetIdOwnedBy: specified asset owner is not signed up'); | |
return (0); | |
} | |
return firstAssetId[phoneNumbersInverse[assetOwnerPhoneNumber]]; | |
} | |
function mobileSendAssetTo(uint256 assetId, uint40 assetBuyerPhoneNumber) stopInEmergency returns (bool) { | |
if (!hasSignedUp(assetBuyerPhoneNumber)) { | |
Error('mobileSendAssetTo: asset recipient is not signed up'); | |
return (false); | |
} | |
return (sendAssetTo(assetId, phoneNumbersInverse[assetBuyerPhoneNumber])); | |
} | |
// Force issuer to check its mobile identity as authorized issuer | |
// Deprecated: Now the only way to issue an asset is by offering it as a gift | |
// function mobileIssueAsset(string content, uint256 sellPrice) stopInEmergency onlyIssuer returns (uint256 nextAssetId) { | |
// return (issueAsset(content, sellPrice)); | |
// } | |
// Issuer sends a new free asset to a given user as a gift | |
function mobileIssueAssetTo(string content, uint40 phoneNumberTo) stopInEmergency onlyIssuer returns (bool) { | |
if (!hasSignedUp(phoneNumberTo)) { | |
Error('mobileIssueAssetTo: asset recipient is not signed up'); | |
return (false); | |
} | |
uint256 assetId = issueAsset(content, 0); // 0 tokens, as a gift | |
if (assetId == 0) { | |
Error('mobileIssueAssetTo: asset has not been properly issued'); | |
return (false); | |
} | |
// The brand new asset is inmediatly sent to the recipient | |
return(mobileSendAssetTo(assetId, phoneNumberTo)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment