github.com/igggame/nebulas-go@v2.1.0+incompatible/nf/nvm/test/NRC721BasicToken.js (about) 1 // Copyright (C) 2017 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // the go-nebulas library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with the go-nebulas library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 19 'use strict'; 20 21 var Operator = function (obj) { 22 this.operator = {}; 23 this.parse(obj); 24 }; 25 26 Operator.prototype = { 27 toString: function () { 28 return JSON.stringify(this.operator); 29 }, 30 31 parse: function (obj) { 32 if (typeof obj != "undefined") { 33 var data = JSON.parse(obj); 34 for (var key in data) { 35 this.operator[key] = data[key]; 36 } 37 } 38 }, 39 40 get: function (key) { 41 return this.operator[key]; 42 }, 43 44 set: function (key, value) { 45 this.operator[key] = value; 46 } 47 }; 48 49 var StandardToken = function () { 50 LocalContractStorage.defineProperties(this, { 51 _name: null, 52 }); 53 54 LocalContractStorage.defineMapProperties(this, { 55 "tokenOwner": null, 56 "ownedTokensCount": { 57 parse: function (value) { 58 return new BigNumber(value); 59 }, 60 stringify: function (o) { 61 return o.toString(10); 62 } 63 }, 64 "tokenApprovals": null, 65 "operatorApprovals": { 66 parse: function (value) { 67 return new Operator(value); 68 }, 69 stringify: function (o) { 70 return o.toString(); 71 } 72 }, 73 74 }); 75 }; 76 77 StandardToken.prototype = { 78 init: function (name) { 79 this._name = name; 80 }, 81 82 name: function () { 83 return this._name; 84 }, 85 86 // Returns the number of tokens owned by owner. 87 balanceOf: function (owner) { 88 var balance = this.ownedTokensCount.get(owner); 89 if (balance instanceof BigNumber) { 90 return balance.toString(10); 91 } else { 92 return "0"; 93 } 94 }, 95 96 //Returns the address of the owner of the tokenID. 97 ownerOf: function (tokenID) { 98 return this.tokenOwner.get(tokenID); 99 }, 100 101 /** 102 * Set or reaffirm the approved address for an token. 103 * The function SHOULD throws unless transcation from is the current token owner, or an authorized operator of the current owner. 104 */ 105 approve: function (to, tokenId) { 106 var from = Blockchain.transaction.from; 107 108 var owner = this.ownerOf(tokenId); 109 if (to == owner) { 110 throw new Error("invalid address in approve."); 111 } 112 if (owner == from || this.isApprovedForAll(owner, from)) { 113 this.tokenApprovals.set(tokenId, to); 114 this._approveEvent(true, owner, to, tokenId); 115 } else { 116 throw new Error("permission denied in approve."); 117 } 118 }, 119 120 // Returns the approved address for a single token. 121 getApproved: function (tokenId) { 122 return this.tokenApprovals.get(tokenId); 123 }, 124 125 /** 126 * Enable or disable approval for a third party (operator) to manage all of transaction from's assets. 127 * operator Address to add to the set of authorized operators. 128 * @param approved True if the operators is approved, false to revoke approval 129 */ 130 setApprovalForAll: function(to, approved) { 131 var from = Blockchain.transaction.from; 132 if (from == to) { 133 throw new Error("invalid address in setApprovalForAll."); 134 } 135 var operator = this.operatorApprovals.get(from) || new Operator(); 136 operator.set(to, approved); 137 this.operatorApprovals.set(from, operator); 138 }, 139 140 /** 141 * @dev Tells whether an operator is approved by a given owner 142 * @param owner owner address which you want to query the approval of 143 * @param operator operator address which you want to query the approval of 144 * @return bool whether the given operator is approved by the given owner 145 */ 146 isApprovedForAll: function(owner, operator) { 147 var operator = this.operatorApprovals.get(owner); 148 if (operator != null) { 149 if (operator.get(operator) === "true") { 150 return true; 151 } else { 152 return false; 153 } 154 } 155 }, 156 157 158 /** 159 * @dev Returns whether the given spender can transfer a given token ID 160 * @param spender address of the spender to query 161 * @param tokenId uint256 ID of the token to be transferred 162 * @return bool whether the msg.sender is approved for the given token ID, 163 * is an operator of the owner, or is the owner of the token 164 */ 165 _isApprovedOrOwner: function(spender, tokenId) { 166 var owner = this.ownerOf(tokenId); 167 return spender == owner || this.getApproved(tokenId) == spender || this.isApprovedForAll(owner, spender); 168 }, 169 170 /** 171 * Transfers the ownership of an token from one address to another address. 172 * The caller is responsible to confirm that to is capable of receiving token or else they may be permanently lost. 173 * Transfers tokenId from address from to address to, and MUST fire the Transfer event. 174 * The function SHOULD throws unless the transaction from is the current owner, an authorized operator, or the approved address for this token. 175 * Throws if from is not the current owner. 176 * Throws if to is the contract address. 177 * Throws if tokenId is not a valid token. 178 */ 179 transferFrom: function (from, to, tokenId) { 180 var sender = Blockchain.transaction.from; 181 var contractAddress = Blockchain.transaction.to; 182 if (contractAddress == to) { 183 throw new Error("Forbidden to transfer money to a smart contract address"); 184 } 185 if (this._isApprovedOrOwner(sender, tokenId)) { 186 this._clearApproval(from, tokenId); 187 this._removeTokenFrom(from, tokenId); 188 this._addTokenTo(to, tokenId); 189 this._transferEvent(true, from, to, tokenId); 190 } else { 191 throw new Error("permission denied in transferFrom."); 192 } 193 194 }, 195 196 197 /** 198 * Internal function to clear current approval of a given token ID 199 * Throws if the given address is not indeed the owner of the token 200 * @param sender owner of the token 201 * @param tokenId uint256 ID of the token to be transferred 202 */ 203 _clearApproval: function (sender, tokenId) { 204 var owner = this.ownerOf(tokenId); 205 if (sender != owner) { 206 throw new Error("permission denied in clearApproval."); 207 } 208 this.tokenApprovals.del(tokenId); 209 }, 210 211 /** 212 * Internal function to remove a token ID from the list of a given address 213 * @param from address representing the previous owner of the given token ID 214 * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address 215 */ 216 _removeTokenFrom: function(from, tokenId) { 217 if (from != this.ownerOf(tokenId)) { 218 throw new Error("permission denied in removeTokenFrom."); 219 } 220 var tokenCount = this.ownedTokensCount.get(from); 221 if (tokenCount.lt(1)) { 222 throw new Error("Insufficient account balance in removeTokenFrom."); 223 } 224 this.ownedTokensCount.set(from, tokenCount.sub(1)); 225 }, 226 227 /** 228 * Internal function to add a token ID to the list of a given address 229 * @param to address representing the new owner of the given token ID 230 * @param tokenId uint256 ID of the token to be added to the tokens list of the given address 231 */ 232 _addTokenTo: function(to, tokenId) { 233 this.tokenOwner.set(tokenId, to); 234 var tokenCount = this.ownedTokensCount.get(to) || new BigNumber(0); 235 this.ownedTokensCount.set(to, tokenCount.add(1)); 236 }, 237 238 /** 239 * Internal function to mint a new token 240 * @param to The address that will own the minted token 241 * @param tokenId uint256 ID of the token to be minted by the msg.sender 242 */ 243 _mint: function(to, tokenId) { 244 this._addTokenTo(to, tokenId); 245 this._transferEvent(true, "", to, tokenId); 246 }, 247 248 /** 249 * Internal function to burn a specific token 250 * @param tokenId uint256 ID of the token being burned by the msg.sender 251 */ 252 _burn: function(owner, tokenId) { 253 this._clearApproval(owner, tokenId); 254 this._removeTokenFrom(owner, tokenId); 255 this._transferEvent(true, owner, "", tokenId); 256 }, 257 258 _transferEvent: function (status, from, to, tokenId) { 259 Event.Trigger(this.name(), { 260 Status: status, 261 Transfer: { 262 from: from, 263 to: to, 264 tokenId: tokenId 265 } 266 }); 267 }, 268 269 _approveEvent: function (status, owner, spender, tokenId) { 270 Event.Trigger(this.name(), { 271 Status: status, 272 Approve: { 273 owner: owner, 274 spender: spender, 275 tokenId: tokenId 276 } 277 }); 278 } 279 280 }; 281 282 module.exports = StandardToken;