A fixed-supply token with transfers and third-party allowances, deployed December 2016.
Context
Frontier and Homestead era deployment.
Token Information
Key Facts
Description
A fixed-supply token supporting transfers and third-party allowances. Deployed December 2016 by 0xce9ad44c906984381d8b099f76de034a8d04375c.
Source Verified
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Spurious Dragon Era
Continued DoS protection. State trie clearing.
Bytecode Overview
Verified Source Available
Source verified through compiler archaeology and exact bytecode matching.
View Verification ProofShow source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
pragma solidity ^0.4.0;
/*
* Token - is a smart contract interface
* for managing common functionality of
* a token.
*
* ERC.20 Token standard: https://github.com/eth ereum/EIPs/issues/20
*/
contract TokenInterface {
// total amount of tokens
uint totalSupply;
/**
*
* balanceOf() - constant function check concrete tokens balance
*
* @param owner - account owner
*
* @return the value of balance
*/
function balanceOf(address owner) constant returns (uint256 balance);
function transfer(address to, uint256 value) returns (bool success);
function transferFrom(address from, address to, uint256 value) returns (bool success);
/**
*
* approve() - function approves to a person to spend some tokens from
* owner balance.
*
* @param spender - person whom this right been granted.
* @param value - value to spend.
*
* @return true in case of succes, otherwise failure
*
*/
function approve(address spender, uint256 value) returns (bool success);
/**
*
* allowance() - constant function to check how much is
* permitted to spend to 3rd person from owner balance
*
* @param owner - owner of the balance
* @param spender - permitted to spend from this balance person
*
* @return - remaining right to spend
*
*/
function allowance(address owner, address spender) constant returns (uint256 remaining);
// events notifications
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
/*
* StandardToken - is a smart contract
* for managing common functionality of
* a token.
*
* ERC.20 Token standard:
* https://github.com/eth ereum/EIPs/issues/20
*/
contract StandardToken is TokenInterface {
// token ownership
mapping (address => uint256) balances;
// spending permision management
mapping (address => mapping (address => uint256)) allowed;
function StandardToken(){
}
/**
* transfer() - transfer tokens from msg.sender balance
* to requested account
*
* @param to - target address to transfer tokens
* @param value - ammount of tokens to transfer
*
* @return - success / failure of the transaction
*/
function transfer(address to, uint256 value) returns (bool success) {
if (balances[msg.sender] >= value && value > 0) {
// do actual tokens transfer
balances[msg.sender] -= value;
balances[to] += value;
// rise the Transfer event
Transfer(msg.sender, to, value);
return true;
} else {
return false;
}
}
/**
* transferFrom() -
*
* @param from -
* @param to -
* @param value -
*
* @return
*/
function transferFrom(address from, address to, uint256 value) returns (bool success) {
if ( balances[from] >= value &&
allowed[from][msg.sender] >= value &&
value > 0) {
// do the actual transfer
balances[from] -= value;
balances[to] =+ value;
// addjust the permision, after part of
// permited to spend value was used
allowed[from][msg.sender] -= value;
// rise the Transfer event
Transfer(from, to, value);
return true;
} else {
return false;
}
}
/**
*
* balanceOf() - constant function check concrete tokens balance
*
* @param owner - account owner
*
* @return the value of balance
*/
function balanceOf(address owner) constant returns (uint256 balance) {
return balances[owner];
}
/**
*
* approve() - function approves to a person to spend some tokens from
* owner balance.
*
* @param spender - person whom this right been granted.
* @param value - value to spend.
*
* @return true in case of succes, otherwise failure
*
*/
function approve(address spender, uint256 value) returns (bool success) {
// now spender can use balance in
// ammount of value from owner balance
allowed[msg.sender][spender] = value;
// rise event about the transaction
Approval(msg.sender, spender, value);
return true;
}
/**
*
* allowance() - constant function to check how mouch is
* permited to spend to 3rd person from owner balance
*
* @param owner - owner of the balance
* @param spender - permited to spend from this balance person
*
* @return - remaining right to spend
*
*/
function allowance(address owner, address spender) constant returns (uint256 remaining) {
return allowed[owner][spender];
}
}
/**
*
* @title Hacker Gold
*
* The official token powering the hack.ether.camp virtual accelerator.
* This is the only way to acquire tokens from startups during the event.
*
* Whitepaper https://hack.ether.camp/whitepaper
*
*/
contract HackerGold is StandardToken {
// Name of the token
string public name = "HackerGold";
// Decimal places
uint8 public decimals = 3;
// Token abbreviation
string public symbol = "HKG";
// 1 ether = 200 hkg
uint BASE_PRICE = 200;
// 1 ether = 150 hkg
uint MID_PRICE = 150;
// 1 ether = 100 hkg
uint FIN_PRICE = 100;
// Safety cap
uint SAFETY_LIMIT = 4000000 ether;
// Zeros after the point
uint DECIMAL_ZEROS = 1000;
// Total value in wei
uint totalValue;
// Address of multisig wallet holding ether from sale
address wallet;
// Structure of sale increase milestones
struct milestones_struct {
uint p1;
uint p2;
uint p3;
uint p4;
uint p5;
uint p6;
}
// Milestones instance
milestones_struct milestones;
/**
* Constructor of the contract.
*
* Passes address of the account holding the value.
* HackerGold contract itself does not hold any value
*
* @param multisig address of MultiSig wallet which will hold the value
*/
function HackerGold(address multisig) {
wallet = multisig;
// set time periods for sale
milestones = milestones_struct(
1476972000, // P1: GMT: 20-Oct-2016 14:00 => The Sale Starts
1478181600, // P2: GMT: 03-Nov-2016 14:00 => 1st Price Ladder
1479391200, // P3: GMT: 17-Nov-2016 14:00 => Price Stable,
// Hackathon Starts
1480600800, // P4: GMT: 01-Dec-2016 14:00 => 2nd Price Ladder
1481810400, // P5: GMT: 15-Dec-2016 14:00 => Price Stable
1482415200 // P6: GMT: 22-Dec-2016 14:00 => Sale Ends, Hackathon Ends
);
}
/**
* Fallback function: called on ether sent.
*
* It calls to createHKG function with msg.sender
* as a value for holder argument
*/
function () payable {
createHKG(msg.sender);
}
/**
* Creates HKG tokens.
*
* Runs sanity checks including safety cap
* Then calculates current price by getPrice() function, creates HKG tokens
* Finally sends a value of transaction to the wallet
*
* Note: due to lack of floating point types in Solidity,
* contract assumes that last 3 digits in tokens amount are stood after the point.
* It means that if stored HKG balance is 100000, then its real value is 100 HKG
*
* @param holder token holder
*/
function createHKG(address holder) payable {
if (now < milestones.p1) throw;
if (now >= milestones.p6) throw;
if (msg.value == 0) throw;
// safety cap
if (getTotalValue() + msg.value > SAFETY_LIMIT) throw;
uint tokens = msg.value * getPrice() * DECIMAL_ZEROS / 1 ether;
totalSupply += tokens;
balances[holder] += tokens;
totalValue += msg.value;
if (!wallet.send(msg.value)) throw;
}
/**
* Denotes complete price structure during the sale.
*
* @return HKG amount per 1 ETH for the current moment in time
*/
function getPrice() constant returns (uint result) {
if (now < milestones.p1) return 0;
if (now >= milestones.p1 && now < milestones.p2) {
return BASE_PRICE;
}
if (now >= milestones.p2 && now < milestones.p3) {
uint days_in = 1 + (now - milestones.p2) / 1 days;
return BASE_PRICE - days_in * 25 / 7; // daily decrease 3.5
}
if (now >= milestones.p3 && now < milestones.p4) {
return MID_PRICE;
}
if (now >= milestones.p4 && now < milestones.p5) {
days_in = 1 + (now - milestones.p4) / 1 days;
return MID_PRICE - days_in * 25 / 7; // daily decrease 3.5
}
if (now >= milestones.p5 && now < milestones.p6) {
return FIN_PRICE;
}
if (now >= milestones.p6){
return 0;
}
}
/**
* Returns total stored HKG amount.
*
* Contract assumes that last 3 digits of this value are behind the decimal place. i.e. 10001 is 10.001
* Thus, result of this function should be divided by 1000 to get HKG value
*
* @return result stored HKG amount
*/
function getTotalSupply() constant returns (uint result) {
return totalSupply;
}
/**
* It is used for test purposes.
*
* Returns the result of 'now' statement of Solidity language
*
* @return unix timestamp for current moment in time
*/
function getNow() constant returns (uint result) {
return now;
}
/**
* Returns total value passed through the contract
*
* @return result total value in wei
*/
function getTotalValue() constant returns (uint result) {
return totalValue;
}
}
/**
*
* EventInfo - imutable class that denotes
* the time of the virtual accelerator hack
* event
*
*/
contract EventInfo{
uint constant HACKATHON_5_WEEKS = 60 * 60 * 24 * 7 * 5;
uint constant T_1_WEEK = 60 * 60 * 24 * 7;
uint eventStart = 1479391200; // Thu, 17 Nov 2016 14:00:00 GMT
uint eventEnd = eventStart + HACKATHON_5_WEEKS;
/**
* getEventStart - return the start of the event time
*/
function getEventStart() constant returns (uint result){
return eventStart;
}
/**
* getEventEnd - return the end of the event time
*/
function getEventEnd() constant returns (uint result){
return eventEnd;
}
/**
* getVotingStart - the voting starts 1 week after the
* event starts
*/
function getVotingStart() constant returns (uint result){
return eventStart+ T_1_WEEK;
}
/**
* getTradingStart - the DST tokens trading starts 1 week
* after the event starts
*/
function getTradingStart() constant returns (uint result){
return eventStart+ T_1_WEEK;
}
/**
* getNow - helper class to check what time the contract see
*/
function getNow() constant returns (uint result){
return now;
}
}
/*
* DSTContract - DST stands for decentralized startup team.
* the contract ensures funding for a decentralized
* team in 2 phases:
*
* +. Funding by HKG during the hackathon event.
* +. Funding by Ether after the event is over.
*
* After the funds been collected there is a governence
* mechanism managed by proposition to withdraw funds
* for development usage.
*
* The DST ensures that backers of the projects keeps
* some influence on the project by ability to reject
* propositions they find as non effective.
*
* In very radical occasions the backers may loose
* the trust in the team completelly, in that case
* there is an option to propose impeachment process
* completelly removing the execute and assigning new
* person to manage the funds.
*
*/
contract DSTContract is StandardToken{
// Zeros after the point
uint DECIMAL_ZEROS = 1000;
// Proposal lifetime
uint PROPOSAL_LIFETIME = 10 days;
// Proposal funds threshold, in percents
uint PROPOSAL_FUNDS_TH = 20;
address executive;
EventInfo eventInfo;
// Indicated where the DST is traded
address virtualExchangeAddress;
HackerGold hackerGold;
mapping (address => uint256) votingRights;
// 1 - HKG => DST qty; tokens for 1 HKG
uint hkgPrice;
// 1 - Ether => DST qty; tokens for 1 Ether
uint etherPrice;
string public name = "...";
uint8 public decimals = 3;
string public symbol = "...";
bool ableToIssueTokens = true;
uint preferedQtySold;
uint collectedHKG;
uint collectedEther;
// Proposal of the funds spending
mapping (bytes32 => Proposal) proposals;
enum ProposalCurrency { HKG, ETHER }
ProposalCurrency enumDeclaration;
struct Proposal{
bytes32 id;
uint value;
string urlDetails;
uint votindEndTS;
uint votesObjecting;
address submitter;
bool redeemed;
ProposalCurrency proposalCurrency;
mapping (address => bool) voted;
}
uint counterProposals;
uint timeOfLastProposal;
Proposal[] listProposals;
/**
* Impeachment process proposals
*/
struct ImpeachmentProposal{
string urlDetails;
address newExecutive;
uint votindEndTS;
uint votesSupporting;
mapping (address => bool) voted;
}
ImpeachmentProposal lastImpeachmentProposal;
/**
*
* DSTContract: ctor for DST token and governence contract
*
* @param eventInfoAddr EventInfo: address of object denotes events
* milestones
* @param hackerGoldAddr HackerGold: address of HackerGold token
*
* @param dstName string: dstName: real name of the team
*
* @param dstSymbol string: 3 letter symbold of the team
*
*/
function DSTContract(EventInfo eventInfoAddr, HackerGold hackerGoldAddr, string dstName, string dstSymbol){
executive = msg.sender;
name = dstName;
symbol = dstSymbol;
hackerGold = HackerGold(hackerGoldAddr);
eventInfo = EventInfo(eventInfoAddr);
}
function() payable
onlyAfterEnd {
// there is tokens left from hackathon
if (etherPrice == 0) throw;
uint tokens = msg.value * etherPrice * DECIMAL_ZEROS / (1 ether);
// check if demand of tokens is
// overflow the supply
uint retEther = 0;
if (balances[this] < tokens) {
tokens = balances[this];
retEther = msg.value - tokens / etherPrice * (1 finney);
// return left ether
if (!msg.sender.send(retEther)) throw;
}
// do transfer
balances[msg.sender] += tokens;
balances[this] -= tokens;
// count collected ether
collectedEther += msg.value - retEther;
// rise event
BuyForEtherTransaction(msg.sender, collectedEther, totalSupply, etherPrice, tokens);
}
/**
* setHKGPrice - set price: 1HKG => DST tokens qty
*
* @param qtyForOneHKG uint: DST tokens for 1 HKG
*
*/
function setHKGPrice(uint qtyForOneHKG) onlyExecutive {
hkgPrice = qtyForOneHKG;
PriceHKGChange(qtyForOneHKG, preferedQtySold, totalSupply);
}
/**
*
* issuePreferedTokens - prefered tokens issued on the hackathon event
* grant special rights
*
* @param qtyForOneHKG uint: price DST tokens for one 1 HKG
* @param qtyToEmit uint: new supply of tokens
*
*/
function issuePreferedTokens(uint qtyForOneHKG,
uint qtyToEmit) onlyExecutive
onlyIfAbleToIssueTokens
onlyBeforeEnd
onlyAfterTradingStart {
// no issuence is allowed before enlisted on the
// exchange
if (virtualExchangeAddress == 0x0) throw;
totalSupply += qtyToEmit;
balances[this] += qtyToEmit;
hkgPrice = qtyForOneHKG;
// now spender can use balance in
// amount of value from owner balance
allowed[this][virtualExchangeAddress] += qtyToEmit;
// rise event about the transaction
Approval(this, virtualExchangeAddress, qtyToEmit);
// rise event
DstTokensIssued(hkgPrice, preferedQtySold, totalSupply, qtyToEmit);
}
/**
*
* buyForHackerGold - on the hack event this function is available
* the buyer for hacker gold will gain votes to
* influence future proposals on the DST
*
* @param hkgValue - qty of this DST tokens for 1 HKG
*
*/
function buyForHackerGold(uint hkgValue) onlyBeforeEnd
returns (bool success) {
// validate that the caller is official accelerator HKG Exchange
if (msg.sender != virtualExchangeAddress) throw;
// transfer token
address sender = tx.origin;
uint tokensQty = hkgValue * hkgPrice;
// gain voting rights
votingRights[sender] +=tokensQty;
preferedQtySold += tokensQty;
collectedHKG += hkgValue;
// do actual transfer
transferFrom(this,
virtualExchangeAddress, tokensQty);
transfer(sender, tokensQty);
// rise event
BuyForHKGTransaction(sender, preferedQtySold, totalSupply, hkgPrice, tokensQty);
return true;
}
/**
*
* issueTokens - function will issue tokens after the
* event, able to sell for 1 ether
*
* @param qtyForOneEther uint: DST tokens for 1 ETH
* @param qtyToEmit uint: new tokens supply
*
*/
function issueTokens(uint qtyForOneEther,
uint qtyToEmit) onlyAfterEnd
onlyExecutive
onlyIfAbleToIssueTokens {
balances[this] += qtyToEmit;
etherPrice = qtyForOneEther;
totalSupply += qtyToEmit;
// rise event
DstTokensIssued(qtyForOneEther, totalSupply, totalSupply, qtyToEmit);
}
/**
* setEtherPrice - change the token price
*
* @param qtyForOneEther uint: new price - DST tokens for 1 ETH
*/
function setEtherPrice(uint qtyForOneEther) onlyAfterEnd
onlyExecutive {
etherPrice = qtyForOneEther;
// rise event for this
NewEtherPrice(qtyForOneEther);
}
/**
* disableTokenIssuance - function will disable any
* option for future token
* issuence
*/
function disableTokenIssuance() onlyExecutive {
ableToIssueTokens = false;
DisableTokenIssuance();
}
/**
* burnRemainToken - eliminated all available for sale
* tokens.
*/
function burnRemainToken() onlyExecutive {
totalSupply -= balances[this];
balances[this] = 0;
// rise event for this
BurnedAllRemainedTokens();
}
/**
* submitEtherProposal: submit proposal to use part of the
* collected ether funds
*
* @param requestValue uint: value in wei
* @param url string: details of the proposal
*/
function submitEtherProposal(uint requestValue, string url) onlyAfterEnd
onlyExecutive returns (bytes32 resultId, bool resultSucces) {
// ensure there is no more issuence available
if (ableToIssueTokens) throw;
// ensure there is no more tokens available
if (balanceOf(this) > 0) throw;
// Possible to submit a proposal once 2 weeks
if (now < (timeOfLastProposal + 2 weeks)) throw;
uint percent = collectedEther / 100;
if (requestValue > PROPOSAL_FUNDS_TH * percent) throw;
// if remained value is less than requested gain all.
if (requestValue > this.balance)
requestValue = this.balance;
// set id of the proposal
// submit proposal to the map
bytes32 id = sha3(msg.data, now);
uint timeEnds = now + PROPOSAL_LIFETIME;
Proposal memory newProposal = Proposal(id, requestValue, url, timeEnds, 0, msg.sender, false, ProposalCurrency.ETHER);
proposals[id] = newProposal;
listProposals.push(newProposal);
timeOfLastProposal = now;
ProposalRequestSubmitted(id, requestValue, timeEnds, url, msg.sender);
return (id, true);
}
/**
*
* submitHKGProposal - submit proposal to request for
* partial HKG funds collected
*
* @param requestValue uint: value in HKG to request.
* @param url string: url with details on the proposition
*/
function submitHKGProposal(uint requestValue, string url) onlyAfterEnd
onlyExecutive returns (bytes32 resultId, bool resultSucces){
// If there is no 2 months over since the last event.
// There is no posible to get any HKG. After 2 months
// all the HKG is available.
if (now < (eventInfo.getEventEnd() + 8 weeks)) {
throw;
}
// Possible to submit a proposal once 2 weeks
if (now < (timeOfLastProposal + 2 weeks)) throw;
uint percent = preferedQtySold / 100;
// validate the amount is legit
// first 5 proposals should be less than 20%
if (counterProposals <= 5 &&
requestValue > PROPOSAL_FUNDS_TH * percent) throw;
// if remained value is less than requested
// gain all.
if (requestValue > getHKGOwned())
requestValue = getHKGOwned();
// set id of the proposal
// submit proposal to the map
bytes32 id = sha3(msg.data, now);
uint timeEnds = now + PROPOSAL_LIFETIME;
Proposal memory newProposal = Proposal(id, requestValue, url, timeEnds, 0, msg.sender, false, ProposalCurrency.HKG);
proposals[id] = newProposal;
listProposals.push(newProposal);
++counterProposals;
timeOfLastProposal = now;
ProposalRequestSubmitted(id, requestValue, timeEnds, url, msg.sender);
return (id, true);
}
/**
* objectProposal - object previously submitted proposal,
* the objection right is obtained by
* purchasing prefered tokens on time of
* the hackathon.
*
* @param id bytes32 : the id of the proposla to redeem
*/
function objectProposal(bytes32 id){
Proposal memory proposal = proposals[id];
// check proposal exist
if (proposals[id].id == 0) throw;
// check already redeemed
if (proposals[id].redeemed) throw;
// ensure objection time
if (now >= proposals[id].votindEndTS) throw;
// ensure not voted
if (proposals[id].voted[msg.sender]) throw;
// submit votes
uint votes = votingRights[msg.sender];
proposals[id].votesObjecting += votes;
// mark voted
proposals[id].voted[msg.sender] = true;
uint idx = getIndexByProposalId(id);
listProposals[idx] = proposals[id];
ObjectedVote(id, msg.sender, votes);
}
function getIndexByProposalId(bytes32 id) returns (uint result){
for (uint i = 0; i < listProposals.length; ++i){
if (id == listProposals[i].id) return i;
}
}
/**
* redeemProposalFunds - redeem funds requested by prior
* submitted proposal
*
* @param id bytes32: the id of the proposal to redeem
*/
function redeemProposalFunds(bytes32 id) onlyExecutive {
if (proposals[id].id == 0) throw;
if (proposals[id].submitter != msg.sender) throw;
// ensure objection time
if (now < proposals[id].votindEndTS) throw;
// check already redeemed
if (proposals[id].redeemed) throw;
// check votes objection => 55% of total votes
uint objectionThreshold = preferedQtySold / 100 * 55;
if (proposals[id].votesObjecting > objectionThreshold) throw;
if (proposals[id].proposalCurrency == ProposalCurrency.HKG){
// send hacker gold
hackerGold.transfer(proposals[id].submitter, proposals[id].value);
} else {
// send ether
bool success = proposals[id].submitter.send(proposals[id].value);
// rise event
EtherRedeemAccepted(proposals[id].submitter, proposals[id].value);
}
// execute the proposal
proposals[id].redeemed = true;
}
/**
* getAllTheFunds - to ensure there is no deadlock can
* can happen, and no case that voting
* structure will freeze the funds forever
* the startup will be able to get all the
* funds without a proposal required after
* 6 months.
*
*
*/
function getAllTheFunds() onlyExecutive {
// If there is a deadlock in voting participates
// the funds can be redeemed completelly in 6 months
if (now < (eventInfo.getEventEnd() + 24 weeks)) {
throw;
}
// all the Ether
bool success = msg.sender.send(this.balance);
// all the HKG
hackerGold.transfer(msg.sender, getHKGOwned());
}
/**
* submitImpeachmentProposal - submit request to switch
* executive.
*
* @param urlDetails - details of the impeachment proposal
* @param newExecutive - address of the new executive
*
*/
function submitImpeachmentProposal(string urlDetails, address newExecutive){
// to offer impeachment you should have
// voting rights
if (votingRights[msg.sender] == 0) throw;
// the submission of the first impeachment
// proposal is possible only after 3 months
// since the hackathon is over
if (now < (eventInfo.getEventEnd() + 12 weeks)) throw;
// check there is 1 months over since last one
if (lastImpeachmentProposal.votindEndTS != 0 &&
lastImpeachmentProposal.votindEndTS + 2 weeks > now) throw;
// submit impeachment proposal
// add the votes of the submitter
// to the proposal right away
lastImpeachmentProposal = ImpeachmentProposal(urlDetails, newExecutive, now + 2 weeks, votingRights[msg.sender]);
lastImpeachmentProposal.voted[msg.sender] = true;
// rise event
ImpeachmentProposed(msg.sender, urlDetails, now + 2 weeks, newExecutive);
}
/**
* supportImpeachment - vote for impeachment proposal
* that is currently in progress
*
*/
function supportImpeachment(){
// ensure that support is for exist proposal
if (lastImpeachmentProposal.newExecutive == 0x0) throw;
// to offer impeachment you should have
// voting rights
if (votingRights[msg.sender] == 0) throw;
// check if not voted already
if (lastImpeachmentProposal.voted[msg.sender]) throw;
// check if not finished the 2 weeks of voting
if (lastImpeachmentProposal.votindEndTS + 2 weeks <= now) throw;
// support the impeachment
lastImpeachmentProposal.voted[msg.sender] = true;
lastImpeachmentProposal.votesSupporting += votingRights[msg.sender];
// rise impeachment suppporting event
ImpeachmentSupport(msg.sender, votingRights[msg.sender]);
// if the vote is over 70% execute the switch
uint percent = preferedQtySold / 100;
if (lastImpeachmentProposal.votesSupporting >= 70 * percent){
executive = lastImpeachmentProposal.newExecutive;
// impeachment event
ImpeachmentAccepted(executive);
}
}
// **************************** //
// * Constant Getters * //
// **************************** //
function votingRightsOf(address _owner) constant returns (uint256 result) {
result = votingRights[_owner];
}
function getPreferedQtySold() constant returns (uint result){
return preferedQtySold;
}
function setVirtualExchange(address virtualExchangeAddr){
virtualExchangeAddress = virtualExchangeAddr;
}
function getHKGOwned() constant returns (uint result){
return hackerGold.balanceOf(this);
}
function getEtherValue() constant returns (uint result){
return this.balance;
}
function getExecutive() constant returns (address result){
return executive;
}
function getHKGPrice() constant returns (uint result){
return hkgPrice;
}
function getEtherPrice() constant returns (uint result){
return etherPrice;
}
function getDSTName() constant returns(string result){
return name;
}
function getDSTNameBytes() constant returns(bytes32 result){
return convert(name);
}
function getDSTSymbol() constant returns(string result){
return symbol;
}
function getDSTSymbolBytes() constant returns(bytes32 result){
return convert(symbol);
}
function getAddress() constant returns (address result) {
return this;
}
function getTotalSupply() constant returns (uint result) {
return totalSupply;
}
function getCollectedEther() constant returns (uint results) {
return collectedEther;
}
function getCounterProposals() constant returns (uint result){
return counterProposals;
}
function getProposalIdByIndex(uint i) constant returns (bytes32 result){
return listProposals[i].id;
}
function getProposalObjectionByIndex(uint i) constant returns (uint result){
return listProposals[i].votesObjecting;
}
function getProposalValueByIndex(uint i) constant returns (uint result){
return listProposals[i].value;
}
function getCurrentImpeachmentUrlDetails() constant returns (string result){
return lastImpeachmentProposal.urlDetails;
}
function getCurrentImpeachmentVotesSupporting() constant returns (uint result){
return lastImpeachmentProposal.votesSupporting;
}
function convert(string key) returns (bytes32 ret) {
if (bytes(key).length > 32) {
throw;
}
assembly {
ret := mload(add(key, 32))
}
}
// ********************* //
// * Modifiers * //
// ********************* //
modifier onlyBeforeEnd() { if (now >= eventInfo.getEventEnd()) throw; _; }
modifier onlyAfterEnd() { if (now < eventInfo.getEventEnd()) throw; _; }
modifier onlyAfterTradingStart() { if (now < eventInfo.getTradingStart()) throw; _; }
modifier onlyExecutive() { if (msg.sender != executive) throw; _; }
modifier onlyIfAbleToIssueTokens() { if (!ableToIssueTokens) throw; _; }
// ****************** //
// * Events * //
// ****************** //
event PriceHKGChange(uint indexed qtyForOneHKG, uint indexed tokensSold, uint indexed totalSupply);
event BuyForHKGTransaction(address indexed buyer, uint indexed tokensSold, uint indexed totalSupply, uint qtyForOneHKG, uint tokensAmount);
event BuyForEtherTransaction(address indexed buyer, uint indexed tokensSold, uint indexed totalSupply, uint qtyForOneEther, uint tokensAmount);
event DstTokensIssued(uint indexed qtyForOneHKG, uint indexed tokensSold, uint indexed totalSupply, uint qtyToEmit);
event ProposalRequestSubmitted(bytes32 id, uint value, uint timeEnds, string url, address sender);
event EtherRedeemAccepted(address sender, uint value);
event ObjectedVote(bytes32 id, address voter, uint votes);
event ImpeachmentProposed(address submitter, string urlDetails, uint votindEndTS, address newExecutive);
event ImpeachmentSupport(address supportter, uint votes);
event ImpeachmentAccepted(address newExecutive);
event NewEtherPrice(uint newQtyForOneEther);
event DisableTokenIssuance();
event BurnedAllRemainedTokens();
}
/**
* VirtualExchange - The exchange is a trading system used
* on hack.ether.camp hackathon event to
* support trading a DST tokens for HKG.
*
*/
contract VirtualExchange{
address owner;
EventInfo eventInfo;
mapping (bytes32 => address) dstListed;
HackerGold hackerGold;
function VirtualExchange(address hackerGoldAddr, address eventInfoAddr){
owner = msg.sender;
hackerGold = HackerGold(hackerGoldAddr);
eventInfo = EventInfo(eventInfoAddr);
}
/**
* enlist - enlisting one decentralized startup team to
* the hack event virtual exchange, making the
* DST initated tokens available for acquisition.
*
* @param dstAddress - address of the DSTContract
*
*/
function enlist(address dstAddress) onlyBeforeEnd {
DSTContract dstContract = DSTContract(dstAddress);
bytes32 symbolBytes = dstContract.getDSTSymbolBytes();
/* Don't enlist 2 with the same name */
if (isExistByBytes(symbolBytes)) throw;
// Only owner of the DST can deploy the DST
if (dstContract.getExecutive() != msg.sender) throw;
// All good enlist the company
dstListed[symbolBytes] = dstAddress;
// Indicate to DST which Virtual Exchange is enlisted
dstContract.setVirtualExchange(address(this));
// rise Enlisted event
Enlisted(dstAddress);
}
/**
*
* buy - on the hackathon timeframe that is the function
* that will be the way to buy specific tokens for
* startup.
*
* @param companyNameBytes - the company that is enlisted on the exchange
* and the tokens are available
*
* @param hkg - the ammount of hkg to spend for aquastion
*
*/
function buy(bytes32 companyNameBytes, uint hkg) onlyBeforeEnd
returns (bool success) {
// check DST exist
if (!isExistByBytes(companyNameBytes)) throw;
// validate availability
DSTContract dstContract = DSTContract(dstListed[companyNameBytes]);
uint tokensQty = hkg * dstContract.getHKGPrice();
address veAddress = address(this);
// ensure that there is HKG balance
uint valueHKGOwned = hackerGold.balanceOf(msg.sender);
if (valueHKGOwned < hkg) throw;
// ensure that there is HKG token allowed to be spend
uint valueAvailbeOnExchange = hackerGold.allowance(msg.sender, veAddress);
if (valueAvailbeOnExchange < hkg) throw;
// ensure there is DST tokens for sale
uint dstTokens = dstContract.allowance(dstContract, veAddress);
if (dstTokens < hkg * dstContract.getHKGPrice()) throw;
// Transfer HKG to Virtual Exchange account
hackerGold.transferFrom(msg.sender, veAddress, hkg);
// Transfer to dstCotract ownership
hackerGold.transfer(dstContract.getAddress(), hkg);
// Call DST to transfer tokens
dstContract.buyForHackerGold(hkg);
}
// **************************** //
// * Constant Getters * //
// **************************** //
function isExistByBytes(bytes32 companyNameBytes) constant returns (bool result) {
if (dstListed[companyNameBytes] == 0x0)
return false;
else
return true;
}
function getEventStart() constant eventInfoSet returns (uint result){
return eventInfo.getEventStart();
}
function getEventEnd() constant eventInfoSet returns (uint result){
return eventInfo.getEventEnd();
}
function getNow() constant returns (uint result){
return now;
}
// ********************* //
// * Modifiers * //
// ********************* //
modifier onlyOwner() { if (msg.sender != owner) throw; _; }
modifier eventInfoSet() { if (eventInfo == address(0)) throw; _; }
modifier onlyBeforeEnd() { if (now >= eventInfo.getEventEnd()) throw; _; }
modifier onlyAfterEnd() { if (now < eventInfo.getEventEnd()) throw; _; }
// ****************** //
// * Events * //
// ****************** //
event Enlisted(address indexed dstContract);
}External Links
Related contracts
DoriToken
Same eraA fixed-supply token with transfers and allowance spending, deployed November 2016.
0xdbd90d...c4cb16November 25, 2016"ITT Demo 0.3.6 - Live Chain"
Same eraA fixed-supply token with transfers and third-party allowances, deployed November 2016.
0xb9a357...c293e3November 28, 2016HumanStandartTokenTC
Same eraA fixed-supply token with transfers and third-party allowances, deployed November 2016.
0x7dd73b...715250November 28, 2016test
Same eraA token with transfers and third-party allowances, and an owner who can mint new units, deployed December 2016.
0x3cfb11...cd875bDecember 1, 2016Contract 0x27dcb6...cd45b1
Same eraA fixed-supply token with transfers and third-party allowances, deployed December 2016.
0x27dcb6...cd45b1December 9, 2016test34
Same eraA fixed-supply token with direct transfers only, deployed December 2016.
0xfecde2...94a819December 12, 2016