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;