Created
June 10, 2018 15:51
-
-
Save lychees/c22a8be7b5aaa9c4265c9884cac6c1d7 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
/** | |
* LinkIdol Contract, copyright is owned by Andoromeda Foundation | |
* @author: Frank Wei <frank@frankwei.xyz> | |
* Last updated: 12:00 AM, May 30th | |
* Test Net Contract Address: n1oecF9SK8wUKxAcTVCYfvsvG3P6TmHWdzW | |
* @version: 0.9 beta - need to find the potential bug | |
*/ | |
"use strict" | |
class Operator { | |
constructor(obj) { | |
this.operator = {} | |
this.parse(obj) | |
} | |
toString() { | |
return JSON.stringify(this.operator) | |
} | |
parse(obj) { | |
if (typeof obj != "undefined") { | |
var data = JSON.parse(obj) | |
for (var key in data) { | |
this.operator[key] = data[key] | |
} | |
} | |
} | |
get(key) { | |
return this.operator[key] | |
} | |
set(key, value) { | |
this.operator[key] = value | |
} | |
} | |
class StandardNRC721Token { | |
constructor() { | |
// Contract Need to store on-chain data in LocalContractStorage | |
LocalContractStorage.defineProperties(this, { | |
_name: null, | |
}) | |
LocalContractStorage.defineMapProperties(this, { | |
"tokenOwner": null, | |
"ownedTokensCount": { | |
parse(value) { | |
return new BigNumber(value) | |
}, | |
stringify(o) { | |
return o.toString(10) | |
} | |
}, | |
"tokenApprovals": null, | |
"tokenToChara": null, | |
"operatorApprovals": { | |
parse(value) { | |
return new Operator(value) | |
}, | |
stringify(o) { | |
return o.toString() | |
} | |
}, | |
}) | |
} | |
init(name) { | |
this._name = name | |
} | |
name() { | |
return this._name | |
} | |
balanceOf(_owner) { | |
var balance = this.ownedTokensCount.get(_owner) | |
if (balance instanceof BigNumber) { | |
return balance.toString(10) | |
} else { | |
return "0" | |
} | |
} | |
ownerOf(_tokenId) { | |
return this.tokenOwner.get(_tokenId) | |
} | |
approve(_to, _tokenId) { | |
var from = Blockchain.transaction.from | |
var owner = this.ownerOf(_tokenId) | |
if (_to == owner) { | |
throw new Error("invalid address in approve.") | |
} | |
// msg.sender == owner || isApprovedForAll(owner, msg.sender) | |
if (owner == from || this.isApprovedForAll(owner, from)) { | |
this.tokenApprovals.set(_tokenId, _to) | |
this.approveEvent(true, owner, _to, _tokenId) | |
} else { | |
throw new Error("permission denied in approve.") | |
} | |
} | |
getApproved(_tokenId) { | |
return this.tokenApprovals.get(_tokenId) | |
} | |
setApprovalForAll(_to, _approved) { | |
var from = Blockchain.transaction.from | |
if (from == _to) { | |
throw new Error("invalid address in setApprovalForAll.") | |
} | |
var operator = this.operatorApprovals.get(from) || new Operator() | |
operator.set(_to, _approved) | |
this.operatorApprovals.set(from, operator) | |
} | |
isApprovedForAll(_owner, _operator) { | |
var operator = this.operatorApprovals.get(_owner) | |
if (operator != null) { | |
if (operator.get(_operator) === "true") { | |
return true | |
} else { | |
return false | |
} | |
} | |
} | |
isApprovedOrOwner(_spender, _tokenId) { | |
var owner = this.ownerOf(_tokenId) | |
return _spender == owner || this.getApproved(_tokenId) == _spender || this.isApprovedForAll(owner, _spender) | |
} | |
rejectIfNotApprovedOrOwner(_tokenId) { | |
var from = Blockchain.transaction.from | |
if (!this.isApprovedOrOwner(from, _tokenId)) { | |
throw new Error("permission denied in transferFrom.") | |
} | |
} | |
transferFrom(_from, _to, _tokenId) { | |
var from = Blockchain.transaction.from | |
if (this.isApprovedOrOwner(from, _tokenId)) { | |
this.clearApproval(_from, _tokenId) | |
this.removeTokenFrom(_from, _tokenId) | |
this._addTokenTo(_to, _tokenId) | |
this.transferEvent(true, _from, _to, _tokenId) | |
} else { | |
throw new Error("permission denied in transferFrom.") | |
} | |
} | |
clearApproval(_owner, _tokenId) { | |
var owner = this.ownerOf(_tokenId) | |
if (_owner != owner) { | |
throw new Error("permission denied in clearApproval.") | |
} | |
this.tokenApprovals.del(_tokenId) | |
} | |
removeTokenFrom(_from, _tokenId) { | |
if (_from != this.ownerOf(_tokenId)) { | |
throw new Error("permission denied in removeTokenFrom.") | |
} | |
var tokenCount = this.ownedTokensCount.get(_from) | |
if (tokenCount.lt(1)) { | |
throw new Error("Insufficient account balance in removeTokenFrom.") | |
} | |
this.tokenOwner.delete(_tokenId) | |
this.ownedTokensCount.set(_from, tokenCount - 1) | |
} | |
// These function can be directly called without underscore in the first letter | |
_addTokenTo(_to, _tokenId) { | |
this.tokenOwner.set(_tokenId, _to) | |
var tokenCount = this.ownedTokensCount.get(_to) || new BigNumber(0) | |
this.ownedTokensCount.set(_to, tokenCount + 1) | |
} | |
_mint(_to, _tokenId) { | |
this._addTokenTo(_to, _tokenId) | |
this.transferEvent(true, "", _to, _tokenId) | |
} | |
_burn(_owner, _tokenId) { | |
this.clearApproval(_owner, _tokenId) | |
this.removeTokenFrom(_owner, _tokenId) | |
this.transferEvent(true, _owner, "", _tokenId) | |
} | |
transferEvent(status, _from, _to, _tokenId) { | |
Event.Trigger(this.name(), { | |
Status: status, | |
Transfer: { | |
from: _from, | |
to: _to, | |
tokenId: _tokenId | |
} | |
}) | |
} | |
approveEvent(status, _owner, _spender, _tokenId) { | |
Event.Trigger(this.name(), { | |
Status: status, | |
Approve: { | |
owner: _owner, | |
spender: _spender, | |
tokenId: _tokenId | |
} | |
}) | |
} | |
} | |
class LinkIdolToken extends StandardNRC721Token { | |
constructor() { | |
super() | |
LocalContractStorage.defineProperties(this, { | |
_length: null, | |
girlsList: null, | |
// Changed `totalQty` before deploy!!! | |
totalQty: null | |
}) | |
LocalContractStorage.defineMapProperties(this, { | |
"admins": null | |
}) | |
} | |
init(name, symbol, initialGirlsList) { | |
super.init(name, symbol) | |
this._length = 0 | |
this.totalQty = 10000 | |
this.girlsList = initialGirlsList | |
} | |
_issue(_to, _girlId) { | |
var tokenId = this._length | |
if (this.isSoldOut()) { | |
throw new Error("Sorry, the card pool is empty now.") | |
} else { | |
this._mint(_to, tokenId) | |
this.tokenToChara.set(tokenId, _girlId) | |
this.totalQty -= 1; | |
this._length += 1; | |
return tokenId | |
} | |
} | |
isSoldOut() { | |
return this.totalQty <= 0 | |
} | |
getCardsLeft() { | |
return this.totalQty; | |
} | |
getCardIdByTokenId(_tokenId) { | |
return this.tokenToChara.get(_tokenId) | |
} | |
getCardNameByTokenId(_tokenId) { | |
const cardId = this.getCardIdByTokenId(_tokenId) | |
return this.girlsList[cardId] | |
} | |
getGirlsList() { | |
return this.girlsList | |
} | |
getTokenIDsByAddress(_address) { | |
var result = [] | |
for (let id = 0; id < this._length; id += 1) { | |
if (this.ownerOf(id) === _address) { | |
result.push(id) | |
} | |
} | |
return result | |
} | |
getTotalSupply() { | |
return this._length | |
} | |
} | |
class LinkIdolContract extends LinkIdolToken { | |
constructor() { | |
super() | |
LocalContractStorage.defineProperties(this, { | |
cardPrice: null, | |
owner: null, | |
referCutPercentage: null | |
}) | |
} | |
init(name, symbol, initialPrice, initialGirlsList) { | |
const { | |
from | |
} = Blockchain.transaction | |
super.init(name, symbol, initialGirlsList) | |
this.cardPrice = new BigNumber(initialPrice) | |
this.owner = from | |
this.admins.set(from, "true") | |
this.referCutPercentage = 5 | |
} | |
onlyAdmins() { | |
const { | |
from | |
} = Blockchain.transaction | |
if (!this.admins.get(from)) { | |
throw new Error("Sorry, You don't have the permission as admins.") | |
} | |
} | |
setAdmins(address) { | |
this.onlyContractOwner() | |
this.admins.set(address, "true") | |
} | |
onlyContractOwner() { | |
const { | |
from | |
} = Blockchain.transaction | |
if (this.owner !== from) { | |
throw new Error("Sorry, But you don't have the permission as owner.") | |
} | |
} | |
getPrice() { | |
return this.cardPrice.toString(10) | |
} | |
// For keeping price to fiat | |
changePrice(value) { | |
this.onlyAdmins() | |
this.cardPrice = new BigNumber(value) | |
} | |
changeReferPercentage(value) { | |
this.onlyAdmins() | |
if (value > 100) { | |
throw new Error("Refer Percentage above 100 is ridiculous, we are not selling for lost") | |
} else { | |
this.referCutPercentage = value | |
} | |
} | |
withdraw(value) { | |
this.onlyAdmins() | |
// Only the owner can have the withdraw fund | |
return Blockchain.transfer(this.owner, new BigNumber(value)) | |
} | |
getReferPercentage() { | |
return this.referCutPercentage | |
} | |
_issueMultipleCard(from, qty) { | |
const resultArray = [] | |
for (let i = 0; i < qty; i += 1) { | |
var randomGirlId = parseInt(Math.random() * this.girlsList.length) | |
var tokenId = this._issue(from, randomGirlId) | |
resultArray.push(tokenId) | |
} | |
return resultArray | |
} | |
luckyDraw(referer) { | |
var { | |
from, | |
value | |
} = Blockchain.transaction | |
const { | |
cardPrice, | |
referCutPercentage | |
} = this | |
const qty = value.dividedToIntegerBy(cardPrice) | |
if (value.gt(0)) { | |
const result = this._issueMultipleCard(from, qty) | |
if (referer !== "") { | |
const referCut = value.dividedToIntegerBy(100 / referCutPercentage) | |
Blockchain.transfer(referer, referCut) | |
} | |
return result | |
} else { | |
throw new Error("You don't have enough token, try again with more.") | |
} | |
} | |
recycle(_owner, _tokenId) { | |
this.onlyAdmins() | |
this._burn(_owner, _tokenId) | |
} | |
} | |
module.exports = LinkIdolContract |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment