sidebar_position |
---|
3 |
Wallet Interfaces
Most operations in Neo blockchain are related to accounts. A wallet is the collection of accounts that includes one or multiple accounts. This document contains the following topics:
-
The basic concepts and operations of accounts and wallets
-
The method
WalletAPI
,which encapsulates wallet-related interfaces to provide the functions of balance inquiry, GAS claim, and transfer.
Account and Wallet
Account
An account is the user identity in Neo, which is essentially a private and public key pair ( KeyPair
) .
// create a new KeyPair
byte[] privateKey = new byte[32];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
rng.GetBytes(privateKey);
}
KeyPair keyPair = new KeyPair(privateKey);
Private Key
Private key is an authorization tool used to sign transactions. Having a private key means you own an account that you can handle all the assets in it. The private key is essentially a 32-bit byte array that can be represented as a hexadecimal string, for example:
"0x450d6c2a04b5b470339a745427bae6828400cf048400837d73c415063835e005"
// export private key to hex string
string privateHex = keyPair.PrivateKey.ToHexString();
// get KeyPair from private hex string
keyPair = Utility.GetKeyPair(privateHex);
WIF
WIF is another string representation of the private key, which is equivalent to the private key. For example, the above private key is represented as the following WIF:
"KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"
// export KeyPair as WIF
string wif = keyPair.Export();
// get KeyPair from WIF
KeyPair keyPair1 = Utility.GetKeyPair(wif);
Public Key
The public key verifies the signature of the private key. It corresponds to the ECPoint type in Neo. The public key can be calculated with the private key. Typically it is a 66-digit hexadecimal string:
"02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575"
// export public key hex string
string publicHex = keyPair.PublicKey.ToString();
// get public key from hex string
Neo.Cryptography.ECC.ECPoint publicKey = Neo.Cryptography.ECC.ECPoint.Parse(publicHex, Neo.Cryptography.ECC.ECCurve.Secp256r1);
Account ScriptHash
ScriptHash, corresponding to UInt160
in Neo, is essentially a 20-bit byte array generated from the public key by script construction and hash algorithm. Since the hash algorithm is not reversible, the public key cannot be calculated backwards from the script hash. ScriptHash is usually expressed as a reversed hexadecimal string in big-endian order: "0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"
// get ScriptHash of KeyPair account
UInt160 scriptHash = Contract.CreateSignatureContract(keyPair.PublicKey).ScriptHash;
string strScriptHash = scriptHash.ToString();
Address
Address is another string form of ScriptHash and can be transformed to or from ScriptHash. As the unique identifier of the account, address is the most commonly used account form. It is similar to the account number for a traditional account, when you transfer money you transfer it to a specified address. A common address format is: "Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"
using Neo.Wallets;
// ScriptHash to address
string adddress = scriptHash.ToAddress();
// address to ScriptHash
scriptHash = adddress.ToScriptHash();
Wallet
Wallet is a collection of accounts. NEP6 is the most commonly used wallet standard in Neo. A NEP6 wallet can be serialized into a JSON file, in which the encrypted account private key is saved. The corresponding password is required to decrypt the private key.
Here is an example:
Create a new NEP6 wallet with an account and save as JSON file:
// create wallet
string path = "wallet_new.json";
string password = "MyPass";
NEP6Wallet wallet_new = new NEP6Wallet(path);
using (wallet_new.Unlock(password))
{
wallet_new.CreateAccount(keyPair.PrivateKey);
}
wallet_new.Save();
Read the NEP6 wallet from the JSON file and decrypt the account:
// load wallet from nep6 wallet
NEP6Wallet wallet = new NEP6Wallet(path);
KeyPair keyPair2;
using (wallet.Unlock(password))
{
keyPair2 = wallet.GetAccounts().First().GetKey();
}
Using WalletAPI
Initialization
Initializing WalletAPI
:
// choose a neo node with rpc opened
RpcClient client = new RpcClient(new Uri("http://localhost:20332"), null, null, ProtocolSettings.Load("config.json"));
WalletAPI walletAPI = new WalletAPI(client);
Inquiring balance
The type of account balance is usually BigInteger, which is a representation after rounding the decimal part. It needs to be divided by Factor to get the actual Token amount.
Inquiry NEP-17 asset balance using the string parameter:
// get the neo balance of account
string tokenHash = NativeContract.NEO.Hash.ToString();
string address = "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW";
BigInteger balance = await walletAPI.GetTokenBalanceAsync(tokenHash, address).ConfigureAwait(false);
or using the parameter of ScriptHash type:
// Get the NEO balance of account
UInt160 tokenScriptHash = Utility.GetScriptHash(tokenHash, ProtocolSettings.Default);
UInt160 accountHash = Utility.GetScriptHash(address, ProtocolSettings.Default);
Nep17API nep17API = new Nep17API(client);
BigInteger balance = await nep17API.BalanceOfAsync(tokenScriptHash, accountHash).ConfigureAwait(false);
In Neo N3 NEO and GAS are both NEP17 assets with the fixed scripthash. Here we provide a simpler interface:
// Get the NEO balance
uint neoBalance = await walletAPI.GetNeoBalanceAsync(address).ConfigureAwait(false);
// Get the GAS balance
decimal gasBalance = await walletAPI.GetGasBalanceAsync(address).ConfigureAwait(false);
Claiming GAS
In Neo N3 GAS is automatically claimed when NEO is transferred. You can construct a transaction transferring to yourself to claim GAS.
-
First check the claimable GAS amount at current address:
// Get the claimable GAS of one address string address = "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW"; decimal gasAmount = await walletAPI.GetUnclaimedGasAsync(address).ConfigureAwait(false);
or use ScriptHash of the account to check:
string address = "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW"; UInt160 accountHash = Utility.GetScriptHash(address); decimal gasAmount = await walletAPI.GetUnclaimedGasAsync(accountHash).ConfigureAwait(false);
-
Construct a transaction sending NEO to yourself:
// Claiming GAS needs the KeyPair of account. You can also use wif or private key hex string string wif = "L1rFMTamZj85ENnqNLwmhXKAprHuqr1MxMHmCWCGiXGsAdQ2dnhb"; Transaction transaction = await walletAPI.ClaimGasAsync(wif).ConfigureAwait(false);
or use
KeyPair
:KeyPair keyPair = Utility.GetKeyPair(wif); Transaction transaction = await walletAPI.ClaimGasAsync(keyPair).ConfigureAwait(false);
Asset Transfer
WalletAPI
encapsulates transfer methods of NEP-17 assets.
Use string parameters:
string tokenHash = NativeContract.NEO.Hash.ToString();
string wif = "L1rFMTamZj85ENnqNLwmhXKAprHuqr1MxMHmCWCGiXGsAdQ2dnhb";
string address = "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW";
// Transfer 10 NEO from wif to address
await walletAPI.TransferAsync(tokenHash, wif, address, 10).ConfigureAwait(false);
// Print a message after the transaction is on chain
WalletAPI neoAPI = new WalletAPI(client);
await neoAPI.WaitTransactionAsync(transaction)
.ContinueWith(async (p) => Console.WriteLine($"Transaction vm state is {(await p).VMState}"));
or use KeyPair
and UInt160
(ScriptHash):
string wif = "L1rFMTamZj85ENnqNLwmhXKAprHuqr1MxMHmCWCGiXGsAdQ2dnhb";
string address = "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW";
KeyPair sender = Utility.GetKeyPair(wif);
UInt160 receiver = Utility.GetScriptHash(address, ProtocolSettings.Default);
// Transfer 10 NEO from wif to address
await walletAPI.TransferAsync(NativeContract.NEO.Hash, sender, receiver, 10).ConfigureAwait(false);
NEP17 transfer from multi-signature account:
KeyPair receiverKey = Utility.GetKeyPair("L1rFMTamZj85ENnqNLwmhXKAprHuqr1MxMHmCWCGiXGsAdQ2dnhb");
KeyPair keyPair1 = Utility.GetKeyPair("L1rFMTamZj85ENnqNLwmhXKAprHuqr1MxMHmCWCGiXGsAdQ2dnhb");
KeyPair keyPair2 = Utility.GetKeyPair("L2ynA5aq6KPJjpisXb8pGXnRvgDqYVkgC2Rw85GM51B9W33YcdiZ");
KeyPair keyPair3 = Utility.GetKeyPair("L3TbPZ3Gtqh3TTk2CWn44m9iiuUhBGZWoDJQuvVw5Zbx5NAjPbdb");
KeyPair keyPair4 = Utility.GetKeyPair("L3Ke1RSBycXmRukv27L6o7sQWzDwDbFcbfR9oBBwXbCKHdBvb4ZM");
//make transaction
Transaction tx = await walletAPI.TransferAsync(NativeContract.GAS.Hash, 3, new ECPoint[] { keyPair1.PublicKey, keyPair2.PublicKey, keyPair3.PublicKey, keyPair4.PublicKey }, new KeyPair[] { keyPair1, keyPair2, keyPair3 }, Contract.CreateSignatureContract(receiverKey.PublicKey).ScriptHash, 10 * NativeContract.GAS.Factor).ConfigureAwait(false);