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