github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/contracts/demo/howToCreatePrivacyContract.txt (about)

     1  Token contract privacy is a demo which can not be used in production system
     2  
     3  
     4  How to create your Dapp with Privacy
     5  
     6  Following demo is a token contract with privacy transaction
     7  
     8  
     9  pragma solidity ^0.4.11;
    10  
    11  /**
    12   * Math operations with safety checks
    13   */
    14  library SafeMath {
    15    function mul(uint a, uint b) internal pure returns (uint) {
    16      uint c = a * b;
    17      assert(a == 0 || c / a == b);
    18      return c;
    19    }
    20  
    21    function div(uint a, uint b) internal pure returns (uint) {
    22      assert(b > 0);
    23      uint c = a / b;
    24      assert(a == b * c + a % b);
    25      return c;
    26    }
    27  
    28    function sub(uint a, uint b) internal pure returns (uint) {
    29      assert(b <= a);
    30      return a - b;
    31    }
    32  
    33    function add(uint a, uint b) internal pure returns (uint) {
    34      uint c = a + b;
    35      assert(c >= a);
    36      return c;
    37    }
    38  
    39    function max64(uint64 a, uint64 b) internal pure returns (uint64) {
    40      return a >= b ? a : b;
    41    }
    42  
    43    function min64(uint64 a, uint64 b) internal pure returns (uint64) {
    44      return a < b ? a : b;
    45    }
    46  
    47    function max256(uint256 a, uint256 b) internal pure returns (uint256) {
    48      return a >= b ? a : b;
    49    }
    50  
    51    function min256(uint256 a, uint256 b) internal pure returns (uint256) {
    52      return a < b ? a : b;
    53    }
    54  }
    55  
    56  contract ERC20Protocol {
    57      /* This is a slight change to the ERC20 base standard.
    58      function totalSupply() constant returns (uint supply);
    59      is replaced with:
    60      uint public totalSupply;
    61      This automatically creates a getter function for the totalSupply.
    62      This is moved to the base contract since public getter functions are not
    63      currently recognised as an implementation of the matching abstract
    64      function by the compiler.
    65      */
    66      /// total amount of tokens
    67      uint public totalSupply;
    68  
    69      /// @param _owner The address from which the balance will be retrieved
    70      /// @return The balance
    71      function balanceOf(address _owner) public constant returns (uint balance);
    72  
    73      /// @notice send `_value` token to `_to` from `msg.sender`
    74      /// @param _to The address of the recipient
    75      /// @param _value The amount of token to be transferred
    76      /// @return Whether the transfer was successful or not
    77      function transfer(address _to, uint _value) public returns (bool success);
    78  
    79      /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
    80      /// @param _from The address of the sender
    81      /// @param _to The address of the recipient
    82      /// @param _value The amount of token to be transferred
    83      /// @return Whether the transfer was successful or not
    84      function transferFrom(address _from, address _to, uint _value) public returns (bool success);
    85      
    86  	///if you want to use privacy transaction,you need to implement this function in your contract
    87      /// @notice send `_value` token to `_to` from `msg.sender`
    88      /// @param _to The address of the recipient
    89      /// @param _toKey the ota pubkey 
    90      /// @param _value The amount of token to be transferred
    91      /// @return Whether the transfer was successful or not  
    92      function otatransfer(address _to, bytes _toKey, uint256 _value) public returns (string);    
    93      
    94  	///check privacy transaction 
    95      /// @param _owner The address from which the ota balance will be retrieved
    96      /// @return The balance
    97      function otabalanceOf(address _owner) public constant returns (uint256 balance);
    98  
    99      /// @notice `msg.sender` approves `_spender` to spend `_value` tokens
   100      /// @param _spender The address of the account able to transfer the tokens
   101      /// @param _value The amount of tokens to be approved for transfer
   102      /// @return Whether the approval was successful or not
   103      function approve(address _spender, uint _value) public returns (bool success);
   104  
   105      /// @param _owner The address of the account owning tokens
   106      /// @param _spender The address of the account able to transfer the tokens
   107      /// @return Amount of remaining tokens allowed to spent
   108      function allowance(address _owner, address _spender) public constant returns (uint remaining);
   109  
   110      event Transfer(address indexed _from, address indexed _to, uint _value);
   111      event Approval(address indexed _owner, address indexed _spender, uint _value);
   112  }
   113  
   114  //the contract implements ERC20Protocol interface with privacy transaction
   115  contract StandardToken is ERC20Protocol {
   116  
   117      using SafeMath for uint;
   118      string public constant name = "WanToken-Beta";
   119      string public constant symbol = "WanToken";
   120      uint public constant decimals = 18;
   121      
   122      function transfer(address _to, uint _value) public returns (bool success) {
   123  
   124          if (balances[msg.sender] >= _value) {
   125              balances[msg.sender] -= _value;
   126              balances[_to] += _value;
   127              Transfer(msg.sender, _to, _value);
   128              return true;
   129          } else { return false; }
   130      }
   131  
   132      function transferFrom(address _from, address _to, uint _value) public returns (bool success) {
   133  
   134          if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value) {
   135              balances[_to] += _value;
   136              balances[_from] -= _value;
   137              allowed[_from][msg.sender] -= _value;
   138              Transfer(_from, _to, _value);
   139              return true;
   140          } else { return false; }
   141      }
   142  
   143      function balanceOf(address _owner) public constant returns (uint balance) {
   144          return balances[_owner];
   145      }
   146  
   147      function approve(address _spender, uint _value) public returns (bool success) {
   148  
   149          assert((_value == 0) || (allowed[msg.sender][_spender] == 0));
   150  
   151          allowed[msg.sender][_spender] = _value;
   152          Approval(msg.sender, _spender, _value);
   153          return true;
   154      }   
   155      
   156      function allowance(address _owner, address _spender) public constant returns (uint remaining) {
   157        return allowed[_owner][_spender];
   158      }
   159  
   160      ////////////////////////////////////////////////////////////////////////
   161      mapping (address => uint) balances;
   162      mapping (address => mapping (address => uint)) allowed;
   163      
   164      // privacy balance, bytes for public key 
   165      mapping (address => uint256) public privacyBalance;
   166      mapping (address => bytes) public otaKey;
   167      
   168      //this only for initialize, only for test to mint token to one wan address
   169      function initPrivacyAsset(address initialBase, bytes baseKeyBytes, uint256 value) public {
   170          privacyBalance[initialBase] = value;
   171          otaKey[initialBase] = baseKeyBytes;
   172      }   
   173      
   174      // return string just for debug
   175      function otatransfer(address _to, bytes _toKey, uint256 _value) public returns (string) {      
   176          if(privacyBalance[msg.sender] < _value) return "sender token too low";
   177          
   178          privacyBalance[msg.sender] -= _value;
   179          privacyBalance[_to] += _value;
   180          otaKey[_to] = _toKey;
   181          return "success";
   182      } 
   183  
   184  	//check privacy balance
   185      function otabalanceOf(address _owner) public view returns (uint256 balance) {
   186          return privacyBalance[_owner];
   187      }   
   188      
   189  }
   190  
   191  Note:
   192    1. Privacy transaction function is "otatransfer" in the ERC20Protocol, the contract with privacy transaction need to implement ERC20Protocol
   193    2. Privacy balance is stored in the map privacyBalance, function otabalanceOf can get this balance
   194  
   195  
   196    
   197  How to compile and deploy:    
   198  
   199  Requirement:
   200  
   201  1: a working Wanchain client, go to the github site, https://github.com/wanchain/go-wanchain, to get the latest version
   202  2: remix https://remix.ethereum.org, which is an amazing online smart contract development IDE
   203  3: your awesome Dapp consists of one or multiple smart contracts
   204  
   205  Steps:
   206  
   207  1: go to remix, copy and paste your smart contract code, make static syntax analysis, and compile it
   208  2: click Details on the right panel of remix, copy all the code of WEB3DEPLOY section from the pop-up
   209  3: copy the script and run it in gwan console
   210  var erc20simple_contract = web3.eth.contract([{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_toKey","type":"bytes"},{"name":"_value","type":"uint256"}],"name":"otatransfer","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"privacyBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"initialBase","type":"address"},{"name":"baseKeyBytes","type":"bytes"},{"name":"value","type":"uint256"}],"name":"initPrivacyAsset","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"otabalanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"otaKey","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]);
   211  
   212  var erc20simple = erc20simple_contract.new(
   213     {
   214       from: web3.eth.accounts[1], 
   215       data: '0x6060604052341561000f57600080fd5b6111e38061001e6000396000f3006060604052600436106100d0576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100d5578063095ea7b31461016357806318160ddd146101bd578063209194e6146101e657806323b872dd146102e4578063313ce5671461035d57806341267ca21461038657806370a08231146103d357806395d89b4114610420578063a3796c15146104ae578063a9059cbb14610533578063ce6ebd3d1461058d578063dd62ed3e146105da578063f8a5b33514610646575b600080fd5b34156100e057600080fd5b6100e86106f8565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561012857808201518184015260208101905061010d565b50505050905090810190601f1680156101555780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561016e57600080fd5b6101a3600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610731565b604051808215151515815260200191505060405180910390f35b34156101c857600080fd5b6101d06108b5565b6040518082815260200191505060405180910390f35b34156101f157600080fd5b610269600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919080359060200190919050506108bb565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102a957808201518184015260208101905061028e565b50505050905090810190601f1680156102d65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156102ef57600080fd5b610343600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a75565b604051808215151515815260200191505060405180910390f35b341561036857600080fd5b610370610ce5565b6040518082815260200191505060405180910390f35b341561039157600080fd5b6103bd600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610cea565b6040518082815260200191505060405180910390f35b34156103de57600080fd5b61040a600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610d02565b6040518082815260200191505060405180910390f35b341561042b57600080fd5b610433610d4b565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610473578082015181840152602081019050610458565b50505050905090810190601f1680156104a05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156104b957600080fd5b610531600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091908035906020019091905050610d84565b005b341561053e57600080fd5b610573600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610e21565b604051808215151515815260200191505060405180910390f35b341561059857600080fd5b6105c4600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610f7e565b6040518082815260200191505060405180910390f35b34156105e557600080fd5b610630600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610fc7565b6040518082815260200191505060405180910390f35b341561065157600080fd5b61067d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061104e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156106bd5780820151818401526020810190506106a2565b50505050905090810190601f1680156106ea5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6040805190810160405280600d81526020017f57616e546f6b656e2d426574610000000000000000000000000000000000000081525081565b6000808214806107bd57506000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054145b15156107c557fe5b81600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b6108c36110fe565b81600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015610947576040805190810160405280601481526020017f73656e64657220746f6b656e20746f6f206c6f770000000000000000000000008152509050610a6e565b81600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555082600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209080519060200190610a34929190611112565b506040805190810160405280600781526020017f737563636573730000000000000000000000000000000000000000000000000081525090505b9392505050565b600081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610b42575081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b15610cd95781600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610cde565b600090505b9392505050565b601281565b60036020528060005260406000206000915090505481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6040805190810160405280600881526020017f57616e546f6b656e00000000000000000000000000000000000000000000000081525081565b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209080519060200190610e1b929190611112565b50505050565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515610f735781600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610f78565b600090505b92915050565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b60046020528060005260406000206000915090508054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156110f65780601f106110cb576101008083540402835291602001916110f6565b820191906000526020600020905b8154815290600101906020018083116110d957829003601f168201915b505050505081565b602060405190810160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061115357805160ff1916838001178555611181565b82800160010185558215611181579182015b82811115611180578251825591602001919060010190611165565b5b50905061118e9190611192565b5090565b6111b491905b808211156111b0576000816000905550600101611198565b5090565b905600a165627a7a72305820c7a344a3e72215ba3952e15ab354904e1edd02798099defd384453d37142be270029', 
   216       gas: '4700000'
   217     }, function (e, contract){
   218      console.log(e, contract);
   219      if (typeof contract.address !== 'undefined') {
   220           console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
   221      }
   222   })
   223  
   224  4: the transaction id and contract address (hash values starting with '0x') will be printed out onto the console after few seconds
   225  
   226  5: now, you can play with your Dapp 
   227  
   228  Note:
   229  	You can locate a demo wanchain token contract and involved scripts under contracts/demo/ directory
   230  
   231  
   232  How to invoke privacy transfer
   233  
   234  After deployed above token contract on wanchain,in the wanchain console,you can invoke token privacy transaction according to following ways
   235  
   236  Suppose there are at lease 3 account in your wanchain node
   237  
   238  1. define assit function and variable
   239  
   240  var initPriBalance = 10000;
   241  var priTranValue = 888;
   242  
   243  var wanBalance = function(addr){
   244  	return web3.fromWin(web3.eth.getBalance(addr));
   245  }
   246  
   247  var wanUnlock = function(addr){
   248      return personal.unlockAccount(addr,"wanglu",99999);
   249  }
   250  
   251  var sendWanFromUnlock = function (From, To , V){
   252  	eth.sendTransaction({from:From, to: To, value: web3.toWin(V)});
   253  }
   254  
   255  var wait = function (conditionFunc) {
   256  	var loopLimit = 130;
   257  	var loopTimes = 0;
   258  	while (!conditionFunc()) {
   259  		admin.sleep(2);
   260  		loopTimes++;
   261  		if(loopTimes>=loopLimit){
   262  			throw Error("wait timeout! conditionFunc:" + conditionFunc)
   263  		}
   264  	}
   265  }
   266  
   267  wanUnlock(eth.accounts[1])
   268  wanUnlock(eth.accounts[2])
   269  stampBalance = 0.09;
   270  
   271  
   272  2. buy stamp for token privacy transaction
   273  
   274  abiDefStamp = [{"constant":false,"type":"function","stateMutability":"nonpayable","inputs":[{"name":"OtaAddr","type":"string"},{"name":"Value","type":"uint256"}],"name":"buyStamp","outputs":[{"name":"OtaAddr","type":"string"},{"name":"Value","type":"uint256"}]},{"constant":false,"type":"function","inputs":[{"name":"RingSignedData","type":"string"},{"name":"Value","type":"uint256"}],"name":"refundCoin","outputs":[{"name":"RingSignedData","type":"string"},{"name":"Value","type":"uint256"}]},{"constant":false,"type":"function","stateMutability":"nonpayable","inputs":[],"name":"getCoins","outputs":[{"name":"Value","type":"uint256"}]}];
   275  
   276  contractDef = eth.contract(abiDefStamp);
   277  stampContractAddr = "0x00000000000000000000000000000000000000c8";
   278  stampContract = contractDef.at(stampContractAddr);
   279  
   280  var wanAddr = wan.getWanAddress(eth.accounts[1]);
   281  var otaAddrStamp = wan.generateOneTimeAddress(wanAddr);
   282  txBuyData = stampContract.buyStamp.getData(otaAddrStamp, web3.toWin(stampBalance));
   283  
   284  sendTx = eth.sendTransaction({from:eth.accounts[1], to:stampContractAddr, value:web3.toWin(stampBalance), data:txBuyData, gas: 1000000});
   285  wait(function(){return eth.getTransaction(sendTx).blockNumber != null;});
   286  
   287  keyPairs = wan.computeOTAPPKeys(eth.accounts[1], otaAddrStamp).split('+');
   288  privateKeyStamp = keyPairs[0];
   289  
   290  3. get stamp mix set for ring sign
   291  
   292  var mixStampAddresses = wan.getOTAMixSet(otaAddrStamp,2);
   293  var mixSetWith0x = []
   294  for (i = 0; i < mixStampAddresses.length; i++){
   295      mixSetWith0x.push(mixStampAddresses[i])
   296  }
   297  
   298  
   299  4. define token contract ABI
   300  
   301  var erc20simple_contract = web3.eth.contract([{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_toKey","type":"bytes"},{"name":"_value","type":"uint256"}],"name":"otatransfer","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"privacyBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"initialBase","type":"address"},{"name":"baseKeyBytes","type":"bytes"},{"name":"value","type":"uint256"}],"name":"initPrivacyAsset","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"otabalanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"otaKey","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]);
   302  
   303  contractAddr = '0xa2e526a3632d225f15aa0592e00bed31a48c953d';//this address should changed according to your contract deploy
   304  erc20simple = erc20simple_contract.at(contractAddr)
   305  
   306  5. create one time address for account1
   307  
   308  var wanAddr = wan.getWanAddress(eth.accounts[1]);
   309  var otaAddrTokenHolder = wan.generateOneTimeAddress(wanAddr);
   310  keyPairs = wan.computeOTAPPKeys(eth.accounts[1], otaAddrTokenHolder).split('+');
   311  privateKeyTokenHolder = keyPairs[0];
   312  addrTokenHolder = keyPairs[2];
   313  sendTx = erc20simple.initPrivacyAsset.sendTransaction(addrTokenHolder, otaAddrTokenHolder, '0x' + initPriBalance.toString(16), {from:eth.accounts[1], gas:1000000});
   314  wait(function(){return eth.getTransaction(sendTx).blockNumber != null;});
   315  
   316  ota1Balance = erc20simple.privacyBalance(addrTokenHolder)
   317  if (ota1Balance != initPriBalance) {
   318  	throw Error('ota1 balance wrong! balance:' + ota1Balance + ', except:' + initPriBalance)
   319  }
   320  
   321  6. generate ring sign data
   322  
   323  var hashMsg = addrTokenHolder
   324  var ringSignData = personal.genRingSignData(hashMsg, privateKeyStamp, mixSetWith0x.join("+"))
   325  
   326  7. create one time address for account2
   327  
   328  var wanAddr = wan.getWanAddress(eth.accounts[2]);
   329  var otaAddr4Account2 = wan.generateOneTimeAddress(wanAddr);
   330  keyPairs = wan.computeOTAPPKeys(eth.accounts[2], otaAddr4Account2).split('+');
   331  privateKeyOtaAcc2 = keyPairs[0];
   332  addrOTAAcc2 = keyPairs[2];
   333  
   334  8. generate token privacy transfer data
   335  
   336  cxtInterfaceCallData = erc20simple.otatransfer.getData(addrOTAAcc2, otaAddr4Account2, priTranValue);
   337  
   338  9. generate call token privacy transfer data
   339  
   340  glueContractDef = eth.contract([{"constant":false,"type":"function","inputs":[{"name":"RingSignedData","type":"string"},{"name":"CxtCallParams","type":"bytes"}],"name":"combine","outputs":[{"name":"RingSignedData","type":"string"},{"name":"CxtCallParams","type":"bytes"}]}]);
   341  glueContract = glueContractDef.at("0x0000000000000000000000000000000000000000")
   342  combinedData = glueContract.combine.getData(ringSignData, cxtInterfaceCallData)
   343  
   344  
   345  10.send privacy transaction
   346  
   347  sendTx = personal.sendPrivacyCxtTransaction({from:addrTokenHolder, to:contractAddr, value:0, data: combinedData, gasprice:'0x' + (200000000000).toString(16)}, privateKeyTokenHolder)
   348  wait(function(){return eth.getTransaction(sendTx).blockNumber != null;});
   349  
   350  
   351  11. check balance
   352  
   353  ota2Balance = erc20simple.privacyBalance(addrOTAAcc2)
   354  if (ota2Balance != priTranValue) {
   355  	throw Error("ota2 balance wrong. balance:" + ota2Balance +  ", expect:" + priTranValue)
   356  }
   357  
   358  ota1Balance = erc20simple.privacyBalance(addrTokenHolder)
   359  if (ota1Balance != initPriBalance - priTranValue) {
   360  	throw Error("ota2 balance wrong. balance:" + ota1Balance +  ", expect:" + (initPriBalance - priTranValue))
   361  }
   362