1 | # @iov/cli
|
2 |
|
3 | [![npm version](https://img.shields.io/npm/v/@iov/cli.svg)](https://www.npmjs.com/package/@iov/cli)
|
4 |
|
5 | ## Installation and first run
|
6 |
|
7 | The `iov-cli` executable is available via npm. We recommend local installations
|
8 | to your demo project. If you don't have one yet, just
|
9 | `mkdir iov-cli-installation && cd iov-cli-installation && yarn init -y`.
|
10 |
|
11 | ### locally with yarn
|
12 |
|
13 | ```
|
14 | $ yarn add @iov/cli --dev
|
15 | $ ./node_modules/.bin/iov-cli
|
16 | ```
|
17 |
|
18 | ### locally with npm
|
19 |
|
20 | ```
|
21 | $ npm install @iov/cli --save-dev
|
22 | $ ./node_modules/.bin/iov-cli
|
23 | ```
|
24 |
|
25 | ### globally with yarn
|
26 |
|
27 | ```
|
28 | $ yarn global add @iov/cli
|
29 | $ iov-cli
|
30 | ```
|
31 |
|
32 | ### globally with npm
|
33 |
|
34 | ```
|
35 | $ npm install -g @iov/cli
|
36 | $ iov-cli
|
37 | ```
|
38 |
|
39 | ## How to use the IOV-Core command line interface
|
40 |
|
41 | 1. Install `@iov/cli` and run `iov-cli` as shown above
|
42 | 2. Start a local BNS blockchain as described in
|
43 | [scripts/bnsd/README.md](https://github.com/iov-one/iov-core/tree/master/scripts/bnsd/README.md)
|
44 | 3. Play around as in the following example code:
|
45 |
|
46 | ```
|
47 | > const profile = new UserProfile();
|
48 | > const signer = new MultiChainSigner(profile);
|
49 | > const { connection } = await signer.addChain(createBnsConnector("ws://localhost:23456"));
|
50 | > const chainId = connection.chainId();
|
51 |
|
52 | > chainId
|
53 | 'test-chain-esuZ1V'
|
54 |
|
55 | > const wallet = profile.addWallet(Ed25519HdWallet.fromMnemonic("degree tackle suggest window test behind mesh extra cover prepare oak script"));
|
56 |
|
57 | > profile.getIdentities(wallet.id)
|
58 | []
|
59 |
|
60 | > const faucet = await profile.createIdentity(wallet.id, chainId, HdPaths.iov(0))
|
61 |
|
62 | > faucet.pubkey
|
63 | { algo: 'ed25519',
|
64 | data:
|
65 | Uint8Array [
|
66 | 224,
|
67 | 42, ...
|
68 |
|
69 | > profile.setIdentityLabel(faucet, "blockchain of value faucet")
|
70 |
|
71 | > profile.getIdentities(wallet.id)
|
72 | [ { chainId: 'test-chain-esuZ1V',
|
73 | pubkey: { algo: 'ed25519', data: [Uint8Array] } } ]
|
74 |
|
75 | > const faucetAddress = signer.identityToAddress(faucet);
|
76 | > faucetAddress
|
77 | 'tiov1k898u78hgs36uqw68dg7va5nfkgstu5z0fhz3f'
|
78 | > (await connection.getAccount({ address: faucetAddress })).balance
|
79 |
|
80 | > const recipient = await profile.createIdentity(wallet.id, chainId, HdPaths.iov(1));
|
81 | > const recipientAddress = signer.identityToAddress(recipient);
|
82 |
|
83 | > .editor
|
84 | const sendTx = await connection.withDefaultFee<SendTransaction & WithCreator>({
|
85 | kind: "bcp/send",
|
86 | creator: faucet,
|
87 | recipient: recipientAddress,
|
88 | memo: "My first transaction",
|
89 | amount: {
|
90 | quantity: "33123456789",
|
91 | fractionalDigits: 9,
|
92 | tokenTicker: "CASH" as TokenTicker,
|
93 | },
|
94 | });
|
95 | ^D
|
96 | > await signer.signAndPost(sendTx);
|
97 | > (await connection.getAccount({ address: recipientAddress })).balance;
|
98 |
|
99 | > await connection.searchTx({ sentFromOrTo: faucetAddress });
|
100 | > await connection.searchTx({ sentFromOrTo: recipientAddress });
|
101 | ```
|
102 |
|
103 | 3. Congratulations, you sent your first money!
|
104 | 4. Add an additional wallet
|
105 |
|
106 | ```
|
107 | > profile.wallets.value
|
108 | [ { id: 'ReYESw51lsOOr8_X', label: undefined } ]
|
109 |
|
110 | > const wallet2 = profile.addWallet(Secp256k1HdWallet.fromMnemonic("organ wheat manage mirror wish truly tool trumpet since equip flight bracket"))
|
111 |
|
112 | > profile.wallets.value
|
113 | [ { id: 'ReYESw51lsOOr8_X', label: undefined },
|
114 | { id: 'FtIcQqMWcRpEIruk', label: undefined } ]
|
115 |
|
116 | > profile.getIdentities(wallet.id)
|
117 | [ { chainId: 'test-chain-esuZ1V',
|
118 | pubkey: { algo: 'ed25519', data: [Uint8Array] } } ]
|
119 |
|
120 | > profile.getIdentities(wallet2.id)
|
121 | []
|
122 |
|
123 | > profile.setWalletLabel(wallet.id, "ed")
|
124 | > profile.setWalletLabel(wallet2.id, "secp")
|
125 |
|
126 | > profile.wallets.value
|
127 | [ { id: 'ReYESw51lsOOr8_X', label: 'ed' },
|
128 | { id: 'FtIcQqMWcRpEIruk', label: 'secp' } ]
|
129 | ```
|
130 |
|
131 | 5. Now store to disk
|
132 |
|
133 | ```
|
134 | > const db = levelup(leveldown('./my_userprofile_db'))
|
135 | > await profile.storeIn(db, "secret passwd")
|
136 | ```
|
137 |
|
138 | 6. and restore
|
139 |
|
140 | ```
|
141 | > const profileFromDb = await UserProfile.loadFrom(db, "secret passwd");
|
142 | > profileFromDb
|
143 | UserProfile {
|
144 | createdAt: 2018-07-04T16:07:14.583Z,
|
145 | keyring:
|
146 | Keyring { wallets: [ [Ed25519HdWallet], [Secp256k1HdWallet] ] },
|
147 | ...
|
148 | ```
|
149 |
|
150 | ### Register a username on the IOV Name Service
|
151 |
|
152 | Assuming you have a `profile`, a `signer` and a `recipient` identity with
|
153 | transactions associated from above
|
154 |
|
155 | ```
|
156 | > .editor
|
157 | const registrationTx = await connection.withDefaultFee<RegisterUsernameTx & WithCreator>({
|
158 | kind: "bns/register_username",
|
159 | creator: recipient,
|
160 | targets: [],
|
161 | username: "hans*iov",
|
162 | });
|
163 | ^D
|
164 | > await signer.signAndPost(registrationTx);
|
165 | > const bnsConnection = connection as BnsConnection;
|
166 | > await bnsConnection.getUsernames({ owner: recipientAddress });
|
167 | [ { username: 'hans*iov',
|
168 | owner: 'tiov14cn8m57wtrlewmlnjucctsahpnxlj92l0crkvq',
|
169 | targets: [] } ]
|
170 | > await bnsConnection.getUsernames({ username: "hans*iov" });
|
171 | [ { username: 'hans*iov',
|
172 | owner: 'tiov14cn8m57wtrlewmlnjucctsahpnxlj92l0crkvq',
|
173 | targets: [] } ]
|
174 | ```
|
175 |
|
176 | ### Disconnecting
|
177 |
|
178 | When you are done using a WebSocket connection, disconnect the connection
|
179 |
|
180 | ```
|
181 | > (await connection.getAccount({ address: faucetAddress })).balance
|
182 | [ { quantity: '123456755876543211',
|
183 | fractionalDigits: 9,
|
184 | tokenTicker: 'CASH' } ]
|
185 | > connection.disconnect()
|
186 | undefined
|
187 | > (await connection.getAccount({ address: faucetAddress })).balance
|
188 | Error: Socket was closed, so no data can be sent anymore.
|
189 | at ...
|
190 | ```
|
191 |
|
192 | ## Faucet usage
|
193 |
|
194 | When using a Testnet, you can use the IovFaucet to receive tokens.
|
195 |
|
196 | In this example we connect to a public test network.
|
197 |
|
198 | ```
|
199 | > const mnemonic = Bip39.encode(Random.getBytes(16)).toString();
|
200 | > mnemonic
|
201 | 'helmet album grow detail apology thank wire chef fame core private cargo'
|
202 | > const profile = new UserProfile();
|
203 | > const wallet = profile.addWallet(Ed25519HdWallet.fromMnemonic(mnemonic));
|
204 |
|
205 | > const signer = new MultiChainSigner(profile);
|
206 | > const { connection } = await signer.addChain(createBnsConnector("https://rpc.lovenet.iov.one"));
|
207 | > const chainId = connection.chainId();
|
208 |
|
209 | > const alice = await profile.createIdentity(wallet.id, chainId, HdPaths.iov(0));
|
210 | > const aliceAddress = signer.identityToAddress(alice);
|
211 |
|
212 | > const faucet = new IovFaucet("https://bns-faucet.lovenet.iov.one/");
|
213 |
|
214 | > await faucet.credit(aliceAddress, "IOV" as TokenTicker)
|
215 | > (await connection.getAccount({ address: aliceAddress })).balance
|
216 | [ { quantity: '10000000000',
|
217 | fractionalDigits: 9,
|
218 | tokenTicker: 'IOV' } ]
|
219 | ```
|
220 |
|
221 | ## License
|
222 |
|
223 | This package is part of the IOV-Core repository, licensed under the Apache
|
224 | License 2.0 (see
|
225 | [NOTICE](https://github.com/iov-one/iov-core/blob/master/NOTICE) and
|
226 | [LICENSE](https://github.com/iov-one/iov-core/blob/master/LICENSE)).
|