Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save computerphysicslab/93405f03880b7eb422013cdbbc3d493f to your computer and use it in GitHub Desktop.
Save computerphysicslab/93405f03880b7eb422013cdbbc3d493f to your computer and use it in GitHub Desktop.
/*
Watafan asset Smart Contract v1.0
developed by:
MarketPay.io , 2017
https://marketpay.io/
http://lnked.in/blockchain
*/
pragma solidity ^0.4.6;
contract Mortal {
address owner;
function Mortal() { owner = msg.sender; }
function kill() { if (msg.sender == owner) suicide(owner); }
// @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;
}
// @A generic error log
event Error(string error);
}
// @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 Mortal {
// **** 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) 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) 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) 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 {
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
function transfer(address _to, uint256 _amount) returns (bool success) {
// Preventing balance integer overflow at (2^256 - 1)
if (balances[msg.sender] >= _amount && balances[_to] + _amount > balances[_to]) {
balances[msg.sender] -= _amount;
balances[_to] += _amount;
Transfer(msg.sender, _to, _amount);
return true;
} else {
return false;
}
}
function transferFrom(address _from, address _to, uint256 _amount) returns (bool success) {
// Preventing balance integer overflow at (2^256 - 1)
if (balances[_from] >= _amount && allowed[_from][msg.sender] >= _amount && balances[_to] + _amount > balances[_to]) {
balances[_to] += _amount;
balances[_from] -= _amount;
allowed[_from][msg.sender] -= _amount;
Transfer(_from, _to, _amount);
return true;
} else {
return false;
}
}
function approve(address _spender, uint256 _amount) 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 Mortal {
// **** DATA
mapping (address => uint40) phoneNumbers;
mapping (uint40 => address) phoneNumbersInverse;
// **** METHODS
// User signs up, registering its mobile phone number
function signUp(uint40 phoneNumber) {
phoneNumbers[msg.sender] = phoneNumber;
phoneNumbersInverse[phoneNumber] = msg.sender;
SignUp(phoneNumber, msg.sender, timestamp()); // Event log
}
// Operator checks whether a given user has been registered
function hasSignedUp(uint40 phoneNumber) constant returns (bool signedUp) {
if (phoneNumbersInverse[phoneNumber] == address(0)) { // check if the address is not set
return (false);
} else {
return (true);
}
}
// **** EVENTS
// Triggered when a new user signs up from its DApp
event SignUp(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) returns (bool success) {
if (!hasSignedUp(toPhoneNumber)) {
return (false);
}
return transfer(phoneNumbersInverse[toPhoneNumber], amount);
}
function mobileTransferFrom(uint40 fromPhoneNumber, uint40 toPhoneNumber, uint256 amount) 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) 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
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;
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
}
mapping (uint256 => asst) assetsById;
mapping (address => uint256) firstAssetId; // Roots for the linked assets, by address
uint256 lastAssetId; // Last assetId
// **** METHODS
// Queries the asset, knowing the id
function getAssetById(uint256 assetId) constant returns (uint256 _assetId, uint256 _next, uint256 _prev, uint256 _timestampCreation, address _assetOwner, string _content, uint256 _sellPrice) {
return (assetsById[assetId].assetId, assetsById[assetId].next, assetsById[assetId].prev, assetsById[assetId].timestampCreation, assetsById[assetId].assetOwner, assetsById[assetId].content, assetsById[assetId].sellPrice);
}
// 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) 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 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 balance overflow
if (balances[msg.sender] + assetsById[assetId].sellPrice < balances[msg.sender]) {
Error('sendAssetTo: overflow on seller balance');
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 = msg.sender;
// 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;
}
function issueAsset(string content, uint256 sellPrice) returns (bool) {
// Check whether user is allowed to issue a new asset
if (msg.sender != owner ) {
Error('issueAsset: only SC owner is allowed to issue new assets');
return false;
}
// Find out next asset Id
uint256 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].content = content;
assetsById[nextAssetId].sellPrice = sellPrice;
// 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 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 the admin issues a new asset
event IssueAsset(uint256 nextAssetId, 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, string _content, uint256 _sellPrice) {
return (assetsById[assetId].assetId, assetsById[assetId].next, assetsById[assetId].prev, assetsById[assetId].timestampCreation, phoneNumbers[assetsById[assetId].assetOwner], assetsById[assetId].content, assetsById[assetId].sellPrice);
}
function mobileGetFirstAssetIdOwnedBy(uint40 assetOwnerPhoneNumber) constant returns (uint256 assetId) {
if (!hasSignedUp(assetOwnerPhoneNumber)) {
return (0);
}
return firstAssetId[phoneNumbersInverse[assetOwnerPhoneNumber]];
}
function mobileSendAssetTo(uint256 assetId, uint40 assetBuyerPhoneNumber) returns (bool) {
if (!hasSignedUp(assetBuyerPhoneNumber)) {
return (false);
}
return (sendAssetTo(assetId, phoneNumbersInverse[assetBuyerPhoneNumber]));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment