Wanchain Documentation¶
Contents¶
Introduction¶
What is Wanchain?¶
Wanchain aims to build a blockchain infrastructure that can be used to realize the connection and value exchange of different block-chain networks in a decentralized way. It uses the latest theory of cryptography to make up for the shortcomings of existing inter-chain protocol. Any blockchain network, whether public chain, private chain or alliance chain, can be access to Wanchain to complete the inter-chain transaction of digital assets at a low cost. Wanchain is not just a generic inter-chain protocol, but also a distributed ledger that records inter-chain transactions and in-chain transactions. This ledger supports not only the smart contracts, but also the privacy protection of smart contract tokens trade. It is a qualitative leap to the Interconnection of thousands of Chains and turn of Chains into Internet, and the centralized application of advanced cryptography theory in the field of blockchain, as well as a new and complete blockchain network with high efficiency and completeness. Wanchain is about to reshape the economic ecology of blockchain.
Differentiation of other blockchain product¶
From the perspective of blockchain industry’s development, the ultimate vision of Wanchain is to create an “Internet” of blockchain to achieve the qualitative leap of blockchain turning from chains to internet. In Wanchain’s ecosystem, thousands of chains are interconnected, where value can be transferred free from barriers, giving full play of blockchains function of carrying and transferring value. Wanchain is about to reshape the economic ecology.
From the perceptive of the development of blockchain’s underlying technology, Wanchain applies secure multi-party computation, threshold secret sharing, ring signature scheme based on elliptic curve, one-off generation mechanism of account and many other cutting-edge technologies of cryptology, and solves privacy protection problem of smart contract token transaction. To some extent, Wanchain is the typical application of advanced cryptography solving the real problems of blockchain, representing the development direction of blockchain’s underlying technology, that is, transforming from conditional security to provable security, from logical control to algorithm theory control. Wanchain boasts a professional cryptography research team who will continue to contribute to the industry as a whole for the cryptography applying in the field of blockchain.
From the perspective of blockchain application, Wanchain is more than a blockchain project realizing inter-chain transaction and interoperability of multiple assets, but a complete blockchain developing platform. While achieving the function of inter-chain transaction, Wanchain is also a blockchain network that can run independently: it contains native coin, supports smart contracts, and has privacy protection mechanisms for smart contract token transactions. Any developers may develop application met their need on Wanchain in accordance with application scenario.
Milestones¶
2016/06
Research on privacy protection and cross-chain transactions
2016/12
Development on Proof of Concept
2017/06
White Paper published. Wanchain.org online
2017/09
ICO Crowd funding
2018/01
Wanchain 1.0 goes live (Privacy Protection, WAN, Wallet, Block chain Explorer)
2018/06 (ongoing)
Wanchain 2.0 (Integration with Ethereum, Multi-Coin Wallet)
2018/12 (ongoing)
Wanchain 3.0 (Integration with Bitcoin, Multi-Coin Wallet)
2019/12 (ongoing)
Wanchain 4.0 (Integration with Private Chains, Multi-Coin Wallet)
Community¶
Official Links:
Wanchain Clients¶
Connecting to Wanchain Clients¶
GUI WAN Wallet¶
There are three GUI wallets for belowing type of operate systems:
- Windows OS
- Mac OS
- Linux OS
We have an universal How to Use GUI wallet guide to guide you step by step to quickly get familar with our wallet
Command Line¶
We provide command line tools for anyone who is comfortable using CMD terminology
Please find How to Use CLI Wallet guide here
WAN Account¶
We have a step-by-step tutorial process on github to guide you through https://github.com/wanchain/go-wanchain/wiki/How-To-Use-(GUI)-Guide
Keystore¶
Keystore is where controls your account details, if you lose your keystore files you are at high risks to lose all your current assets, therefore we strongly recommend you backup all keystore files at a place you could trust and won’t forget (ie Offline PC device or U-Disk etc)
At any circumstances, you should NOT share or reveal your keystore information with anyone you don’t trust, you might get stolen by doing so . If you think your keystore has been leak to any 3rd parties, please transfer your assets to a new account !
You can always find your accounts & application data at backups
- Open your Wallet GUI click:
- File -> Backup -> Accounts /Application data
Once you clicked Accounts it will pop up a folder with “Keystore” file inside.
- Here is the root :
- C:UsersAdministratorAppDataRoamingwanchain
Double click Keystore files under file wanchain, you will find all your accounts information and those file/files are what you need to keep in safe all the time.
Creating Account¶
Have an existing account
If you have an existing keystore file , you can simply conduct drag & drop on your wallet GUI to get it back
File -> Import accounts -> Drag & Drop -> Done
Create a new account
If you need to create a new account , simply click “Account” once you log in wallet GUI .
Account -> Input New Account Name -> Enter/Re-enter password -> Done
Ordinary & Private Address¶
Ordinary address (Short address) as known as public address which allows everyone see transaction details. On the opposite, Private address (Long address) as known as MSA (Master Stealth Address) which details will not be revealed.
Example of Oridinary address :
0xefe000C1b9f9ca9bf063857aAF5fCb7B8A25eaA1
Example of Private address :
0x02bddd6c139a10c5c9e81d1d6438dd26bc4a26824a2c729819d21ee1fca8b2dbc203936c798596ac4adcbe89e96c88397894b6dfab14a95ea7e137c31f56b9c81255
Backup and restore accounts¶
The process to backup your acounts :
Click File -> Backup -> Application Data
You will see files under WanWalletGui as defaulted. Please select them all and make copy to a safety place where you can trust.
The Accounts & Application Data stores all your public transaction records, private transaction records and OTA balance. If you delete these files , you will not lose your assets but you will not be able to see your assets at your current wallet at meantime unless you back them up in advance . However, you can always call it back via “Import Account” which we have demonstrated to you in above content.
WAN¶
What is WAN?¶
WAN or WANCoin known as the native currancy of WAN chain. Both common intra-chain transactions and inter-chain transactions will consume a certain amount of WAN, and at the same time, WANC will be used as a margin for inter-chain verification node.
WAN Supply¶
The base unit of WAN is called Win. Blow is a list of named demonimations and their value in Win accordinly.
Unit | Win Value | Win |
---|---|---|
Win | 1 win | 1 |
Kwin | 1e3 win | 1,000 |
Mwin | 1e6 win | 1,000,000 |
Gwin | 1e9 win | 1,000,000,000 |
Szabo | 1e12 win | 1,000,000,000,000 |
Finney | 1e15 win | 1,000,000,000,000,000 |
Wan | 1e18 win | 1,000,000,000,000,000,000 |
The Wanchain network¶
Main network¶
Test network¶
Pass the --testnet
argument to the client. e.g.:
> gwan --testnet
> wanwalletgui --network testnet
Contracts and Transactions¶
How To Deploy Smart Contract On Wanchain¶
Smart Contract Source Code Example¶
Note
The following smart contract code is only an example and is NOT to be used in Production systems.
pragma solidity ^0.4.11;
/**
* Math operations with safety checks
*/
library SafeMath {
function mul(uint a, uint b) internal pure returns (uint) {
uint c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint a, uint b) internal pure returns (uint) {
assert(b > 0);
uint c = a / b;
assert(a == b * c + a % b);
return c;
}
function sub(uint a, uint b) internal pure returns (uint) {
assert(b <= a);
return a - b;
}
function add(uint a, uint b) internal pure returns (uint) {
uint c = a + b;
assert(c >= a);
return c;
}
function max64(uint64 a, uint64 b) internal pure returns (uint64) {
return a >= b ? a : b;
}
function min64(uint64 a, uint64 b) internal pure returns (uint64) {
return a < b ? a : b;
}
function max256(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
contract ERC20Protocol {
/* This is a slight change to the ERC20 base standard.
function totalSupply() constant returns (uint supply);
is replaced with:
uint public totalSupply;
This automatically creates a getter function for the totalSupply.
This is moved to the base contract since public getter functions are not
currently recognised as an implementation of the matching abstract
function by the compiler.
*/
/// total amount of tokens
uint public totalSupply;
/// @param _owner The address from which the balance will be retrieved
/// @return The balance
function balanceOf(address _owner) public constant returns (uint balance);
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transfer(address _to, uint _value) public returns (bool success);
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transferFrom(address _from, address _to, uint _value) public returns (bool success);
///if you want to use privacy transaction,you need to implement this function in your contract
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _toKey the ota pubkey
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function otatransfer(address _to, bytes _toKey, uint256 _value) public returns (string);
///check privacy transaction
/// @param _owner The address from which the ota balance will be retrieved
/// @return The balance
function otabalanceOf(address _owner) public constant returns (uint256 balance);
/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of tokens to be approved for transfer
/// @return Whether the approval was successful or not
function approve(address _spender, uint _value) public returns (bool success);
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
function allowance(address _owner, address _spender) public constant returns (uint remaining);
event Transfer(address indexed _from, address indexed _to, uint _value);
event Approval(address indexed _owner, address indexed _spender, uint _value);
}
//the contract implements ERC20Protocol interface with privacy transaction
contract StandardToken is ERC20Protocol {
using SafeMath for uint;
string public constant name = "WanToken-Beta";
string public constant symbol = "WanToken";
uint public constant decimals = 18;
function transfer(address _to, uint _value) public returns (bool success) {
if (balances[msg.sender] >= _value) {
balances[msg.sender] -= _value;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
} else { return false; }
}
function transferFrom(address _from, address _to, uint _value) public returns (bool success) {
if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value) {
balances[_to] += _value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
Transfer(_from, _to, _value);
return true;
} else { return false; }
}
function balanceOf(address _owner) public constant returns (uint balance) {
return balances[_owner];
}
function approve(address _spender, uint _value) public returns (bool success) {
assert((_value == 0) || (allowed[msg.sender][_spender] == 0));
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public constant returns (uint remaining) {
return allowed[_owner][_spender];
}
mapping (address => uint) balances; mapping (address => mapping (address => uint)) allowed;
// privacy balance, bytes for public key
mapping (address => uint256) public privacyBalance;
mapping (address => bytes) public otaKey;
//this only for initialize, only for test to mint token to one wan address
function initPrivacyAsset(address initialBase, bytes baseKeyBytes, uint256 value) public {
privacyBalance[initialBase] = value;
otaKey[initialBase] = baseKeyBytes;
}
// return string just for debug
function otatransfer(address _to, bytes _toKey, uint256 _value) public returns (string) {
if(privacyBalance[msg.sender] < _value) return "sender token too low";
privacyBalance[msg.sender] -= _value;
privacyBalance[_to] += _value;
otaKey[_to] = _toKey;
return "success";
}
//check privacy balance
function otabalanceOf(address _owner) public view returns (uint256 balance) {
return privacyBalance[_owner];
}
}
Note
- Privacy transaction function is “otatransfer” in the ERC20 Protocol, the contract with privacy transaction need to implement ERC20 Protocol
- Privacy balance is stored in the map privacyBalance, function otabalanceOf can get this balance
How To Compile And Deploy¶
Requirement:
- A working Wanchain client, go to the github site: go-wanchain to get the latest version
- Remix which is an amazing online smart contract development IDE
- your awesome Dapp consists of one or multiple smart contracts
Steps:
- go to remix, copy and paste your smart contract code, make static syntax analysis, and compile it
- click Details on the right panel of remix, copy all the code of WEB3DEPLOY section from the pop-up
- copy the script and run it in gwan console
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" } ])var erc20simple = erc20simple_contract.new( { from: web3.eth.accounts[1], data: '0x6060604052341561000f57600080fd5b6111e38061001e6000396000f3006060604052600436106100d0576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100d5578063095ea7b31461016357806318160ddd146101bd578063209194e6146101e657806323b872dd146102e4578063313ce5671461035d57806341267ca21461038657806370a08231146103d357806395d89b4114610420578063a3796c15146104ae578063a9059cbb14610533578063ce6ebd3d1461058d578063dd62ed3e146105da578063f8a5b33514610646575b600080fd5b34156100e057600080fd5b6100e86106f8565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561012857808201518184015260208101905061010d565b50505050905090810190601f1680156101555780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561016e57600080fd5b6101a3600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610731565b604051808215151515815260200191505060405180910390f35b34156101c857600080fd5b6101d06108b5565b6040518082815260200191505060405180910390f35b34156101f157600080fd5b610269600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919080359060200190919050506108bb565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102a957808201518184015260208101905061028e565b50505050905090810190601f1680156102d65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156102ef57600080fd5b610343600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a75565b604051808215151515815260200191505060405180910390f35b341561036857600080fd5b610370610ce5565b6040518082815260200191505060405180910390f35b341561039157600080fd5b6103bd600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610cea565b6040518082815260200191505060405180910390f35b34156103de57600080fd5b61040a600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610d02565b6040518082815260200191505060405180910390f35b341561042b57600080fd5b610433610d4b565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610473578082015181840152602081019050610458565b50505050905090810190601f1680156104a05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156104b957600080fd5b610531600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091908035906020019091905050610d84565b005b341561053e57600080fd5b610573600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610e21565b604051808215151515815260200191505060405180910390f35b341561059857600080fd5b6105c4600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610f7e565b6040518082815260200191505060405180910390f35b34156105e557600080fd5b610630600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610fc7565b6040518082815260200191505060405180910390f35b341561065157600080fd5b61067d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061104e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156106bd5780820151818401526020810190506106a2565b50505050905090810190601f1680156106ea5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6040805190810160405280600d81526020017f57616e546f6b656e2d426574610000000000000000000000000000000000000081525081565b6000808214806107bd57506000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054145b15156107c557fe5b81600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b6108c36110fe565b81600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015610947576040805190810160405280601481526020017f73656e64657220746f6b656e20746f6f206c6f770000000000000000000000008152509050610a6e565b81600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555082600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209080519060200190610a34929190611112565b506040805190810160405280600781526020017f737563636573730000000000000000000000000000000000000000000000000081525090505b9392505050565b600081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610b42575081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b15610cd95781600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610cde565b600090505b9392505050565b601281565b60036020528060005260406000206000915090505481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6040805190810160405280600881526020017f57616e546f6b656e00000000000000000000000000000000000000000000000081525081565b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209080519060200190610e1b929190611112565b50505050565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515610f735781600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610f78565b600090505b92915050565b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b60046020528060005260406000206000915090508054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156110f65780601f106110cb576101008083540402835291602001916110f6565b820191906000526020600020905b8154815290600101906020018083116110d957829003601f168201915b505050505081565b602060405190810160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061115357805160ff1916838001178555611181565b82800160010185558215611181579182015b82811115611180578251825591602001919060010190611165565b5b50905061118e9190611192565b5090565b6111b491905b808211156111b0576000816000905550600101611198565b5090565b905600a165627a7a72305820c7a344a3e72215ba3952e15ab354904e1edd02798099defd384453d37142be270029', gas: '4700000' }, function (e, contract) { console.log(e, contract); if (typeof contract.address !== 'undefined') { console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); } } )
- the transaction id and contract address (hash values starting with ‘0x’) will be printed out onto the console after few seconds
- now, you can play with your Dapp
Note
You can locate a demo WANCHAIN token contract and involved scripts under contracts/demo/ directory
How To Invoke Privacy Transfer¶
After deployed above token contract on WANCHAIN,in the WANCHAIN console,you can invoke token privacy transaction according to following process:
Suppose there are at lease 3 accounts in your WANCHAIN node
- Define asset function and variable
var initPriBalance = 10000; var priTranValue = 888; var wanBalance = function (addr) { return web3.fromWin(web3.eth.getBalance(addr)); } var wanUnlock = function (addr) { return personal.unlockAccount(addr, "wanglu", 99999); } var sendWanFromUnlock = function (From, To, V) { eth.sendTransaction({ from: From, to: To, value: web3.toWin(V) }); } var wait = function (conditionFunc) { var loopLimit = 130; var loopTimes = 0; while (!conditionFunc()) { admin.sleep(2); loopTimes++; if (loopTimes >= loopLimit) { throw Error("wait timeout! conditionFunc:" + conditionFunc) } } } wanUnlock(eth.accounts[1]) wanUnlock(eth.accounts[2]) stampBalance = 0.09;
- buy stamp for token privacy transaction
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" }] }]; contractDef = eth.contract(abiDefStamp); stampContractAddr = "0x00000000000000000000000000000000000000c8"; stampContract = contractDef.at(stampContractAddr); var wanAddr = wan.getWanAddress(eth.accounts[1]); var otaAddrStamp = wan.generateOneTimeAddress(wanAddr); txBuyData = stampContract.buyStamp.getData(otaAddrStamp, web3.toWin(stampBalance)); sendTx = eth.sendTransaction({ from: eth.accounts[1], to: stampContractAddr, value: web3.toWin(stampBalance), data: txBuyData, gas: 1000000 }); wait(function () { return eth.getTransaction(sendTx).blockNumber != null; }); keyPairs = wan.computeOTAPPKeys(eth.accounts[1], otaAddrStamp).split('+'); privateKeyStamp = keyPairs[0];
- get stamp mix set for ring sign
var mixStampAddresses = wan.getOTAMixSet(otaAddrStamp, 2); var mixSetWith0x = [] for (i = 0; i < mixStampAddresses.length; i++) { mixSetWith0x.push(mixStampAddresses[i]) }
- define token contract ABI
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" }]); contractAddr = '0xa2e526a3632d225f15aa0592e00bed31a48c953d'; // this address should changed according to your contract deploy erc20simple = erc20simple_contract.at(contractAddr)
- create one time address for account1
var wanAddr = wan.getWanAddress(eth.accounts[1]); var otaAddrTokenHolder = wan.generateOneTimeAddress(wanAddr); keyPairs = wan.computeOTAPPKeys(eth.accounts[1], otaAddrTokenHolder).split('+'); privateKeyTokenHolder = keyPairs[0]; addrTokenHolder = keyPairs[2]; sendTx = erc20simple.initPrivacyAsset.sendTransaction(addrTokenHolder, otaAddrTokenHolder, '0x' + initPriBalance.toString(16), { from: eth.accounts[1], gas: 1000000 }); wait(function () { return eth.getTransaction(sendTx).blockNumber != null; }); ota1Balance = erc20simple.privacyBalance(addrTokenHolder) if (ota1Balance != initPriBalance) { throw Error('ota1 balance wrong! balance:' + ota1Balance + ', except:' + initPriBalance) }
- generate ring sign data
var hashMsg = addrTokenHolder var ringSignData = personal.genRingSignData(hashMsg, privateKeyStamp, mixSetWith0x.join("+"))
- create one time address for account2
var wanAddr = wan.getWanAddress(eth.accounts[2]); var otaAddr4Account2 = wan.generateOneTimeAddress(wanAddr); keyPairs = wan.computeOTAPPKeys(eth.accounts[2], otaAddr4Account2).split('+'); privateKeyOtaAcc2 = keyPairs[0]; addrOTAAcc2 = keyPairs[2];
- generate token privacy transfer data
cxtInterfaceCallData = erc20simple.otatransfer.getData(addrOTAAcc2, otaAddr4Account2, priTranValue);
- generate call token privacy transfer data
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" }] }]); glueContract = glueContractDef.at("0x0000000000000000000000000000000000000000") combinedData = glueContract.combine.getData(ringSignData, cxtInterfaceCallData)
- send privacy transaction
sendTx = personal.sendPrivacyCxtTransaction({from:addrTokenHolder, to:contractAddr, value:0, data: combinedData, gasprice:'0x' + (200000000000).toString(16)}, privateKeyTokenHolder) wait(function(){return eth.getTransaction(sendTx).blockNumber != null;});
- check balance
ota2Balance = erc20simple.privacyBalance(addrOTAAcc2); if (ota2Balance != priTranValue) { throw Error("ota2 balance wrong. balance:" + ota2Balance + ", expect:" + priTranValue); } ota1Balance = erc20simple.privacyBalance(addrTokenHolder) if (ota1Balance != initPriBalance - priTranValue) { throw Error("ota2 balance wrong. balance:" + ota1Balance + ", expect:" + (initPriBalance - priTranValue)); }
Developer Tools¶
Using truffle to deploy Smart Contracts (v0.6)¶
1. Install truffle
Truffle is a command line tool to compile, deploy, and test smart contracts on blockchain. Before installing truffle, you want to install or upgrade the npm to the latest version. To install npm, use the following command:
$ sudo apt-get install npm
To upgrade npm, use the following command
$ sudo npm i -g npm
Run npm to install truffle
$ sudo npm install -g truffle
Note
Here -g is for global install so that truffle can be run from any directory
2. Use truffle tool
Once truffle is installed, you can type truffle to see a list of commands and options.
Usage: truffle <command> [options]
Commands:
init Initialize new and empty Ethereum project
compile Compile contract source files
migrate Run migrations to deploy contracts
deploy (alias for migrate)
build Execute build pipeline (if configuration present)
test Run JavaScript and Solidity tests
debug Interactively debug any transaction on the blockchain (experimental)
opcode Print the compiled opcodes for a given contract
console Run a console with contract abstractions and commands available
develop Open a console with a local development blockchain
create Helper to create new contracts, migrations and tests
install Install a package from the Ethereum Package Registry
publish Publish a package to the Ethereum Package Registry
networks Show addresses for deployed contracts on each network
watch Watch filesystem for changes and rebuild the project automatically
serve Serve the build directory on localhost and watch for changes
exec Execute a JS module within this Truffle environment
unbox Download a Truffle Box, a pre-built Truffle project
version Show version number and exit
See more at http://truffleframework.com/docs
3. Initiate, compile, and deploy a truffle project for Wanchain
Make a truffle directory
$ mkdir wanchain-example
Initialize the truffle project
3.1 Initiate
In the truffle project directory,execute:
$ truffle initOnce a truffle project is initialized, several directories will be created, including
- contracts : where the source contracts are supposed to reside
- migrations : where the deployment scripts are supposed to reside
- test : where the test files are supposed to reside
- build : the contract compiled result will be put here, created after running truffle compile or truffle migrate.
- truffle-config.js : The configuration file provides default setup parameters for the project
- truffle.js : This provide truffle smart contract parameters
The directory will be like below:
3.2 compile
In the truffle project directory, execute the command:
$ truffle compileIf the compilation is successful, a build directory will be created and abi files will be generated under build/contracts/ directory.These abi files can then be deployed as smart contract.
3.3 Config
Setup truffle.js file to specify the network setting etc.
module.exports = { networks: { development: { host: 'localhost', port: 8545, network_id: '*', gas: 4000000, gasPrice: 180e9, // following address needed to be replaced with unlocked account on gwan node from: '0x8f84573C8BaB4d56FDdB48cc792424E8816908fB' } } }Add deploy script for contract in the directory migrations in the truffle project:
Such as the deploy script name is 2_deploy_contracts.js which will deploy the contract PollApp.sol in the contract directory, the script will be as following:
var PollApp = artifacts.require("./PollApp.sol"); module.exports = function(deployer) { deployer.deploy(PollApp); };3.4 start gwan node on local host
Run following command in the directory which include gwan
$ ./gwan --rpc --testnet --rpcapi eth,net,admin,personal,wan --verbosity=0 consoleIn the gwan console to unlock a existing wanchain account in gwan node and make sure there are balance in the unlocked account, this account need to be same with the from address in the file truffle.js
3.5 deploy contracts
Execute command in the truffle project directory:
$ truffle migrate --network developmentThe result will be as following:
4. Test deployed smart contract
4.1 test script
Truffle support test for the contract, the test script should put in the directory “test” in the truffle,the test script maybe look like this:
var solc = require('solc'); var Web3 = require('web3'); const PollApp = artifacts.require('./PollApp.sol'); contract('PollApp', ([owner]) => { let PollAppInstance; before('set up contract before test', async () => { await web3.personal.unlockAccount(owner, '****', 9999); //create instance PollAppInstance = await PollApp.new({from: owner}); }) it('test case - 001', async () => { await PollAppInstance.XXX()({ from: owner }); assert.equal(..., ..., 'description...'); }) })4.2 start test
In the directory of the truffle project, execute the command:
$ truffle test or specify to execute one test script $ truffle test ./test/XXX.jsThis command will execute the test script in the directory “test” of truffle project. The result may look like this:
Cross-chain Transactions¶
Wallet Support¶
How to verify install package’s SHA256 checksum¶
Windows¶
The following command will display SHA256 hash value on a Windows operating system (“SHA256” parameter is case sensitive on certain versions of Windows):
certutil -hashfile <path><filename> SHA256
Linux¶
The following command will display SHA256 hash value on a Linux operating system:
sha256sum <path>/<filename>
Mac¶
The following command will display SHA256 hash value on a Mac operating system.
openssl dgst -sha256 <path>/<filename>