react-native-zano 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ export declare const tmpPath: string;
2
+ /**
3
+ * Clones a git repo and checks our a hash.
4
+ */
5
+ export declare function getRepo(name: string, uri: string, hash: string): Promise<void>;
6
+ /**
7
+ * Downloads & unpacks a zip file.
8
+ */
9
+ export declare function getZip(name: string, uri: string): Promise<void>;
10
+ export declare function fileExists(path: string): Promise<boolean>;
11
+ export declare function loudExec(command: string, args: string[], opts?: {
12
+ cwd?: string;
13
+ }): Promise<void>;
14
+ /**
15
+ * Runs a command and returns its results.
16
+ */
17
+ export declare function quietExec(command: string, args: string[], opts?: {
18
+ cwd?: string;
19
+ }): Promise<string>;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.quietExec = exports.loudExec = exports.fileExists = exports.getZip = exports.getRepo = exports.tmpPath = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const promises_1 = require("fs/promises");
6
+ const path_1 = require("path");
7
+ exports.tmpPath = (0, path_1.join)(__dirname, '../../tmp');
8
+ /**
9
+ * Clones a git repo and checks our a hash.
10
+ */
11
+ async function getRepo(name, uri, hash) {
12
+ const path = (0, path_1.join)(exports.tmpPath, name);
13
+ // Clone (if needed):
14
+ if (!(await fileExists(path))) {
15
+ console.log(`Cloning ${name}...`);
16
+ await loudExec('git', ['clone', uri, name]);
17
+ }
18
+ // Checkout:
19
+ console.log(`Checking out ${name}...`);
20
+ await loudExec('git', ['checkout', '-f', hash], { cwd: path });
21
+ // Checkout submodules:
22
+ await loudExec('git', ['submodule', 'update', '--init', '--recursive'], {
23
+ cwd: path
24
+ });
25
+ }
26
+ exports.getRepo = getRepo;
27
+ /**
28
+ * Downloads & unpacks a zip file.
29
+ */
30
+ async function getZip(name, uri) {
31
+ const path = (0, path_1.join)(exports.tmpPath, name);
32
+ if (!(await fileExists(path))) {
33
+ console.log(`Getting ${name}...`);
34
+ await loudExec('curl', ['-L', '-o', path, uri]);
35
+ }
36
+ // Unzip:
37
+ await loudExec('unzip', ['-u', path]);
38
+ }
39
+ exports.getZip = getZip;
40
+ async function fileExists(path) {
41
+ return await (0, promises_1.access)(path).then(() => true, () => false);
42
+ }
43
+ exports.fileExists = fileExists;
44
+ async function loudExec(command, args, opts = {}) {
45
+ const { cwd = exports.tmpPath } = opts;
46
+ return await new Promise((resolve, reject) => {
47
+ const child = (0, child_process_1.spawn)(command, args, {
48
+ cwd,
49
+ stdio: 'inherit',
50
+ env: process.env
51
+ });
52
+ child.on('error', reject);
53
+ child.on('exit', code => {
54
+ if (code === 0) {
55
+ resolve();
56
+ }
57
+ else {
58
+ reject(new Error(`${command} exited with code ${String(code)}`));
59
+ }
60
+ });
61
+ });
62
+ }
63
+ exports.loudExec = loudExec;
64
+ /**
65
+ * Runs a command and returns its results.
66
+ */
67
+ async function quietExec(command, args, opts = {}) {
68
+ const { cwd = exports.tmpPath } = opts;
69
+ return (0, child_process_1.execSync)(command + ' ' + args.join(' '), {
70
+ cwd,
71
+ encoding: 'utf8'
72
+ }).replace(/\n$/, '');
73
+ }
74
+ exports.quietExec = quietExec;
@@ -0,0 +1,69 @@
1
+ import { AddressInfo, AsyncCallResponse, CloseResponse, ConnectivityStatus, FeePriority, GetBalancesResponse, GetRecentTransactionsResponse, GetSeedPhraseInfo, JsonRpc, ReturnCode, TryPullResultResponse, WalletDetails, WalletFiles, WalletInfoExtended, WalletStatus } from './types';
2
+ /**
3
+ * The shape of the native C++ module exposed to React Native.
4
+ *
5
+ * You do not normally need this, but it is accessible as
6
+ * `require('react-native').NativeModules.ZanoModule`.
7
+ *
8
+ * Pass this object to the `CppBridge` constructor to re-assemble the API.
9
+ */
10
+ export interface NativeZanoModule {
11
+ readonly callZano: (name: string, jsonArguments: string[]) => Promise<string>;
12
+ readonly methodNames: string[];
13
+ readonly documentDirectory: string;
14
+ }
15
+ export declare class CppBridge {
16
+ private readonly module;
17
+ constructor(zanoModule: NativeZanoModule);
18
+ init(rpcAddress: string, logLevel: number): Promise<JsonRpc<ReturnCode>>;
19
+ initWithIpPort(ip: string, port: string, logLevel: number): Promise<JsonRpc<ReturnCode>>;
20
+ reset(): Promise<JsonRpc<ReturnCode>>;
21
+ setLogLevel(logLevel: number): Promise<string>;
22
+ getVersion(): Promise<string>;
23
+ getWalletFiles(): Promise<WalletFiles | {}>;
24
+ getExportPrivateInfo(targetDir: string): Promise<JsonRpc<ReturnCode>>;
25
+ deleteWallet(fileName: string): Promise<JsonRpc<ReturnCode>>;
26
+ getAddressInfo(addr: string): Promise<AddressInfo>;
27
+ getAppconfig(encryptionKey: string): Promise<object>;
28
+ setAppconfig(confStr: string, encryptionKey: string): Promise<JsonRpc<ReturnCode>>;
29
+ generateRandomKey(length: number): Promise<string>;
30
+ getLogsBuffer(): Promise<string>;
31
+ truncateLog(): Promise<JsonRpc<ReturnCode>>;
32
+ getConnectivityStatus(): Promise<ConnectivityStatus>;
33
+ open(path: string, password: string): Promise<JsonRpc<WalletDetails>>;
34
+ restore(seed: string, path: string, password: string, seedPassword: string): Promise<JsonRpc<WalletDetails>>;
35
+ generate(path: string, password: string): Promise<JsonRpc<WalletDetails>>;
36
+ getOpenedWallets(): Promise<JsonRpc<WalletDetails[]>>;
37
+ getWalletStatus(walletId: number): Promise<WalletStatus>;
38
+ closeWallet(walletId: number): Promise<CloseResponse>;
39
+ invoke(walletId: number, params: string): Promise<string>;
40
+ asyncCall(methodName: string, instanceId: number, params: string): Promise<AsyncCallResponse>;
41
+ tryPullResult<T>(arg: number): Promise<TryPullResultResponse<T>>;
42
+ syncCall(methodName: string, instanceId: number, params: string): Promise<string>;
43
+ isWalletExist(path: string): Promise<boolean>;
44
+ getWalletInfo(walletId: number): Promise<{
45
+ wi: WalletDetails['wi'];
46
+ wi_extended: WalletInfoExtended;
47
+ }>;
48
+ resetWalletPassword(walletId: number, password: string): Promise<string>;
49
+ getCurrentTxFee(priority: FeePriority): Promise<number>;
50
+ getSeedPhraseInfo(seed: string, seedPassword: string): Promise<GetSeedPhraseInfo>;
51
+ generateSeedPhrase(rpcAddress: string, storagePath: string, seedPassword: string, logLevel?: number): Promise<WalletDetails>;
52
+ startWallet(mnemonicSeed: string, seedPassword: string, storagePath: string): Promise<WalletDetails>;
53
+ stopWallet(walletId: number): Promise<string>;
54
+ removeWallet(walletId: number): Promise<void>;
55
+ walletStatus(walletId: number): Promise<WalletStatus>;
56
+ getBalances(walletId: number): Promise<GetBalancesResponse>;
57
+ getTransactions(walletId: number, offset?: number): Promise<GetRecentTransactionsResponse>;
58
+ whitelistAssets(walletId: number, assetIds: string[]): Promise<void>;
59
+ transfer(walletId: number, transferOpts: {
60
+ assetId: string;
61
+ fee: number;
62
+ nativeAmount: number;
63
+ recipient: string;
64
+ comment?: string;
65
+ paymentId?: string;
66
+ }): Promise<string>;
67
+ private handleRpcResponse;
68
+ private _asyncCallWithRetry;
69
+ }
@@ -0,0 +1,328 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CppBridge = void 0;
4
+ const types_1 = require("./types");
5
+ class CppBridge {
6
+ constructor(zanoModule) {
7
+ this.module = zanoModule;
8
+ }
9
+ // -----------------------------------------------------------------------------
10
+ // Raw API
11
+ // -----------------------------------------------------------------------------
12
+ async init(rpcAddress, logLevel) {
13
+ const response = await this.module.callZano('init', [
14
+ rpcAddress,
15
+ this.module.documentDirectory,
16
+ logLevel.toFixed()
17
+ ]);
18
+ return JSON.parse(response);
19
+ }
20
+ async initWithIpPort(ip, port, logLevel) {
21
+ const response = await this.module.callZano('initWithIpPort', [
22
+ ip,
23
+ port,
24
+ this.module.documentDirectory,
25
+ logLevel.toFixed()
26
+ ]);
27
+ return JSON.parse(response);
28
+ }
29
+ async reset() {
30
+ const response = await this.module.callZano('reset', []);
31
+ return JSON.parse(response);
32
+ }
33
+ async setLogLevel(logLevel) {
34
+ return await this.module.callZano('setLogLevel', [logLevel.toFixed()]);
35
+ }
36
+ async getVersion() {
37
+ return await this.module.callZano('getVersion', []);
38
+ }
39
+ async getWalletFiles() {
40
+ const files = await this.module.callZano('getWalletFiles', []);
41
+ return JSON.parse(files);
42
+ }
43
+ async getExportPrivateInfo(targetDir) {
44
+ const response = await this.module.callZano('getExportPrivateInfo', [
45
+ targetDir
46
+ ]);
47
+ return JSON.parse(response);
48
+ }
49
+ async deleteWallet(fileName) {
50
+ const response = await this.module.callZano('deleteWallet', [fileName]);
51
+ return JSON.parse(response);
52
+ }
53
+ async getAddressInfo(addr) {
54
+ const response = await this.module.callZano('getAddressInfo', [addr]);
55
+ return JSON.parse(response);
56
+ }
57
+ async getAppconfig(encryptionKey) {
58
+ const response = await this.module.callZano('getAppconfig', [encryptionKey]);
59
+ return JSON.parse(response);
60
+ }
61
+ async setAppconfig(confStr, encryptionKey) {
62
+ const response = await this.module.callZano('setAppconfig', [
63
+ confStr,
64
+ encryptionKey
65
+ ]);
66
+ return JSON.parse(response);
67
+ }
68
+ async generateRandomKey(length) {
69
+ return await this.module.callZano('generateRandomKey', [length.toFixed()]);
70
+ }
71
+ async getLogsBuffer() {
72
+ return await this.module.callZano('getLogsBuffer', []);
73
+ }
74
+ async truncateLog() {
75
+ const response = await this.module.callZano('truncateLog', []);
76
+ return JSON.parse(response);
77
+ }
78
+ async getConnectivityStatus() {
79
+ const response = await this.module.callZano('getConnectivityStatus', []);
80
+ return JSON.parse(response);
81
+ }
82
+ async open(path, password) {
83
+ const response = await this.module.callZano('open', [path, password]);
84
+ return JSON.parse(response);
85
+ }
86
+ async restore(seed, path, password, seedPassword) {
87
+ const response = await this.module.callZano('restore', [
88
+ seed,
89
+ path,
90
+ password,
91
+ seedPassword
92
+ ]);
93
+ return JSON.parse(response);
94
+ }
95
+ async generate(path, password) {
96
+ const response = await this.module.callZano('generate', [path, password]);
97
+ return JSON.parse(response);
98
+ }
99
+ async getOpenedWallets() {
100
+ const response = await this.module.callZano('getOpenedWallets', []);
101
+ return JSON.parse(response);
102
+ }
103
+ async getWalletStatus(walletId) {
104
+ const response = await this.module.callZano('getWalletStatus', [
105
+ walletId.toFixed()
106
+ ]);
107
+ return JSON.parse(response);
108
+ }
109
+ async closeWallet(walletId) {
110
+ const response = await this.module.callZano('closeWallet', [
111
+ walletId.toFixed()
112
+ ]);
113
+ return JSON.parse(response);
114
+ }
115
+ async invoke(walletId, params) {
116
+ return await this.module.callZano('invoke', [walletId.toFixed(), params]);
117
+ }
118
+ async asyncCall(methodName, instanceId, params) {
119
+ const response = await this.module.callZano('asyncCall', [
120
+ methodName,
121
+ instanceId.toFixed(),
122
+ params
123
+ ]);
124
+ return JSON.parse(response);
125
+ }
126
+ async tryPullResult(arg) {
127
+ const response = await this.module.callZano('tryPullResult', [
128
+ arg.toFixed()
129
+ ]);
130
+ return JSON.parse(response);
131
+ }
132
+ async syncCall(methodName, instanceId, params) {
133
+ return await this.module.callZano('syncCall', [
134
+ methodName,
135
+ instanceId.toFixed(),
136
+ params
137
+ ]);
138
+ }
139
+ async isWalletExist(path) {
140
+ const response = await this.module.callZano('isWalletExist', [
141
+ this.module.documentDirectory + '/wallets/' + path
142
+ ]);
143
+ return response === '1';
144
+ }
145
+ async getWalletInfo(walletId) {
146
+ const response = await this.module.callZano('getWalletInfo', [
147
+ walletId.toFixed()
148
+ ]);
149
+ return JSON.parse(response);
150
+ }
151
+ async resetWalletPassword(walletId, password) {
152
+ return await this.module.callZano('resetWalletPassword', [
153
+ walletId.toFixed(),
154
+ password
155
+ ]);
156
+ }
157
+ // 0 (default), 1 (unimportant), 2 (normal), 3 (elevated), 4 (priority)
158
+ async getCurrentTxFee(priority) {
159
+ const fee = await this.module.callZano('getCurrentTxFee', [
160
+ priority.toFixed()
161
+ ]);
162
+ return parseInt(fee);
163
+ }
164
+ // -----------------------------------------------------------------------------
165
+ // Convenience API
166
+ // -----------------------------------------------------------------------------
167
+ async getSeedPhraseInfo(seed, seedPassword) {
168
+ const params = {
169
+ seed_phrase: seed,
170
+ seed_password: seedPassword
171
+ };
172
+ const seedInfo = await this._asyncCallWithRetry('get_seed_phrase_info', 0, JSON.stringify(params));
173
+ return seedInfo;
174
+ }
175
+ async generateSeedPhrase(rpcAddress, storagePath, seedPassword, logLevel = -1) {
176
+ await this.init(rpcAddress, logLevel);
177
+ const response = await this.generate(storagePath, seedPassword);
178
+ const result = this.handleRpcResponse(response);
179
+ await this.closeWallet(result.wallet_id);
180
+ return result;
181
+ }
182
+ async startWallet(mnemonicSeed, seedPassword, storagePath) {
183
+ const files = await this.getWalletFiles();
184
+ let items = [];
185
+ if ('items' in files) {
186
+ items = files.items;
187
+ }
188
+ if (!items.includes(storagePath)) {
189
+ const response = await this.restore(mnemonicSeed, storagePath, seedPassword, seedPassword);
190
+ const result = this.handleRpcResponse(response);
191
+ return result;
192
+ }
193
+ else {
194
+ const response = await this.open(storagePath, seedPassword);
195
+ const result = this.handleRpcResponse(response);
196
+ return result;
197
+ }
198
+ }
199
+ async stopWallet(walletId) {
200
+ const closeResponse = await this._asyncCallWithRetry('close', walletId, '');
201
+ if (closeResponse.return_code !== 'OK') {
202
+ throw new Error(`${closeResponse.return_code}`);
203
+ }
204
+ return closeResponse.return_code;
205
+ }
206
+ async removeWallet(walletId) {
207
+ const response = await this.getOpenedWallets();
208
+ const result = this.handleRpcResponse(response);
209
+ const wallet = result.find(w => w.wallet_id === walletId);
210
+ if (wallet == null)
211
+ return;
212
+ await this.stopWallet(walletId);
213
+ await this.deleteWallet(wallet.wi.path);
214
+ }
215
+ async walletStatus(walletId) {
216
+ const walletStatus = await this._asyncCallWithRetry('get_wallet_status', walletId, '');
217
+ return walletStatus;
218
+ }
219
+ async getBalances(walletId) {
220
+ const params = {
221
+ method: 'getbalance'
222
+ };
223
+ const response = await this._asyncCallWithRetry('invoke', walletId, JSON.stringify(params));
224
+ const result = this.handleRpcResponse(response);
225
+ return result;
226
+ }
227
+ async getTransactions(walletId, offset = 0) {
228
+ const params = {
229
+ method: 'get_recent_txs_and_info2',
230
+ params: {
231
+ count: 100,
232
+ exclude_mining_txs: true,
233
+ exclude_unconfirmed: false,
234
+ offset,
235
+ order: 'FROM_BEGIN_TO_END',
236
+ update_provision_info: true
237
+ }
238
+ };
239
+ const response = await this._asyncCallWithRetry('invoke', walletId, JSON.stringify(params));
240
+ const result = this.handleRpcResponse(response);
241
+ return result;
242
+ }
243
+ async whitelistAssets(walletId, assetIds) {
244
+ const currentWhitelistParams = {
245
+ method: 'assets_whitelist_get',
246
+ params: {}
247
+ };
248
+ const whitelistAssetsResponse = await this._asyncCallWithRetry('invoke', walletId, JSON.stringify(currentWhitelistParams));
249
+ let whitelistSet = new Set();
250
+ if ('local_whitelist' in whitelistAssetsResponse) {
251
+ whitelistSet = new Set(whitelistAssetsResponse.local_whitelist.map(asset => asset.asset_id));
252
+ }
253
+ for (const assetId of assetIds) {
254
+ if (!whitelistSet.has(assetId)) {
255
+ const addAssetParams = {
256
+ method: 'assets_whitelist_add',
257
+ params: {
258
+ asset_id: assetId
259
+ }
260
+ };
261
+ await this._asyncCallWithRetry('invoke', walletId, JSON.stringify(addAssetParams));
262
+ }
263
+ }
264
+ }
265
+ async transfer(walletId, transferOpts) {
266
+ const params = {
267
+ method: 'transfer',
268
+ params: {
269
+ comment: transferOpts.comment,
270
+ destinations: [
271
+ {
272
+ address: transferOpts.recipient,
273
+ amount: transferOpts.nativeAmount,
274
+ asset_id: transferOpts.assetId
275
+ }
276
+ ],
277
+ fee: transferOpts.fee,
278
+ hide_receiver: true,
279
+ mixin: 15,
280
+ payment_id: transferOpts.paymentId ?? '',
281
+ push_payer: false,
282
+ service_entries_permanent: true
283
+ }
284
+ };
285
+ const response = await this._asyncCallWithRetry('invoke', walletId, JSON.stringify(params));
286
+ const result = this.handleRpcResponse(response);
287
+ return result.tx_hash;
288
+ }
289
+ // -----------------------------------------------------------------------------
290
+ // Utils
291
+ // -----------------------------------------------------------------------------
292
+ handleRpcResponse(json) {
293
+ if ('result' in json) {
294
+ return json.result;
295
+ }
296
+ else if ('error' in json) {
297
+ throw new Error(`${json.error.code} ${json.error.message}`);
298
+ }
299
+ else {
300
+ throw new Error('Unknown error');
301
+ }
302
+ }
303
+ async _asyncCallWithRetry(methodName, instanceId, params) {
304
+ while (true) {
305
+ const jobIdResponse = await this.asyncCall(methodName, instanceId, params);
306
+ while (true) {
307
+ const tryPullResponse = await this.tryPullResult(jobIdResponse.job_id);
308
+ await new Promise(resolve => setTimeout(resolve, 100)); // 100 ms recommended by documentation
309
+ if (tryPullResponse.status === 'idle') {
310
+ // try this again. job ID is still valid
311
+ continue;
312
+ }
313
+ else if (tryPullResponse.status === 'delivered') {
314
+ const error = (0, types_1.asMaybeBusy)(tryPullResponse.result);
315
+ if (error != null) {
316
+ // try this again. job ID is no longer valid
317
+ break;
318
+ }
319
+ return tryPullResponse.result;
320
+ }
321
+ else if (tryPullResponse.status === 'canceled') {
322
+ throw new Error(`${methodName} job canceled`);
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ exports.CppBridge = CppBridge;
@@ -0,0 +1,4 @@
1
+ import { CppBridge, NativeZanoModule } from './CppBridge';
2
+ export declare function makeZano(): CppBridge;
3
+ export type { CppBridge, NativeZanoModule };
4
+ export * from './types';
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.makeZano = void 0;
18
+ const react_native_1 = require("react-native");
19
+ const CppBridge_1 = require("./CppBridge");
20
+ function makeZano() {
21
+ const { ZanoModule } = react_native_1.NativeModules;
22
+ if (ZanoModule == null) {
23
+ throw new Error('react-native-zano native module not linked');
24
+ }
25
+ return new CppBridge_1.CppBridge(ZanoModule);
26
+ }
27
+ exports.makeZano = makeZano;
28
+ __exportStar(require("./types"), exports);