Browse Source

docs

master
jojapoppa 5 months ago
parent
commit
ff2bf27988
100 changed files with 25502 additions and 188 deletions
  1. +0
    -1
      .gitignore
  2. +9
    -187
      README.md
  3. +11
    -0
      dist/lib/Assert.d.ts
  4. +56
    -0
      dist/lib/Assert.js
  5. +9
    -0
      dist/lib/CnUtils.d.ts
  6. +60
    -0
      dist/lib/CnUtils.js
  7. +300
    -0
      dist/lib/Config.d.ts
  8. +186
    -0
      dist/lib/Config.js
  9. +83
    -0
      dist/lib/Constants.d.ts
  10. +136
    -0
      dist/lib/Constants.js
  11. +5
    -0
      dist/lib/CryptoWrapper.d.ts
  12. +72
    -0
      dist/lib/CryptoWrapper.js
  13. +240
    -0
      dist/lib/Daemon.d.ts
  14. +519
    -0
      dist/lib/Daemon.js
  15. +33
    -0
      dist/lib/FeeType.d.ts
  16. +55
    -0
      dist/lib/FeeType.js
  17. +75
    -0
      dist/lib/JsonSerialization.d.ts
  18. +22
    -0
      dist/lib/JsonSerialization.js
  19. +68
    -0
      dist/lib/Logger.d.ts
  20. +157
    -0
      dist/lib/Logger.js
  21. +41
    -0
      dist/lib/Metronome.d.ts
  22. +93
    -0
      dist/lib/Metronome.js
  23. +30
    -0
      dist/lib/MixinLimits.d.ts
  24. +63
    -0
      dist/lib/MixinLimits.js
  25. +9
    -0
      dist/lib/OpenWallet.d.ts
  26. +27
    -0
      dist/lib/OpenWallet.js
  27. +118
    -0
      dist/lib/SubWallet.d.ts
  28. +322
    -0
      dist/lib/SubWallet.js
  29. +219
    -0
      dist/lib/SubWallets.d.ts
  30. +723
    -0
      dist/lib/SubWallets.js
  31. +14
    -0
      dist/lib/SynchronizationStatus.d.ts
  32. +65
    -0
      dist/lib/SynchronizationStatus.js
  33. +91
    -0
      dist/lib/Transfer.d.ts
  34. +875
    -0
      dist/lib/Transfer.js
  35. +218
    -0
      dist/lib/Types.d.ts
  36. +274
    -0
      dist/lib/Types.js
  37. +110
    -0
      dist/lib/Utilities.d.ts
  38. +327
    -0
      dist/lib/Utilities.js
  39. +94
    -0
      dist/lib/ValidateParameters.d.ts
  40. +274
    -0
      dist/lib/ValidateParameters.js
  41. +1589
    -0
      dist/lib/WalletBackend.d.ts
  42. +2254
    -0
      dist/lib/WalletBackend.js
  43. +56
    -0
      dist/lib/WalletEncryption.d.ts
  44. +128
    -0
      dist/lib/WalletEncryption.js
  45. +109
    -0
      dist/lib/WalletError.d.ts
  46. +514
    -0
      dist/lib/WalletError.js
  47. +118
    -0
      dist/lib/WalletSynchronizer.d.ts
  48. +485
    -0
      dist/lib/WalletSynchronizer.js
  49. +1
    -0
      dist/lib/WordList.d.ts
  50. +1634
    -0
      dist/lib/WordList.js
  51. +10
    -0
      dist/lib/index.d.ts
  52. +40
    -0
      dist/lib/index.js
  53. +17
    -0
      dist/modules/fedoragold-base58/src/base58.d.ts
  54. +258
    -0
      dist/modules/fedoragold-base58/src/base58.js
  55. +1
    -0
      dist/modules/fedoragold-base58/test/test.d.ts
  56. +21
    -0
      dist/modules/fedoragold-base58/test/test.js
  57. +5
    -0
      dist/modules/fedoragold-bytestream/src/index.d.ts
  58. +14
    -0
      dist/modules/fedoragold-bytestream/src/index.js
  59. +177
    -0
      dist/modules/fedoragold-bytestream/src/reader.d.ts
  60. +415
    -0
      dist/modules/fedoragold-bytestream/src/reader.js
  61. +19
    -0
      dist/modules/fedoragold-bytestream/src/varint.d.ts
  62. +53
    -0
      dist/modules/fedoragold-bytestream/src/varint.js
  63. +139
    -0
      dist/modules/fedoragold-bytestream/src/writer.d.ts
  64. +377
    -0
      dist/modules/fedoragold-bytestream/src/writer.js
  65. +1
    -0
      dist/modules/fedoragold-bytestream/test/test.d.ts
  66. +445
    -0
      dist/modules/fedoragold-bytestream/test/test.js
  67. +1
    -0
      dist/modules/fedoragold-crypto/tests/crypto.d.ts
  68. +733
    -0
      dist/modules/fedoragold-crypto/tests/crypto.js
  69. +112
    -0
      dist/modules/fedoragold-crypto/typescript/Interfaces.d.ts
  70. +19
    -0
      dist/modules/fedoragold-crypto/typescript/Interfaces.js
  71. +445
    -0
      dist/modules/fedoragold-crypto/typescript/index.d.ts
  72. +1488
    -0
      dist/modules/fedoragold-crypto/typescript/index.js
  73. +139
    -0
      dist/modules/fedoragold-utils/src/Address.d.ts
  74. +341
    -0
      dist/modules/fedoragold-utils/src/Address.js
  75. +45
    -0
      dist/modules/fedoragold-utils/src/AddressPrefix.d.ts
  76. +93
    -0
      dist/modules/fedoragold-utils/src/AddressPrefix.js
  77. +131
    -0
      dist/modules/fedoragold-utils/src/Block.d.ts
  78. +465
    -0
      dist/modules/fedoragold-utils/src/Block.js
  79. +90
    -0
      dist/modules/fedoragold-utils/src/BlockTemplate.d.ts
  80. +203
    -0
      dist/modules/fedoragold-utils/src/BlockTemplate.js
  81. +15
    -0
      dist/modules/fedoragold-utils/src/Common.d.ts
  82. +95
    -0
      dist/modules/fedoragold-utils/src/Common.js
  83. +45
    -0
      dist/modules/fedoragold-utils/src/Config.d.ts
  84. +27
    -0
      dist/modules/fedoragold-utils/src/Config.js
  85. +236
    -0
      dist/modules/fedoragold-utils/src/CryptoNote.d.ts
  86. +813
    -0
      dist/modules/fedoragold-utils/src/CryptoNote.js
  87. +38
    -0
      dist/modules/fedoragold-utils/src/Helpers/HTTPClient.d.ts
  88. +189
    -0
      dist/modules/fedoragold-utils/src/Helpers/HTTPClient.js
  89. +289
    -0
      dist/modules/fedoragold-utils/src/LedgerDevice.d.ts
  90. +834
    -0
      dist/modules/fedoragold-utils/src/LedgerDevice.js
  91. +249
    -0
      dist/modules/fedoragold-utils/src/LedgerNote.d.ts
  92. +953
    -0
      dist/modules/fedoragold-utils/src/LedgerNote.js
  93. +229
    -0
      dist/modules/fedoragold-utils/src/LegacyTurtleCoind.d.ts
  94. +798
    -0
      dist/modules/fedoragold-utils/src/LegacyTurtleCoind.js
  95. +93
    -0
      dist/modules/fedoragold-utils/src/LevinPacket.d.ts
  96. +331
    -0
      dist/modules/fedoragold-utils/src/LevinPacket.js
  97. +147
    -0
      dist/modules/fedoragold-utils/src/Multisig.d.ts
  98. +462
    -0
      dist/modules/fedoragold-utils/src/Multisig.js
  99. +91
    -0
      dist/modules/fedoragold-utils/src/MultisigMessage.d.ts
  100. +300
    -0
      dist/modules/fedoragold-utils/src/MultisigMessage.js

+ 0
- 1
.gitignore View File

@@ -1,6 +1,5 @@
node_modules
mywallet.wallet
dist/
package-lock.json
.idea
yarn-error.log

+ 9
- 187
README.md View File

@@ -15,19 +15,19 @@ Provides an interface to the FedoraGold (FED) network, allowing wallet applicati

## Documentation

[You can view the documentation here](https://turtlecoin.github.io/turtlecoin-wallet-backend-js/classes/_walletbackend_.walletbackend.html)
[You can view the documentation here](https://git.fedoragold.com/jojapoppa/fedoragold-wallet-backend)

You can see a list of all the other classes on the right side of the screen.
Note that you will need to prefix them all with `WB.` to access them, if you are not using typescript style imports, assuming you imported with `const WB = require('turtlecoin-wallet-backend')`.
Note that you will need to prefix them all with `WB.` to access them, if you are not using typescript style imports, assuming you imported with `const WB = require('fedoragold-wallet-backend')`.

## Quick Start

You can find an [example project in the examples](https://github.com/turtlecoin/turtlecoin-wallet-backend-js/tree/master/examples/example1) folder.
You can find an [example project in the examples](https://git.fedoragold.com/jojapoppa/fedoragold-wallet-backend) folder.

### Javascript

```javascript
const WB = require('turtlecoin-wallet-backend');
const WB = require('fedoragold-wallet-backend');

(async () => {
const daemon = new WB.Daemon('127.0.0.1', 11898);
@@ -55,7 +55,7 @@ const WB = require('turtlecoin-wallet-backend');
### Typescript

```typescript
import { WalletBackend, Daemon, IDaemon } from 'turtlecoin-wallet-backend';
import { WalletBackend, Daemon, IDaemon } from 'fedoragold-wallet-backend';

(async () => {
const daemon: IDaemon = new Daemon('127.0.0.1', 11898);
@@ -155,7 +155,7 @@ You can view available categories and log levels in the documentation.

### v6.0.6

* Upgrade turtlecoin-utils and other dependencies
* Upgrade fedoragold-utils and other dependencies
* Documentation updates
* Test suite updates

@@ -169,7 +169,7 @@ You can view available categories and log levels in the documentation.

### v6.0.3

* Update turtlecoin-utils
* Update fedoragold-utils
* New events emitted when a ledger is waiting for user input

### v6.0.2
@@ -224,189 +224,11 @@ You can view available categories and log levels in the documentation.
The return type of both `sendTransactionBasic` and `sendTransactionAdvanced` has
changed. The type of the `fee` parameter for `sendTransactionAdvanced` has changed.

### v4.0.11

* Fix rare failure to sync when swapping from non cache node to cache node with blocks stored
* Fix failure to sync when enabling coinbase transaction scanning with blocks stored
* Disable sleeping between block download failures
* Log all public function calls in WalletBackend class
* Fix issue where transactions would be incorrectly reported as errored

### v4.0.10

* Amount of blocks per request will ramp up/down as requests succeed/fail.
* More detailed logging

### v4.0.9

* Bump `turtlecoin-utils`

### v4.0.8

* Allow passing custom `checkRingSignatures` to `turtlecoin-utils`
* Bump `turtlecoin-utils` to support passing `checkRingSignatures`

### v4.0.7

* Bump `turtlecoin-utils` to fix issue where transaction signatures would be misordered when supplying a custom `generateRingSignatures` function

### v4.0.6

* Bump `turtlecoin-utils` to fix issue in some environments

### v4.0.5

* Add a subwallets beta. API may change. Functionality may be buggy.
* No longer will create inputs of over than 1 billion in transactions to prevent creating unmixable funds
* Export the `validateAddress()` function
* Add `getConnectionString()`, for retrieving the daemon connection ip:port pair
* Add an optional subwallet address filter for `getTransactions`

### v4.0.4

* Allow passing custom options to `request()` calls
* Allow making an empty string a valid paymentID false

### v4.0.3

* Update turtlecoin-utils
* Add error code `DAEMON_STILL_PROCESSING` returned when a transaction may or may not have failed
* Fix bug causing balance double counts with fusions in rare case

### v4.0.2

* Fix package.json not being published to NPM causing require() fail

### v4.0.1

* Fix auto-optimize not functioning after loading from file
* Increase node threadpool size to prevent issues with timeouts
* Sort outputs before requesting random outs

### v4.0.0

* Adds a `TRACE` log level for logging of daemon request+response data
* Adds a simpler `validateAddress` function to the `ValidateParameters` module
* Slightly improves the Auto Optimization implementation
* Removes `BlockchainCacheApi` and `ConventionalDaemon` - Please use `Daemon` instead
* Returns additional information from transaction failure when available
* More logging information added
* Transaction creation process sped up by not re-generating keyimages

### v3.4.12

* Adds a customizable user agent option to the config
* Ring signatures are now always checked before sending

### v3.4.11

* Add `on('deadnode')` event

### v3.4.10

* Calculate balance in an alternative way which fixes historical balances being incorrect after a rewind > 5000 blocks

### v3.4.9

* Fix heightchange being emitted on topblock when there are still blocks remaining to be processed

### v3.4.8

* `on('heightchange')` is now emitted when `reset()`, `rewind()`, or `rescan()` is used.
* `on('heightchange')` is now emitted when a top block is stored, fixing wallet height lagging behind network height.

### v3.4.7

* Fix issue with removeForkedTransactions, which also effected `rewind()`

### v3.4.6

* Add `rewind()`
* Add `on('heightchange')` event
* More improvements to keep-alive, max sockets, etc

### v3.4.5

* Fix bug causing balance from sent transaction to appear in both locked + unlocked balance

### v3.4.4

* Fix bug with how forked transactions were handled
* Increase max sockets to use with request to fix timeouts in some environments
* Fix bug where transactions to yourself had an incorrect amount when locked

### v3.4.3

* Add `on('disconnect')` and `on('connect')` events for daemon
* Update `turtlecoin-utils` dependency

### v3.4.2

* Set keep-alive to true for `Daemon` and `BlockchainCacheApi`
* Use IP regex instead of `net` module to allow working in non node environments

### v3.4.1

* Fix transactions being broken

### v3.4.0

* Add type assertions for JavaScript users
* May possibly break your code if you were using implicit conversions to pass strings as numbers, etc
* Fix bug where `cancelledTransactionsFailCount` was not correctly initialized when loading from file
* Fix warning when using TLS with raw IP address
* Known regression - Transactions are broken. Update to 3.4.1

### v3.3.2

* Migrate from node-fetch to request for `BlockchainCacheApi` as it works better in odd environments
* Remove `maxBodyRequestSize` property as `abort-controller` significantly complicated code and didn't work in odd environments
* Known regression - Transactions are broken. Update to 3.4.1

### v3.3.1

* Improve auto optimization
* Update turtlecoin-utils dependency
* Known regression - Transactions are broken. Update to 3.4.1

### v3.3.0

* Adds `swapNode()` method

### v3.2.0

* Adds `getDaemonConnectionInfo()` method
* Removes compiled JavaScript from GitHub - GitHub install is no longer supported

### v3.1.1

* Fixes bug where wallet may not correctly halt after calling `stop()`.

### v3.1.0

* Adds `Daemon` class. This class supports Blockchain cache api's, conventional daemons, http and https, all automatically.
* Marks `ConventionalDaemon` and `BlockchainCacheApi` as deprecated. These will be removed in v4.0.0. Please use the `Daemon` class instead.

### v3.0.1

* Fix issue where `reset()` would cause double wallet scanning.

### v3.0.0

* Fix bug where using multiple wallet instances with different configs would only use the latest config.
* API change - You must now provide a config to the Utilities/ValidateParameters functions if you are using a non default config, for example if you are using the library for another cryptocurrency. Otherwise, the default TurtleCoin config will be used.

### v2.0.0

Start of changelog.

## Contributing

### Building (For Developers)

`git clone https://github.com/turtlecoin/turtlecoin-wallet-backend-js.git`
`git clone https://git.fedoragold.com/jojapoppa/fedoragold-wallet-backend

`cd turtlecoin-wallet-backend`
`cd fedoragold-wallet-backend`

`npm install -g yarn` (Skip this if you already have yarn installed)



+ 11
- 0
dist/lib/Assert.d.ts View File

@@ -0,0 +1,11 @@
export declare function assertStringOrUndefined(param: unknown, name: string): void;
export declare function assertString(param: unknown, name: string): void;
export declare function assertNumberOrUndefined(param: unknown, name: string): void;
export declare function assertNumber(param: unknown, name: string): void;
export declare function assertBooleanOrUndefined(param: unknown, name: string): void;
export declare function assertBoolean(param: unknown, name: string): void;
export declare function assertArrayOrUndefined(param: unknown, name: string): void;
export declare function assertArray(param: unknown, name: string): void;
export declare function assertObjectOrUndefined(param: unknown, name: string): void;
export declare function assertObject(param: unknown, name: string): void;
export declare function assertType(param: unknown, name: string, correctType: string, typeVerificationFunc: (param: unknown) => boolean, allowUndefined: boolean): void;

+ 56
- 0
dist/lib/Assert.js View File

@@ -0,0 +1,56 @@
"use strict";
// Copyright (C) 2019-2020, Zpalmtree
//
// Please see the included LICENSE file for more information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.assertType = exports.assertObject = exports.assertObjectOrUndefined = exports.assertArray = exports.assertArrayOrUndefined = exports.assertBoolean = exports.assertBooleanOrUndefined = exports.assertNumber = exports.assertNumberOrUndefined = exports.assertString = exports.assertStringOrUndefined = void 0;
const _ = require("lodash");
function assertStringOrUndefined(param, name) {
return assertType(param, name, 'string', _.isString, true);
}
exports.assertStringOrUndefined = assertStringOrUndefined;
function assertString(param, name) {
return assertType(param, name, 'string', _.isString, false);
}
exports.assertString = assertString;
function assertNumberOrUndefined(param, name) {
return assertType(param, name, 'number', _.isNumber, true);
}
exports.assertNumberOrUndefined = assertNumberOrUndefined;
function assertNumber(param, name) {
return assertType(param, name, 'number', _.isNumber, false);
}
exports.assertNumber = assertNumber;
function assertBooleanOrUndefined(param, name) {
return assertType(param, name, 'boolean', _.isBoolean, true);
}
exports.assertBooleanOrUndefined = assertBooleanOrUndefined;
function assertBoolean(param, name) {
return assertType(param, name, 'boolean', _.isBoolean, false);
}
exports.assertBoolean = assertBoolean;
function assertArrayOrUndefined(param, name) {
return assertType(param, name, 'array', _.isArray, true);
}
exports.assertArrayOrUndefined = assertArrayOrUndefined;
function assertArray(param, name) {
return assertType(param, name, 'array', _.isArray, false);
}
exports.assertArray = assertArray;
function assertObjectOrUndefined(param, name) {
return assertType(param, name, 'object', _.isObject, true);
}
exports.assertObjectOrUndefined = assertObjectOrUndefined;
function assertObject(param, name) {
return assertType(param, name, 'object', _.isObject, false);
}
exports.assertObject = assertObject;
function assertType(param, name, correctType, typeVerificationFunc, allowUndefined) {
if (allowUndefined && param === undefined) {
return;
}
if (!typeVerificationFunc(param)) {
throw new Error(`Expected ${correctType} for '${name}' parameter, but got ${typeof param}`);
}
}
exports.assertType = assertType;

+ 9
- 0
dist/lib/CnUtils.d.ts View File

@@ -0,0 +1,9 @@
import { ICryptoNote } from 'fedoragold-utils';
import { Config } from './Config';
/**
* This needs to be a function, rather than a default export, since our config
* can change when a user calls createWallet() with a non default config.
* Due to how the module system works, a default export is cached and so the
* config will never update.
*/
export declare function CryptoUtils(config: Config): ICryptoNote;

+ 60
- 0
dist/lib/CnUtils.js View File

@@ -0,0 +1,60 @@
"use strict";
// Copyright (c) 2018-2020, Zpalmtree
//
// Please see the included LICENSE file for more information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.CryptoUtils = void 0;
const fedoragold_utils_1 = require("fedoragold-utils");
const _ = require("lodash");
/** @ignore */
const cached = {};
/**
* This needs to be a function, rather than a default export, since our config
* can change when a user calls createWallet() with a non default config.
* Due to how the module system works, a default export is cached and so the
* config will never update.
*/
function CryptoUtils(config) {
if (!_.isEqual(cached.config, config) || !cached.config || !cached.interface) {
cached.config = config;
if (!config.ledgerTransport) {
cached.interface = new fedoragold_utils_1.CryptoNote({
addressPrefix: config.addressPrefix,
coinUnitPlaces: config.decimalPlaces,
keccakIterations: 1,
}, {
cn_fast_hash: config.cnFastHash,
checkRingSignatures: config.checkRingSignatures,
derivePublicKey: config.derivePublicKey,
deriveSecretKey: config.deriveSecretKey,
generateKeyDerivation: config.generateKeyDerivation,
generateKeyImage: config.generateKeyImage,
generateRingSignatures: config.generateRingSignatures,
secretKeyToPublicKey: config.secretKeyToPublicKey,
underivePublicKey: config.underivePublicKey,
});
}
else {
cached.interface = new fedoragold_utils_1.LedgerNote(config.ledgerTransport, {
addressPrefix: config.addressPrefix,
coinUnitPlaces: config.decimalPlaces,
keccakIterations: 1,
}, {
cn_fast_hash: config.cnFastHash,
checkRingSignatures: config.checkRingSignatures,
derivePublicKey: config.derivePublicKey,
deriveSecretKey: config.deriveSecretKey,
generateKeyDerivation: config.generateKeyDerivation,
generateKeyImage: config.generateKeyImage,
generateRingSignatures: config.generateRingSignatures,
secretKeyToPublicKey: config.secretKeyToPublicKey,
underivePublicKey: config.underivePublicKey,
});
}
return cached.interface;
}
else {
return cached.interface;
}
}
exports.CryptoUtils = CryptoUtils;

+ 300
- 0
dist/lib/Config.d.ts View File

@@ -0,0 +1,300 @@
/// <reference types="ledgerhq__hw-transport" />
import { MixinLimits } from './MixinLimits';
import { LedgerTransport } from 'fedoragold-utils';
/**
* Configuration for the wallet backend.
*
* Everything is optional.
*/
export interface IConfig {
/**
* The amount of decimal places your coin has, e.g. Fedoragold has eight
* decimals
*/
decimalPlaces?: number;
/**
* The address prefix your coin uses - you can find this in CryptoNoteConfig.h.
* In FedoraGold, this converts to FEDG
*/
addressPrefix?: number;
/**
* Request timeout for daemon operations in milliseconds
*/
requestTimeout?: number;
/**
* The block time of your coin, in seconds
*/
blockTargetTime?: number;
/**
* How often to process blocks, in millseconds
*/
syncThreadInterval?: number;
/**
* How often to update the daemon info
*/
daemonUpdateInterval?: number;
/**
* How often to check on locked transactions
*/
lockedTransactionsCheckInterval?: number;
/**
* The amount of blocks to process per 'tick' of the mainloop. Note: too
* high a value will cause the event loop to be blocked, and your interaction
* to be laggy.
*/
blocksPerTick?: number;
/**
* Your coins 'ticker', generally used to refer to the coin, i.e. 123 TRTL
*/
ticker?: string;
/**
* Most people haven't mined any blocks, so lets not waste time scanning
* them
*/
scanCoinbaseTransactions?: boolean;
/**
* The minimum fee allowed for transactions, in ATOMIC units
*/
minimumFee?: number;
/**
* Mapping of height to mixin maximum and mixin minimum
*/
mixinLimits?: MixinLimits;
/**
* The length of a standard address for your coin
*/
standardAddressLength?: number;
/**
* The length of an integrated address for your coin - It's the same as
* a normal address, but there is a paymentID included in there - since
* payment ID's are 64 chars, and base58 encoding is done by encoding
* chunks of 8 chars at once into blocks of 11 chars, we can calculate
* this automatically
*/
integratedAddressLength?: number;
/**
* A replacement function for the JS/C++ underivePublicKey.
*/
underivePublicKey?: (derivation: string, outputIndex: number, outputKey: string) => Promise<string>;
/**
* A replacement function for the JS/C++ derivePublicKey.
*/
derivePublicKey?: (derivation: string, outputIndex: number, publicKey: string) => Promise<string>;
/**
* A replacement function for the JS/C++ deriveSecretKey.
*/
deriveSecretKey?: (derivation: string, outputIndex: number, privateKey: string) => Promise<string>;
/**
* A replacement function for the JS/C++ generateKeyImage.
*/
generateKeyImage?: (publicKey: string, privateKey: string) => Promise<string>;
/**
* A replacement function for the JS/C++ secretKeyToPublicKey.
*/
secretKeyToPublicKey?: (privateKey: string) => Promise<string>;
/**
* A replacement function for the JS/C++ cnFastHash.
*/
cnFastHash?: (input: string) => Promise<string>;
/**
* A replacement function for the JS/C++ generateRingSignatures.
*/
generateRingSignatures?: (transactionPrefixHash: string, keyImage: string, inputKeys: string[], privateKey: string, realIndex: number) => Promise<string[]>;
/**
* A replacement function for the JS/C++ checkRingSignatures.
*/
checkRingSignatures?: (transactionPrefixHash: string, keyImage: string, publicKeys: string[], signatures: string[]) => Promise<boolean>;
/**
* A replacement function for the JS/C++ generateKeyDerivation.
*/
generateKeyDerivation?: (transactionPublicKey: string, privateViewKey: string) => Promise<string>;
/**
* The max amount of memory to use, storing downloaded blocks to be processed.
*/
blockStoreMemoryLimit?: number;
/**
* The amount of blocks to take from the daemon per request. Cannot take
* more than 100.
*/
blocksPerDaemonRequest?: number;
/**
* The amount of seconds to permit not having fetched a block from the
* daemon before emitting 'deadnode'. Note that this just means contacting
* the daemon for data - if you are synced and it returns TopBlock - the
* event will not be emitted.
*/
maxLastFetchedBlockInterval?: number;
/**
* The amount of seconds to permit not having fetched a new network height
* from the daemon before emitting 'deadnode'.
*/
maxLastUpdatedNetworkHeightInterval?: number;
/**
* The amount of seconds to permit not having fetched a new local height
* from the daemon before emitting 'deadnode'.
*/
maxLastUpdatedLocalHeightInterval?: number;
/**
* Allows specifying a custom user agent string to use with requests.
*/
customUserAgentString?: string;
/**
* Allows specifying a custom configuration object for the request module.
*/
customRequestOptions?: any;
/**
* Defines whether we are using the LedgerNote class instead of the
* CryptoNote class
*/
ledgerTransport?: LedgerTransport;
[key: string]: any;
}
/**
* Configuration for the wallet backend
*
* @hidden
*/
export declare class Config implements IConfig {
/**
* The amount of decimal places your coin has, e.g. Fedoragold has eight
* decimals
*/
decimalPlaces: number;
/**
* The address prefix your coin uses - you can find this in CryptoNoteConfig.h.
* In Fedoragold, this converts to FEDG
*/
addressPrefix: number;
/**
* Request timeout for daemon operations in milliseconds
*/
requestTimeout: number;
/**
* The block time of your coin, in seconds
*/
blockTargetTime: number;
/**
* How often to process blocks, in millseconds
*/
syncThreadInterval: number;
/**
* How often to update the daemon info
*/
daemonUpdateInterval: number;
/**
* How often to check on locked transactions
*/
lockedTransactionsCheckInterval: number;
/**
* The amount of blocks to process per 'tick' of the mainloop. Note: too
* high a value will cause the event loop to be blocked, and your interaction
* to be laggy.
*/
blocksPerTick: number;
/**
* Your coins 'ticker', generally used to refer to the coin, i.e. 123 TRTL
*/
ticker: string;
/**
* Most people haven't mined any blocks, so lets not waste time scanning
* them
*/
scanCoinbaseTransactions: boolean;
/**
* The minimum fee allowed for transactions, in ATOMIC units
*/
minimumFee: number;
feePerByteChunkSize: number;
minimumFeePerByte: number;
/**
* Mapping of height to mixin maximum and mixin minimum
*/
mixinLimits: MixinLimits;
/**
* The length of a standard address for your coin
*/
standardAddressLength: number;
integratedAddressLength: number;
/**
* A replacement function for the JS/C++ underivePublicKey.
*/
underivePublicKey?: (derivation: string, outputIndex: number, outputKey: string) => Promise<string>;
/**
* A replacement function for the JS/C++ derivePublicKey.
*/
derivePublicKey?: (derivation: string, outputIndex: number, publicKey: string) => Promise<string>;
/**
* A replacement function for the JS/C++ deriveSecretKey.
*/
deriveSecretKey?: (derivation: string, outputIndex: number, privateKey: string) => Promise<string>;
/**
* A replacement function for the JS/C++ generateKeyImage.
*/
generateKeyImage?: (publicKey: string, privateKey: string) => Promise<string>;
/**
* A replacement function for the JS/C++ secretKeyToPublicKey.
*/
secretKeyToPublicKey?: (privateKey: string) => Promise<string>;
/**
* A replacement function for the JS/C++ cnFastHash.
*/
cnFastHash?: (input: string) => Promise<string>;
/**
* A replacement function for the JS/C++ generateRingSignatures.
*/
generateRingSignatures?: (transactionPrefixHash: string, keyImage: string, inputKeys: string[], privateKey: string, realIndex: number) => Promise<string[]>;
/**
* A replacement function for the JS/C++ checkRingSignatures.
*/
checkRingSignatures?: (transactionPrefixHash: string, keyImage: string, publicKeys: string[], signatures: string[]) => Promise<boolean>;
/**
* A replacement function for the JS/C++ generateKeyDerivation.
*/
generateKeyDerivation?: (transactionPublicKey: string, privateViewKey: string) => Promise<string>;
/**
* The amount of memory to use storing downloaded blocks - 50MB
*/
blockStoreMemoryLimit: number;
/**
* The amount of blocks to take from the daemon per request. Cannot take
* more than 100.
*/
blocksPerDaemonRequest: number;
/**
* The amount of seconds to permit not having fetched a block from the
* daemon before emitting 'deadnode'. Note that this just means contacting
* the daemon for data - if you are synced and it returns TopBlock - the
* event will not be emitted.
*/
maxLastFetchedBlockInterval: number;
/**
* The amount of seconds to permit not having fetched a new network height
* from the daemon before emitting 'deadnode'.
*/
maxLastUpdatedNetworkHeightInterval: number;
/**
* The amount of seconds to permit not having fetched a new local height
* from the daemon before emitting 'deadnode'.
*/
maxLastUpdatedLocalHeightInterval: number;
/**
* Allows setting a customer user agent string
*/
customUserAgentString: string;
/**
* Allows specifying a custom configuration object for the request module.
*/
customRequestOptions: any;
/**
* Defines whether we are using the LedgerNote class instead of the
* CryptoNote class
*/
ledgerTransport?: LedgerTransport;
[key: string]: any;
}
/**
* Merge the default config with the provided config
*
* @hidden
*/
export declare function MergeConfig(config?: IConfig, currentConfig?: Config): Config;

+ 186
- 0
dist/lib/Config.js View File

@@ -0,0 +1,186 @@
"use strict";
// Copyright (C) 2018-2020, Zpalmtree
//
// Please see the included LICENSE file for more information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.MergeConfig = exports.Config = void 0;
const MixinLimits_1 = require("./MixinLimits");
/* eslint-disable @typescript-eslint/no-var-requires */
const version = require('../../package.json').version;
/**
* Configuration for the wallet backend
*
* @hidden
*/
class Config {
constructor() {
/**
* The amount of decimal places your coin has, e.g. Fedoragold has eight
* decimals
*/
this.decimalPlaces = 2;
/**
* The address prefix your coin uses - you can find this in CryptoNoteConfig.h.
* In Fedoragold, this converts to FEDG
*/
this.addressPrefix = 127; //3914525;
/**
* Request timeout for daemon operations in milliseconds
*/
this.requestTimeout = 10 * 1000;
/**
* The block time of your coin, in seconds
*/
this.blockTargetTime = 25;
/**
* How often to process blocks, in millseconds
*/
this.syncThreadInterval = 10;
/**
* How often to update the daemon info
*/
this.daemonUpdateInterval = 10 * 1000;
/**
* How often to check on locked transactions
*/
this.lockedTransactionsCheckInterval = 30 * 1000;
/**
* The amount of blocks to process per 'tick' of the mainloop. Note: too
* high a value will cause the event loop to be blocked, and your interaction
* to be laggy.
*/
this.blocksPerTick = 1;
/**
* Your coins 'ticker', generally used to refer to the coin, i.e. 123 TRTL
*/
this.ticker = 'FED';
/**
* Most people haven't mined any blocks, so lets not waste time scanning
* them
*/
this.scanCoinbaseTransactions = false;
/**
* The minimum fee allowed for transactions, in ATOMIC units
*/
this.minimumFee = 10;
/* Fee per byte is rounded up in chunks. This helps makes estimates
* more accurate. It's suggested to make this a power of two, to relate
* to the underlying storage cost / page sizes for storing a transaction. */
this.feePerByteChunkSize = 256;
/* Fee to charge per byte of transaction. Will be applied in chunks, see
* above. This value comes out to 1.953125. We use this value instead of
* something like 2 because it makes for pretty resulting fees
* - 5 TRTL vs 5.12 TRTL. You can read this as.. the fee per chunk
* is 500 atomic units. The fee per byte is 500 / chunk size. */
this.minimumFeePerByte = 500.00 / this.feePerByteChunkSize;
/**
* Mapping of height to mixin maximum and mixin minimum
*/
this.mixinLimits = new MixinLimits_1.MixinLimits([
/* Height: 440,000, minMixin: 0, maxMixin: 100, defaultMixin: 3 */
new MixinLimits_1.MixinLimit(440000, 0, 100, 3),
/* At height of 620000, static mixin of 7 */
new MixinLimits_1.MixinLimit(620000, 7),
/* At height of 800000, static mixin of 3 */
new MixinLimits_1.MixinLimit(800000, 3),
], 3 /* Default mixin of 3 before block 440,000 */);
/**
* The length of a standard address for your coin
*/
this.standardAddressLength = 99;
/* The length of an integrated address for your coin - It's the same as
a normal address, but there is a paymentID included in there - since
payment ID's are 64 chars, and base58 encoding is done by encoding
chunks of 8 chars at once into blocks of 11 chars, we can calculate
this automatically */
this.integratedAddressLength = 99 + ((64 * 11) / 8);
/**
* A replacement function for the JS/C++ underivePublicKey.
*/
this.underivePublicKey = undefined;
/**
* A replacement function for the JS/C++ derivePublicKey.
*/
this.derivePublicKey = undefined;
/**
* A replacement function for the JS/C++ deriveSecretKey.
*/
this.deriveSecretKey = undefined;
/**
* A replacement function for the JS/C++ generateKeyImage.
*/
this.generateKeyImage = undefined;
/**
* A replacement function for the JS/C++ secretKeyToPublicKey.
*/
this.secretKeyToPublicKey = undefined;
/**
* A replacement function for the JS/C++ cnFastHash.
*/
this.cnFastHash = undefined;
/**
* A replacement function for the JS/C++ generateRingSignatures.
*/
this.generateRingSignatures = undefined;
/**
* A replacement function for the JS/C++ checkRingSignatures.
*/
this.checkRingSignatures = undefined;
/**
* A replacement function for the JS/C++ generateKeyDerivation.
*/
this.generateKeyDerivation = undefined;
/**
* The amount of memory to use storing downloaded blocks - 50MB
*/
this.blockStoreMemoryLimit = 1024 * 1024 * 50;
/**
* The amount of blocks to take from the daemon per request. Cannot take
* more than 100.
*/
this.blocksPerDaemonRequest = 100;
/**
* The amount of seconds to permit not having fetched a block from the
* daemon before emitting 'deadnode'. Note that this just means contacting
* the daemon for data - if you are synced and it returns TopBlock - the
* event will not be emitted.
*/
this.maxLastFetchedBlockInterval = 60 * 3;
/**
* The amount of seconds to permit not having fetched a new network height
* from the daemon before emitting 'deadnode'.
*/
this.maxLastUpdatedNetworkHeightInterval = 60 * 3;
/**
* The amount of seconds to permit not having fetched a new local height
* from the daemon before emitting 'deadnode'.
*/
this.maxLastUpdatedLocalHeightInterval = 60 * 3;
/**
* Allows setting a customer user agent string
*/
this.customUserAgentString = `${this.ticker.toLowerCase()}-wallet-backend-${version}`;
/**
* Allows specifying a custom configuration object for the request module.
*/
this.customRequestOptions = {};
}
}
exports.Config = Config;
/**
* Merge the default config with the provided config
*
* @hidden
*/
function MergeConfig(config, currentConfig = new Config()) {
/* Clone the given config so we don't alter it */
const finalConfig = Object.create(Object.getPrototypeOf(currentConfig), Object.getOwnPropertyDescriptors(currentConfig));
if (!config) {
return finalConfig;
}
for (const [key, value] of Object.entries(config)) {
finalConfig[key] = value;
}
return finalConfig;
}
exports.MergeConfig = MergeConfig;

+ 83
- 0
dist/lib/Constants.d.ts View File

@@ -0,0 +1,83 @@
/// <reference types="node" />
/**
* What version of the file format are we on (to make it easier to
* upgrade the wallet format in the future)
*/
export declare const WALLET_FILE_FORMAT_VERSION: number;
/**
* The number of iterations of PBKDF2 to perform on the wallet
* password.
*/
export declare const PBKDF2_ITERATIONS: number;
/**
* We use this to check that the file is a wallet file, this bit does
* not get encrypted, and we can check if it exists before decrypting.
* If it isn't, it's not a wallet file.
*/
export declare const IS_A_WALLET_IDENTIFIER: Buffer;
/**
* We use this to check if the file has been correctly decoded, i.e.
* is the password correct. This gets encrypted into the file, and
* then when unencrypted the file should start with this - if it
* doesn't, the password is wrong
*/
export declare const IS_CORRECT_PASSWORD_IDENTIFIER: Buffer;
/**
* How large should the lastKnownBlockHashes container be
*/
export declare const LAST_KNOWN_BLOCK_HASHES_SIZE: number;
/**
* Save a block hash checkpoint every BLOCK_HASH_CHECKPOINTS_INTERVAL
* blocks
*/
export declare const BLOCK_HASH_CHECKPOINTS_INTERVAL: number;
/**
* When we get the global indexes, we pass in a range of blocks, to obscure
* which transactions we are interested in - the ones that belong to us.
* To do this, we get the global indexes for all transactions in a range.
* For example, if we want the global indexes for a transaction in block
* 17, we get all the indexes from block 10 to block 20.
*
* This value determines how many blocks to take from.
*/
export declare const GLOBAL_INDEXES_OBSCURITY: number;
/**
* Used to determine whether an unlock time is a height, or a timestamp
*/
export declare const MAX_BLOCK_NUMBER: number;
/**
* Valid output amounts to be mixable
*/
export declare const PRETTY_AMOUNTS: number[];
/**
* Part of the how fast blocks can grow formula
*/
export declare const MAX_BLOCK_SIZE_GROWTH_SPEED_NUMERATOR: number;
/**
* Part of the how fast blocks can grow
*/
export declare const MAX_BLOCK_SIZE_GROWTH_SPEED_DENOMINATOR: number;
/**
* Initial block size
*/
export declare const MAX_BLOCK_SIZE_INITIAL: number;
/**
* Reserved space for miner transaction in block
*/
export declare const CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE: number;
/**
* Minimum number of inputs a fusion transaction must have
*/
export declare const FUSION_TX_MIN_INPUT_COUNT = 12;
/**
* Max size in bytes a fusion transaction can be
*/
export declare const MAX_FUSION_TX_SIZE = 30000;
/**
* Required ratio of inputs to outputs in fusion transactions
*/
export declare const FUSION_TX_MIN_IN_OUT_COUNT_RATIO = 4;
/**
* Max amount to create a single output of
*/
export declare const MAX_OUTPUT_SIZE_CLIENT = 100000000000;

+ 136
- 0
dist/lib/Constants.js View File

@@ -0,0 +1,136 @@
"use strict";
// Copyright (c) 2018-2020, Zpalmtree
//
// Please see the included LICENSE file for more information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.MAX_OUTPUT_SIZE_CLIENT = exports.FUSION_TX_MIN_IN_OUT_COUNT_RATIO = exports.MAX_FUSION_TX_SIZE = exports.FUSION_TX_MIN_INPUT_COUNT = exports.CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE = exports.MAX_BLOCK_SIZE_INITIAL = exports.MAX_BLOCK_SIZE_GROWTH_SPEED_DENOMINATOR = exports.MAX_BLOCK_SIZE_GROWTH_SPEED_NUMERATOR = exports.PRETTY_AMOUNTS = exports.MAX_BLOCK_NUMBER = exports.GLOBAL_INDEXES_OBSCURITY = exports.BLOCK_HASH_CHECKPOINTS_INTERVAL = exports.LAST_KNOWN_BLOCK_HASHES_SIZE = exports.IS_CORRECT_PASSWORD_IDENTIFIER = exports.IS_A_WALLET_IDENTIFIER = exports.PBKDF2_ITERATIONS = exports.WALLET_FILE_FORMAT_VERSION = void 0;
/**
* What version of the file format are we on (to make it easier to
* upgrade the wallet format in the future)
*/
exports.WALLET_FILE_FORMAT_VERSION = 7;
/**
* The number of iterations of PBKDF2 to perform on the wallet
* password.
*/
exports.PBKDF2_ITERATIONS = 500000;
/**
* We use this to check that the file is a wallet file, this bit does
* not get encrypted, and we can check if it exists before decrypting.
* If it isn't, it's not a wallet file.
*/
exports.IS_A_WALLET_IDENTIFIER = Buffer.from([
0x49, 0x66, 0x20, 0x49, 0x20, 0x70, 0x75, 0x6c, 0x6c, 0x20, 0x74,
0x68, 0x61, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x2c, 0x20, 0x77, 0x69,
0x6c, 0x6c, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x64, 0x69, 0x65, 0x3f,
0x0a, 0x49, 0x74, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62,
0x65, 0x20, 0x65, 0x78, 0x74, 0x72, 0x65, 0x6d, 0x65, 0x6c, 0x79,
0x20, 0x70, 0x61, 0x69, 0x6e, 0x66, 0x75, 0x6c, 0x2e,
]);
/**
* We use this to check if the file has been correctly decoded, i.e.
* is the password correct. This gets encrypted into the file, and
* then when unencrypted the file should start with this - if it
* doesn't, the password is wrong
*/
exports.IS_CORRECT_PASSWORD_IDENTIFIER = Buffer.from([
0x59, 0x6f, 0x75, 0x27, 0x72, 0x65, 0x20, 0x61, 0x20, 0x62, 0x69,
0x67, 0x20, 0x67, 0x75, 0x79, 0x2e, 0x0a, 0x46, 0x6f, 0x72, 0x20,
0x79, 0x6f, 0x75, 0x2e,
]);
/**
* How large should the lastKnownBlockHashes container be
*/
exports.LAST_KNOWN_BLOCK_HASHES_SIZE = 50;
/**
* Save a block hash checkpoint every BLOCK_HASH_CHECKPOINTS_INTERVAL
* blocks
*/
exports.BLOCK_HASH_CHECKPOINTS_INTERVAL = 5000;
/**
* When we get the global indexes, we pass in a range of blocks, to obscure
* which transactions we are interested in - the ones that belong to us.
* To do this, we get the global indexes for all transactions in a range.
* For example, if we want the global indexes for a transaction in block
* 17, we get all the indexes from block 10 to block 20.
*
* This value determines how many blocks to take from.
*/
exports.GLOBAL_INDEXES_OBSCURITY = 10;
/**
* Used to determine whether an unlock time is a height, or a timestamp
*/
exports.MAX_BLOCK_NUMBER = 500000000;
/**
* Valid output amounts to be mixable
*/
exports.PRETTY_AMOUNTS = [
1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 20, 30, 40, 50, 60, 70, 80, 90,
100, 200, 300, 400, 500, 600, 700, 800, 900,
1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000,
10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000,
100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000,
1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000,
10000000, 20000000, 30000000, 40000000, 50000000, 60000000, 70000000,
80000000, 90000000,
100000000, 200000000, 300000000, 400000000, 500000000, 600000000, 700000000,
800000000, 900000000,
1000000000, 2000000000, 3000000000, 4000000000, 5000000000, 6000000000,
7000000000, 8000000000, 9000000000,
10000000000, 20000000000, 30000000000, 40000000000, 50000000000, 60000000000,
70000000000, 80000000000, 90000000000,
100000000000, 200000000000, 300000000000, 400000000000, 500000000000,
600000000000, 700000000000, 800000000000, 900000000000,
1000000000000, 2000000000000, 3000000000000, 4000000000000, 5000000000000,
6000000000000, 7000000000000, 8000000000000, 9000000000000,
10000000000000, 20000000000000, 30000000000000, 40000000000000, 50000000000000,
60000000000000, 70000000000000, 80000000000000, 90000000000000,
100000000000000, 200000000000000, 300000000000000, 400000000000000,
500000000000000, 600000000000000, 700000000000000, 800000000000000,
900000000000000,
1000000000000000, 2000000000000000, 3000000000000000, 4000000000000000,
5000000000000000, 6000000000000000, 7000000000000000, 8000000000000000,
9000000000000000,
10000000000000000, 20000000000000000, 30000000000000000, 40000000000000000,
50000000000000000, 60000000000000000, 70000000000000000, 80000000000000000,
90000000000000000,
100000000000000000, 200000000000000000, 300000000000000000, 400000000000000000,
500000000000000000, 600000000000000000, 700000000000000000, 800000000000000000,
900000000000000000,
1000000000000000000, 2000000000000000000, 3000000000000000000, 4000000000000000000,
5000000000000000000, 6000000000000000000, 7000000000000000000, 8000000000000000000,
9000000000000000000, 10000000000000000000,
];
/**
* Part of the how fast blocks can grow formula
*/
exports.MAX_BLOCK_SIZE_GROWTH_SPEED_NUMERATOR = 100 * 1024;
/**
* Part of the how fast blocks can grow
*/
exports.MAX_BLOCK_SIZE_GROWTH_SPEED_DENOMINATOR = 365 * 24 * 60 * 60;
/**
* Initial block size
*/
exports.MAX_BLOCK_SIZE_INITIAL = 100000;
/**
* Reserved space for miner transaction in block
*/
exports.CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE = 600;
/**
* Minimum number of inputs a fusion transaction must have
*/
exports.FUSION_TX_MIN_INPUT_COUNT = 12;
/**
* Max size in bytes a fusion transaction can be
*/
exports.MAX_FUSION_TX_SIZE = 30000;
/**
* Required ratio of inputs to outputs in fusion transactions
*/
exports.FUSION_TX_MIN_IN_OUT_COUNT_RATIO = 4;
/**
* Max amount to create a single output of
*/
exports.MAX_OUTPUT_SIZE_CLIENT = 100000000000;

+ 5
- 0
dist/lib/CryptoWrapper.d.ts View File

@@ -0,0 +1,5 @@
import { Config } from './Config';
export declare function generateKeyDerivation(transactionPublicKey: string, privateViewKey: string, config: Config): Promise<string>;
export declare function generateKeyImagePrimitive(publicSpendKey: string, privateSpendKey: string, outputIndex: number, derivation: string, config: Config): Promise<[string, string?]>;
export declare function generateKeyImage(transactionPublicKey: string, privateViewKey: string, publicSpendKey: string, privateSpendKey: string, transactionIndex: number, config: Config): Promise<[string, string?]>;
export declare function underivePublicKey(derivation: string, outputIndex: number, outputKey: string, config: Config): Promise<string>;

+ 72
- 0
dist/lib/CryptoWrapper.js View File

@@ -0,0 +1,72 @@
"use strict";
// Copyright (c) 2019-2020, Zpalmtree
//
// Please see the included LICENSE file for more information.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.underivePublicKey = exports.generateKeyImage = exports.generateKeyImagePrimitive = exports.generateKeyDerivation = void 0;
const fedoragold_utils_1 = require("fedoragold-utils");
const CnUtils_1 = require("./CnUtils");
const FedoragoldCrypto = new fedoragold_utils_1.Crypto();
const nullKey = '0'.repeat(64);
function generateKeyDerivation(transactionPublicKey, privateViewKey, config) {
return __awaiter(this, void 0, void 0, function* () {
try {
return CnUtils_1.CryptoUtils(config).generateKeyDerivation(transactionPublicKey, privateViewKey);
}
catch (err) {
return nullKey;
}
});
}
exports.generateKeyDerivation = generateKeyDerivation;
function generateKeyImagePrimitive(publicSpendKey, privateSpendKey, outputIndex, derivation, config) {
return __awaiter(this, void 0, void 0, function* () {
if (config.derivePublicKey && config.deriveSecretKey && config.generateKeyImage) {
/* Derive the transfer public key from the derived key, the output index, and our public spend key */
const publicEphemeral = yield config.derivePublicKey(derivation, outputIndex, publicSpendKey);
/* Derive the key image private key from the derived key, the output index, and our spend secret key */
const privateEphemeral = yield config.deriveSecretKey(derivation, outputIndex, privateSpendKey);
/* Generate the key image */
const keyImage = yield config.generateKeyImage(publicEphemeral, privateEphemeral);
return [keyImage, privateEphemeral];
}
try {
const keys = yield CnUtils_1.CryptoUtils(config).generateKeyImagePrimitive(publicSpendKey, privateSpendKey, outputIndex, derivation);
return [keys.keyImage, keys.privateEphemeral];
}
catch (err) {
return [nullKey, nullKey];
}
});
}
exports.generateKeyImagePrimitive = generateKeyImagePrimitive;
function generateKeyImage(transactionPublicKey, privateViewKey, publicSpendKey, privateSpendKey, transactionIndex, config) {
return __awaiter(this, void 0, void 0, function* () {
const derivation = yield generateKeyDerivation(transactionPublicKey, privateViewKey, config);
return generateKeyImagePrimitive(publicSpendKey, privateSpendKey, transactionIndex, derivation, config);
});
}
exports.generateKeyImage = generateKeyImage;
function underivePublicKey(derivation, outputIndex, outputKey, config) {
return __awaiter(this, void 0, void 0, function* () {
if (config.underivePublicKey) {
return config.underivePublicKey(derivation, outputIndex, outputKey);
}
try {
return FedoragoldCrypto.underivePublicKey(derivation, outputIndex, outputKey);
}
catch (err) {
return nullKey;
}
});
}
exports.underivePublicKey = underivePublicKey;

+ 240
- 0
dist/lib/Daemon.d.ts View File

@@ -0,0 +1,240 @@
/// <reference types="node" />
import { EventEmitter } from 'events';
import { Block as UtilsBlock, Transaction as UtilsTransaction } from 'fedoragold-utils';
import { IConfig } from './Config';
import { WalletError } from './WalletError';
import { Block, TopBlock, DaemonConnection } from './Types';
export declare interface Daemon {
/**
* This is emitted whenever the interface fails to contact the underlying daemon.
* This event will only be emitted on the first disconnection. It will not
* be emitted again, until the daemon connects, and then disconnects again.
*
* Example:
*
* ```javascript
* daemon.on('disconnect', (error) => {
* console.log('Possibly lost connection to daemon: ' + error.toString());
* });
* ```
*
* @event This is emitted whenever the interface fails to contact the underlying daemon.
*/
on(event: 'disconnect', callback: (error: Error) => void): this;
/**
* This is emitted whenever the interface previously failed to contact the
* underlying daemon, and has now reconnected.
* This event will only be emitted on the first connection. It will not
* be emitted again, until the daemon disconnects, and then reconnects again.
*
* Example:
*
* ```javascript
* daemon.on('connect', () => {
* console.log('Regained connection to daemon!');
* });
* ```
*
* @event This is emitted whenever the interface previously failed to contact the underlying daemon, and has now reconnected.
*/
on(event: 'connect', callback: () => void): this;
/**
* This is emitted whenever either the localDaemonBlockCount or the networkDaemonBlockCount
* changes.
*
* Example:
*
* ```javascript
* daemon.on('heightchange', (localDaemonBlockCount, networkDaemonBlockCount) => {
* console.log(localDaemonBlockCount, networkDaemonBlockCount);
* });
* ```
*
* @event This is emitted whenever either the localDaemonBlockCount or the networkDaemonBlockCount changes
*/
on(event: 'heightchange', callback: (localDaemonBlockCount: number, networkDaemonBlockCount: number) => void): this;
/**
* This is emitted every time we download a block from the daemon.
*
* This block object is an instance of the [Block fedoragold-utils class](https://utils.turtlecoin.dev/classes/block.html).
* See the Utils docs for further info on using this value.
*
* Note that a block emitted after a previous one could potentially have a lower
* height, if a blockchain fork took place.
*
* Example:
*
* ```javascript
* daemon.on('rawblock', (block) => {
* console.log(`Downloaded new block ${block.hash}`);
* });
* ```
*
* @event This is emitted every time we download a block from the daemon
*/
on(event: 'rawblock', callback: (block: UtilsBlock) => void): this;
/**
* This is emitted every time we download a transaction from the daemon.
*
* This transaction object is an instance of the [Transaction fedoragold-utils class](https://utils.turtlecoin.dev/classes/transaction.html).
* See the Utils docs for further info on using this value.
*
* Note that a transaction emitted after a previous one could potentially have a lower
* height in the chain, if a blockchain fork took place.
*
* Example:
*
* ```javascript
* daemon.on('rawtransaction', (block) => {
* console.log(`Downloaded new transaction ${transaction.hash}`);
* });
* ```
*
* @event This is emitted every time we download a transaction from the daemon
*/
on(event: 'rawtransaction', callback: (transaction: UtilsTransaction) => void): this;
}
/**
* @noInheritDoc
*/
export declare class Daemon extends EventEmitter {
/**
* Daemon/API host
*/
private readonly host;
/**
* Daemon/API port
*/
private readonly port;
/**
* Whether we should use https for our requests
*/
private ssl;
/**
* Have we determined if we should be using ssl or not?
*/
private sslDetermined;
/**
* The address node fees will go to
*/
private feeAddress;
/**
* The amount of the node fee in atomic units
*/
private feeAmount;
/**
* The amount of blocks the daemon we're connected to has
*/
private localDaemonBlockCount;
/**
* The amount of blocks the network has
*/
private networkBlockCount;
/**
* The amount of peers we have, incoming+outgoing
*/
private peerCount;
/**
* The hashrate of the last known local block
*/
private lastKnownHashrate;
/**
* The number of blocks to download per /getwalletsyncdata request
*/
private blockCount;
private config;
private httpAgent;
private httpsAgent;
/**
* Last time the network height updated. If this goes over the configured
* limit, we'll emit deadnode.
*/
private lastUpdatedNetworkHeight;
/**
* Last time the daemon height updated. If this goes over the configured
* limit, we'll emit deadnode.
*/
private lastUpdatedLocalHeight;
/**
* Did our last contact with the daemon succeed. Set to true initially
* so initial failure to connect will fire disconnect event.
*/
private connected;
private useRawBlocks;
/**
* @param host The host to access the API on. Can be an IP, or a URL, for
* example, 1.1.1.1, or blockapi.turtlepay.io
*
* @param port The port to access the API on. Normally 30157 for a Fedoragold
* daemon, 80 for a HTTP api, or 443 for a HTTPS api.
*
* @param ssl You can optionally specify whether this API supports
* ssl/tls/https to save a couple of requests.
* If you're not sure, do not specify this parameter -
* we will work it out automatically.
*/
constructor(host: string, port: number, ssl?: boolean, useRawBlocks?: boolean);
updateConfig(config: IConfig): void;
/**
* Get the amount of blocks the network has
*/
getNetworkBlockCount(): number;
/**
* Get the amount of blocks the daemon we're connected to has
*/
getLocalDaemonBlockCount(): number;
/**
* Initialize the daemon and the fee info
*/
init(): Promise<void>;
/**
* Update the daemon info
*/
updateDaemonInfo(): Promise<void>;
/**
* Get the node fee and address
*/
nodeFee(): [string, number];
/**
* @param blockHashCheckpoints Hashes of the last known blocks. Later
* blocks (higher block height) should be
* ordered at the front of the array.
*
* @param startHeight Height to start taking blocks from
* @param startTimestamp Block timestamp to start taking blocks from
*
* Gets blocks from the daemon. Blocks are returned starting from the last
* known block hash (if higher than the startHeight/startTimestamp)
*/
getWalletSyncData(blockHashCheckpoints: string[], startHeight: number, startTimestamp: number): Promise<[Block[], TopBlock | boolean]>;
/**
* @returns Returns a mapping of transaction hashes to global indexes
*
* Get global indexes for the transactions in the range
* [startHeight, endHeight]
*/
getGlobalIndexesForRange(startHeight: number, endHeight: number): Promise<Map<string, number[]>>;
getCancelledTransactions(transactionHashes: string[]): Promise<string[]>;
/**
* Gets random outputs for the given amounts. requestedOuts per. Usually mixin+1.
*
* @returns Returns an array of amounts to global indexes and keys. There
* should be requestedOuts indexes if the daemon fully fulfilled
* our request.
*/
getRandomOutputsByAmount(amounts: number[], requestedOuts: number): Promise<[number, [number, string][]][]>;
sendTransaction(rawTransaction: string): Promise<WalletError>;
getConnectionInfo(): DaemonConnection;
getConnectionString(): string;
private rawBlocksToBlocks;
/**
* Update the fee address and amount
*/
private updateFeeInfo;
private makeGetRequest;
private makePostRequest;
/**
* Makes a get request to the given endpoint
*/
private makeRequest;
}

+ 519
- 0
dist/lib/Daemon.js View File

@@ -0,0 +1,519 @@
"use strict";
// Copyright (c) 2018-2020, Zpalmtree
//
// Please see the included LICENSE file for more information.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Daemon = void 0;
const _ = require("lodash");
const request = require("request-promise-native");
const events_1 = require("events");
const fedoragold_utils_1 = require("fedoragold-utils");
const http = require("http");
const https = require("https");
const Assert_1 = require("./Assert");
const Config_1 = require("./Config");
const ValidateParameters_1 = require("./ValidateParameters");
const Logger_1 = require("./Logger");
const WalletError_1 = require("./WalletError");
const Types_1 = require("./Types");
/**
* @noInheritDoc
*/
class Daemon extends events_1.EventEmitter {
/**
* @param host The host to access the API on. Can be an IP, or a URL, for
* example, 1.1.1.1, or blockapi.turtlepay.io
*
* @param port The port to access the API on. Normally 30157 for a Fedoragold
* daemon, 80 for a HTTP api, or 443 for a HTTPS api.
*
* @param ssl You can optionally specify whether this API supports
* ssl/tls/https to save a couple of requests.
* If you're not sure, do not specify this parameter -
* we will work it out automatically.
*/
constructor(host, port, ssl, useRawBlocks) {
super();
/**
* Whether we should use https for our requests
*/
this.ssl = true;
/**
* Have we determined if we should be using ssl or not?
*/
this.sslDetermined = false;
/**
* The address node fees will go to
*/
this.feeAddress = '';
/**
* The amount of the node fee in atomic units
*/
this.feeAmount = 0;
/**
* The amount of blocks the daemon we're connected to has
*/
this.localDaemonBlockCount = 0;
/**
* The amount of blocks the network has
*/
this.networkBlockCount = 0;
/**
* The amount of peers we have, incoming+outgoing
*/
this.peerCount = 0;
/**
* The hashrate of the last known local block
*/
this.lastKnownHashrate = 0;
/**
* The number of blocks to download per /getwalletsyncdata request
*/
this.blockCount = 100;
this.config = new Config_1.Config();
this.httpAgent = new http.Agent({
keepAlive: true,
keepAliveMsecs: 20000,
maxSockets: Infinity,
});
this.httpsAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 20000,
maxSockets: Infinity,
});
/**
* Last time the network height updated. If this goes over the configured
* limit, we'll emit deadnode.
*/
this.lastUpdatedNetworkHeight = new Date();
/**
* Last time the daemon height updated. If this goes over the configured
* limit, we'll emit deadnode.
*/
this.lastUpdatedLocalHeight = new Date();
/**
* Did our last contact with the daemon succeed. Set to true initially
* so initial failure to connect will fire disconnect event.
*/
this.connected = true;
this.useRawBlocks = true;
this.setMaxListeners(0);
Assert_1.assertString(host, 'host');
Assert_1.assertNumber(port, 'port');
Assert_1.assertBooleanOrUndefined(ssl, 'ssl');
Assert_1.assertBooleanOrUndefined(useRawBlocks, 'useRawBlocks');
this.host = host;
this.port = port;
/* Raw IP's very rarely support SSL. This fixes the warning from
https://github.com/nodejs/node/pull/23329 */
if (/^(?!0)(?!.*\.$)((1?\d?\d|25[0-5]|2[0-4]\d)(\.|$)){4}$/.test(this.host) && ssl === undefined) {
ssl = false;
}
if (ssl !== undefined) {
this.ssl = ssl;
this.sslDetermined = true;
}
if (useRawBlocks !== undefined) {
this.useRawBlocks = useRawBlocks;
}
}
updateConfig(config) {
this.config = Config_1.MergeConfig(config);
this.blockCount = this.config.blocksPerDaemonRequest;
}
/**
* Get the amount of blocks the network has
*/
getNetworkBlockCount() {
return this.networkBlockCount;
}
/**
* Get the amount of blocks the daemon we're connected to has
*/
getLocalDaemonBlockCount() {
return this.localDaemonBlockCount;
}
/**
* Initialize the daemon and the fee info
*/
init() {
return __awaiter(this, void 0, void 0, function* () {
/* Note - if one promise throws, the other will be cancelled */
yield Promise.all([this.updateDaemonInfo(), this.updateFeeInfo()]);
if (this.networkBlockCount === 0) {
this.emit('deadnode');
}
});
}
/**
* Update the daemon info
*/
updateDaemonInfo() {
return __awaiter(this, void 0, void 0, function* () {
let info;
const haveDeterminedSsl = this.sslDetermined;
try {
[info] = yield this.makeGetRequest('/info');
}
catch (err) {
Logger_1.logger.log('Failed to update daemon info: ' + err.toString(), Logger_1.LogLevel.INFO, [Logger_1.LogCategory.DAEMON]);
const diff1 = (new Date().getTime() - this.lastUpdatedNetworkHeight.getTime()) / 1000;
const diff2 = (new Date().getTime() - this.lastUpdatedLocalHeight.getTime()) / 1000;
if (diff1 > this.config.maxLastUpdatedNetworkHeightInterval
|| diff2 > this.config.maxLastUpdatedLocalHeightInterval) {
this.emit('deadnode');
}
return;
}
/* Possibly determined daemon type was HTTPS, got a valid response,
but not valid data. Manually set to http and try again. */
if (info.height === undefined && !haveDeterminedSsl) {
this.sslDetermined = true;
this.ssl = false;
const diff1 = (new Date().getTime() - this.lastUpdatedNetworkHeight.getTime()) / 1000;
const diff2 = (new Date().getTime() - this.lastUpdatedLocalHeight.getTime()) / 1000;
if (diff1 > this.config.maxLastUpdatedNetworkHeightInterval
|| diff2 > this.config.maxLastUpdatedLocalHeightInterval) {
this.emit('deadnode');
}
return this.updateDaemonInfo();
}
if (this.localDaemonBlockCount !== info.height
|| this.networkBlockCount !== info.networkHeight) {
this.emit('heightchange', info.height, info.networkHeight);
this.lastUpdatedNetworkHeight = new Date();
this.lastUpdatedLocalHeight = new Date();
}
else {
const diff1 = (new Date().getTime() - this.lastUpdatedNetworkHeight.getTime()) / 1000;
const diff2 = (new Date().getTime() - this.lastUpdatedLocalHeight.getTime()) / 1000;
if (diff1 > this.config.maxLastUpdatedNetworkHeightInterval
|| diff2 > this.config.maxLastUpdatedLocalHeightInterval) {
this.emit('deadnode');
}
}
this.localDaemonBlockCount = info.height;
this.networkBlockCount = info.networkHeight;
if (this.networkBlockCount > 0) {
this.networkBlockCount--;
}
this.peerCount = info.incomingConnections + info.outgoingConnections;
this.lastKnownHashrate = info.hashrate;
});
}
/**
* Get the node fee and address
*/
nodeFee() {
return [this.feeAddress, this.feeAmount];
}
/**
* @param blockHashCheckpoints Hashes of the last known blocks. Later
* blocks (higher block height) should be
* ordered at the front of the array.
*
* @param startHeight Height to start taking blocks from
* @param startTimestamp Block timestamp to start taking blocks from
*
* Gets blocks from the daemon. Blocks are returned starting from the last
* known block hash (if higher than the startHeight/startTimestamp)
*/
getWalletSyncData(blockHashCheckpoints, startHeight, startTimestamp) {
return __awaiter(this, void 0, void 0, function* () {
let data;
const endpoint = this.useRawBlocks ? '/sync/raw' : '/sync';
try {
[data] = yield this.makePostRequest(endpoint, {
count: this.blockCount,
checkpoints: blockHashCheckpoints,
skipCoinbaseTransactions: !this.config.scanCoinbaseTransactions,
height: startHeight,
timestamp: startTimestamp,
});
}
catch (err) {
this.blockCount = Math.ceil(this.blockCount / 4);
Logger_1.logger.log(`Failed to get wallet sync data: ${err.toString()}. Lowering block count to ${this.blockCount}`, Logger_1.LogLevel.INFO, [Logger_1.LogCategory.DAEMON]);
return [[], false];
}
/* The node is not dead if we're fetching blocks. */
if (data.blocks.length >= 0) {
Logger_1.logger.log(`Fetched ${data.blocks.length} blocks from the daemon`, Logger_1.LogLevel.DEBUG, [Logger_1.LogCategory.DAEMON]);
if (this.blockCount !== this.config.blocksPerDaemonRequest) {
this.blockCount = Math.min(this.config.blocksPerDaemonRequest, this.blockCount * 2);
Logger_1.logger.log(`Successfully fetched sync data, raising block count to ${this.blockCount}`, Logger_1.LogLevel.DEBUG, [Logger_1.LogCategory.DAEMON]);
}
this.lastUpdatedNetworkHeight = new Date();
this.lastUpdatedLocalHeight = new Date();
}
const blocks = this.useRawBlocks
? yield this.rawBlocksToBlocks(data.blocks)
: data.blocks.map(Types_1.Block.fromJSON);
if (data.synced && data.topBlock && data.topBlock.height && data.topBlock.hash) {
return [blocks, data.topBlock];
}
return [blocks, true];
});
}
/**
* @returns Returns a mapping of transaction hashes to global indexes
*
* Get global indexes for the transactions in the range
* [startHeight, endHeight]
*/
getGlobalIndexesForRange(startHeight, endHeight) {
return __awaiter(this, void 0, void 0, function* () {
try {
const [data] = yield this.makeGetRequest(`/indexes/${startHeight}/${endHeight}`);
const indexes = new Map();
for (const index of data) {
indexes.set(index.hash, index.indexes);
}
return indexes;
}
catch (err) {
Logger_1.logger.log('Failed to get global indexes: ' + err.toString(), Logger_1.LogLevel.ERROR, Logger_1.LogCategory.DAEMON);
return new Map();
}
});
}
getCancelledTransactions(transactionHashes) {
return __awaiter(this, void 0, void 0, function* () {
try {
const [data] = yield this.makePostRequest('/transaction/status', transactionHashes);
return data.notFound || [];
}
catch (err) {
Logger_1.logger.log('Failed to get transactions status: ' + err.toString(), Logger_1.LogLevel.ERROR, Logger_1.LogCategory.DAEMON);
return [];
}
});
}
/**
* Gets random outputs for the given amounts. requestedOuts per. Usually mixin+1.
*
* @returns Returns an array of amounts to global indexes and keys. There
* should be requestedOuts indexes if the daemon fully fulfilled
* our request.
*/
getRandomOutputsByAmount(amounts, requestedOuts) {
return __awaiter(this, void 0, void 0, function* () {
let data;
try {
[data] = yield this.makePostRequest('/indexes/random', {
amounts: amounts,
count: requestedOuts,
});
}
catch (err) {
Logger_1.logger.log('Failed to get random outs: ' + err.toString(), Logger_1.LogLevel.ERROR, [Logger_1.LogCategory.TRANSACTIONS, Logger_1.LogCategory.DAEMON]);
return [];
}
const outputs = [];
for (const output of data) {
const indexes = [];
for (const outs of output.outputs) {
indexes.push([outs.index, outs.key]);
}
/* Sort by output index to make it hard to determine real one */
outputs.push([output.amount, _.sortBy(indexes, ([index]) => index)]);
}
return outputs;
});
}
sendTransaction(rawTransaction) {
return __awaiter(this, void 0, void 0, function* () {
try {
const [result, statusCode] = yield this.makePostRequest('/transaction', rawTransaction);
if (statusCode === 202) {
return WalletError_1.SUCCESS;
}
if (result && result.error && result.error.code) {
const code = WalletError_1.WalletErrorCode[result.error.code] !== undefined
? result.error.code
: WalletError_1.WalletErrorCode.UNKNOWN_ERROR;
return new WalletError_1.WalletError(code, result.error.message);
}
return new WalletError_1.WalletError(WalletError_1.WalletErrorCode.UNKNOWN_ERROR);
}
catch (err) {
Logger_1.logger.log('Failed to send transaction: ' + err.toString(), Logger_1.LogLevel.ERROR, [Logger_1.LogCategory.TRANSACTIONS, Logger_1.LogCategory.DAEMON]);
return new WalletError_1.WalletError(WalletError_1.WalletErrorCode.DAEMON_ERROR, err.toString());
}
});
}
getConnectionInfo() {
return {
host: this.host,
port: this.port,
ssl: this.ssl,
sslDetermined: this.sslDetermined,
};
}
getConnectionString() {
return this.host + ':' + this.port;
}
rawBlocksToBlocks(rawBlocks) {
return __awaiter(this, void 0, void 0, function* () {
const result = [];
for (const rawBlock of rawBlocks) {
const block = yield fedoragold_utils_1.Block.from(rawBlock.blob, this.config);
this.emit('rawblock', block);
this.emit('rawtransaction', block.minerTransaction);
let coinbaseTransaction;
if (this.config.scanCoinbaseTransactions) {
const keyOutputs = [];
for (const output of block.minerTransaction.outputs) {
if (output.type === fedoragold_utils_1.TransactionOutputs.OutputType.KEY) {
const o = output;
keyOutputs.push(new Types_1.KeyOutput(o.key, o.amount.toJSNumber()));
}
}
coinbaseTransaction = new Types_1.RawCoinbaseTransaction(keyOutputs, yield block.minerTransaction.hash(), block.minerTransaction.publicKey, block.minerTransaction.unlockTime > Number.MAX_SAFE_INTEGER
? block.minerTransaction.unlockTime.toJSNumber()
: block.minerTransaction.unlockTime);
}
const transactions = [];
for (const tx of rawBlock.transactions) {
const rawTX = yield fedoragold_utils_1.Transaction.from(tx);
this.emit('rawtransaction', tx);
const keyOutputs = [];
const keyInputs = [];
for (const output of rawTX.outputs) {
if (output.type === fedoragold_utils_1.TransactionOutputs.OutputType.KEY) {
const o = output;
keyOutputs.push(new Types_1.KeyOutput(o.key, o.amount.toJSNumber()));
}
}
for (const input of rawTX.inputs) {
if (input.type === fedoragold_utils_1.TransactionInputs.InputType.KEY) {
const i = input;
keyInputs.push(new Types_1.KeyInput(i.amount.toJSNumber(), i.keyImage));
}
}
transactions.push(new Types_1.RawTransaction(keyOutputs, yield rawTX.hash(), rawTX.publicKey, rawTX.unlockTime > Number.MAX_SAFE_INTEGER
? rawTX.unlockTime.toJSNumber()
: rawTX.unlockTime, rawTX.paymentId || '', keyInputs));
}
result.push(new Types_1.Block(transactions, block.height, yield block.hash(), Math.floor(block.timestamp.getTime() / 1000), coinbaseTransaction));
}
return result;
});
}
/**
* Update the fee address and amount
*/
updateFeeInfo() {
return __awaiter(this, void 0, void 0, function* () {
let feeInfo;
try {
[feeInfo] = yield this.makeGetRequest('/fee');
}
catch (err) {
Logger_1.logger.log('Failed to update fee info: ' + err.toString(), Logger_1.LogLevel.INFO, [Logger_1.LogCategory.DAEMON]);
return;
}
if (feeInfo.address === '') {
return;
}
const integratedAddressesAllowed = false;
const err = (yield ValidateParameters_1.validateAddresses(new Array(feeInfo.address), integratedAddressesAllowed, this.config)).errorCode;
if (err !== WalletError_1.WalletErrorCode.SUCCESS) {
Logger_1.logger.log('Failed to validate address from daemon fee info: ' + err.toString(), Logger_1.LogLevel.WARNING, [Logger_1.LogCategory.DAEMON]);
return;
}
if (feeInfo.amount > 0) {
this.feeAddress = feeInfo.address;
this.feeAmount = feeInfo.amount;
}
});
}
makeGetRequest(endpoint) {
return __awaiter(this, void 0, void 0, function* () {
return this.makeRequest(endpoint, 'GET');
});
}
makePostRequest(endpoint, body) {
return __awaiter(this, void 0, void 0, function* () {
return this.makeRequest(endpoint, 'POST', body);
});
}
/**
* Makes a get request to the given endpoint
*/
makeRequest(endpoint, method, body) {
return __awaiter(this, void 0, void 0, function* () {
const options = {
body,
headers: { 'User-Agent': this.config.customUserAgentString },
json: true,
method,
timeout: this.config.requestTimeout,
resolveWithFullResponse: true,
};
try {
/* Start by trying HTTPS if we haven't determined whether it's
HTTPS or HTTP yet. */
const protocol = this.sslDetermined ? (this.ssl ? 'https' : 'http') : 'https';
const url = `${protocol}://${this.host}:${this.port}${endpoint}`;
Logger_1.logger.log(`Making request to ${url} with params ${body ? JSON.stringify(body) : '{}'}`, Logger_1.LogLevel.TRACE, [Logger_1.LogCategory.DAEMON]);
const response = yield request(Object.assign(Object.assign(Object.assign({ agent: protocol === 'https' ? this.httpsAgent : this.httpAgent }, options), this.config.customRequestOptions), { url }));
/* Cool, https works. Store for later. */
if (!this.sslDetermined) {
this.ssl = true;
this.sslDetermined = true;
}
if (!this.connected) {
this.emit('connect');
this.connected = true;
}
Logger_1.logger.log(`Got response from ${url} with body ${JSON.stringify(response.body)}`, Logger_1.LogLevel.TRACE, [Logger_1.LogCategory.DAEMON]);
return [response.body, response.statusCode];
}
catch (err) {
/* No point trying again with SSL - we already have decided what
type it is. */
if (this.sslDetermined) {
if (this.connected) {
this.emit('disconnect', err);
this.connected = false;
}
throw err;
}
try {
/* Lets try HTTP now. */
const url = `http://${this.host}:${this.port}${endpoint}`;
Logger_1.logger.log(`Making request to ${url} with params ${body ? JSON.stringify(body) : '{}'}`, Logger_1.LogLevel.TRACE, [Logger_1.LogCategory.DAEMON]);
const response = yield request(Object.assign(Object.assign({ agent: this.httpAgent }, options), {
/* Lets try HTTP now. */
url }));
this.ssl = false;
this.sslDetermined = true;
if (!this.connected) {
this.emit('connect');
this.connected = true;
}
Logger_1.logger.log(`Got response from ${url} with body ${JSON.stringify(response.body)}`, Logger_1.LogLevel.TRACE, [Logger_1.LogCategory.DAEMON]);
return [response.body, response.statusCode];
}
catch (err) {
if (this.connected) {
this.emit('disconnect', err);
this.connected = false;
}
throw err;
}
}
});
}
}
exports.Daemon = Daemon;

+ 33
- 0
dist/lib/FeeType.d.ts View File

@@ -0,0 +1,33 @@
import { IConfig } from './Config';
export declare class FeeType {
/**
* Uses the lowest fee possible. Currently is a fee per byte of 1.953125.
*/
static MinimumFee(config?: IConfig): FeeType;
/**
* Specify a custom fee per byte to use. Can be a fractional amount.
* Should be in atomic units.
* Can not be lower than the minimum fee per byte allowed (currently 1.953125)
*
* Note that the fee per byte of the resulting transaction may be higher
* than the specified fee per byte, but it will not be lower. It will also
* not be any more than 2x higher than the specified fee per byte.
* The fee per byte being potentially higher is due to how the transaction
* size estimate process works.
*
* @param feePerByte The custom fee per byte value to use.
*/
static FeePerByte(feePerByte: number): FeeType;
/**
* Specify a fixed fee to use. The transaction will fail if the calculated
* minimum fee per byte for the transaction is lower than the specified
* fixed fee.
*
* @param fixedFee The fixed fee to use
*/
static FixedFee(fixedFee: number): FeeType;
isFixedFee: boolean;
isFeePerByte: boolean;
fixedFee: number;
feePerByte: number;
}

+ 55
- 0
dist/lib/FeeType.js View File

@@ -0,0 +1,55 @@
"use strict";
// Copyright (c) 2019-2020, Zpalmtree
//
// Please see the included LICENSE file for more information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.FeeType = void 0;
const Config_1 = require("./Config");
class FeeType {
constructor() {