edge-currency-plugins 3.11.0 → 3.13.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.
- package/android/src/main/assets/edge-currency-plugins/edge-currency-plugins.js +48 -47
- package/lib/common/plugin/types.js +6 -0
- package/lib/common/utxobased/engine/ServerStates.js +196 -95
- package/lib/common/utxobased/engine/UtxoEngine.js +17 -4
- package/lib/common/utxobased/engine/UtxoWalletTools.js +15 -2
- package/lib/common/utxobased/engine/types.js +7 -1
- package/lib/common/utxobased/info/bitcoin.js +3 -3
- package/lib/common/utxobased/info/bitcoincash.js +1 -1
- package/lib/common/utxobased/info/bitcoingold.js +1 -1
- package/lib/common/utxobased/info/bitcoingoldtestnet.js +1 -1
- package/lib/common/utxobased/info/dash.js +3 -2
- package/lib/common/utxobased/info/digibyte.js +2 -2
- package/lib/common/utxobased/info/dogecoin.js +2 -2
- package/lib/common/utxobased/info/ecash.js +1 -1
- package/lib/common/utxobased/info/feathercoin.js +1 -1
- package/lib/common/utxobased/info/litecoin.js +4 -4
- package/lib/common/utxobased/info/pivx.js +3 -2
- package/lib/common/utxobased/info/qtum.js +2 -2
- package/lib/common/utxobased/info/ravencoin.js +1 -1
- package/lib/common/utxobased/info/smartcash.js +1 -1
- package/lib/common/utxobased/info/ufo.js +1 -1
- package/lib/common/utxobased/info/vertcoin.js +2 -1
- package/lib/common/utxobased/info/zcoin.js +2 -2
- package/lib/common/utxobased/keymanager/keymanager.js +56 -2
- package/lib/common/utxobased/keymanager/types.js +28 -1
- package/lib/common/utxobased/network/Blockbook.js +10 -2
- package/lib/src/common/plugin/types.d.ts +7 -1
- package/lib/src/common/utxobased/engine/ServerStates.d.ts +21 -0
- package/lib/src/common/utxobased/engine/UtxoWalletTools.d.ts +2 -0
- package/lib/src/common/utxobased/engine/types.d.ts +1 -0
- package/lib/src/common/utxobased/keymanager/keymanager.d.ts +3 -2
- package/lib/src/common/utxobased/keymanager/types.d.ts +19 -0
- package/lib/test/common/utxobased/engine/ServerStates.spec.d.ts +1 -0
- package/lib/test/common/utxobased/keymanager/coins/altcointestfixtures.d.ts +5 -0
- package/lib/test/common/utxobased/keymanager/messagePrefix.spec.d.ts +1 -0
- package/package.json +1 -1
|
@@ -48,7 +48,7 @@ const currencyInfo = {
|
|
|
48
48
|
const engineInfo = {
|
|
49
49
|
serverConfigs: [
|
|
50
50
|
{
|
|
51
|
-
type: 'blockbook
|
|
51
|
+
type: 'blockbook',
|
|
52
52
|
uris: ['https://vtc-wusa1.edge.app']
|
|
53
53
|
}
|
|
54
54
|
],
|
|
@@ -77,6 +77,7 @@ const engineInfo = {
|
|
|
77
77
|
segwit: true,
|
|
78
78
|
coinType: 28,
|
|
79
79
|
prefixes: {
|
|
80
|
+
// Vertcoin Core genuinely uses Bitcoin's magic; not an oversight.
|
|
80
81
|
messagePrefix: ['\x18Bitcoin Signed Message:\n'],
|
|
81
82
|
wif: [0x80],
|
|
82
83
|
legacyXPriv: [0x0488ade4],
|
|
@@ -45,7 +45,7 @@ var _commonInfo = require('./commonInfo');
|
|
|
45
45
|
const engineInfo = {
|
|
46
46
|
serverConfigs: [
|
|
47
47
|
{
|
|
48
|
-
type: 'blockbook
|
|
48
|
+
type: 'blockbook',
|
|
49
49
|
uris: ['https://firo-eusa1.edge.app']
|
|
50
50
|
},
|
|
51
51
|
{
|
|
@@ -78,7 +78,7 @@ var _commonInfo = require('./commonInfo');
|
|
|
78
78
|
segwit: false,
|
|
79
79
|
coinType: 136,
|
|
80
80
|
prefixes: {
|
|
81
|
-
messagePrefix: ['\
|
|
81
|
+
messagePrefix: ['\x16Zcoin Signed Message:\n'],
|
|
82
82
|
wif: [0xd2],
|
|
83
83
|
legacyXPriv: [0x0488ade4],
|
|
84
84
|
legacyXPub: [0x0488b21e],
|
|
@@ -21,6 +21,12 @@ var _undefinedIfEmptyString = require('../../../util/undefinedIfEmptyString');
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
24
30
|
var _bip69 = require('./bip69');
|
|
25
31
|
|
|
26
32
|
|
|
@@ -938,14 +944,62 @@ const wifToPrivateKeyEncodingInternal = (
|
|
|
938
944
|
}).publicKey.toString('hex')
|
|
939
945
|
} exports.privateKeyEncodingToPubkey = privateKeyEncodingToPubkey;
|
|
940
946
|
|
|
941
|
-
|
|
947
|
+
/**
|
|
948
|
+
* The `segwitType` to hand `bitcoinjs-message`, or `undefined` to leave the
|
|
949
|
+
* header byte in the legacy Electrum range. Only the BIP137 encoding cares
|
|
950
|
+
* about the derivation purpose, so only it resolves one.
|
|
951
|
+
*/
|
|
952
|
+
function getBip137SegwitType(
|
|
953
|
+
signatureFormat,
|
|
954
|
+
format
|
|
955
|
+
) {
|
|
956
|
+
if (signatureFormat !== 'bip137') return undefined
|
|
957
|
+
const purposeType = bip43PurposeNumberToTypeEnum(
|
|
958
|
+
parseInt(format.replace('bip', ''))
|
|
959
|
+
)
|
|
960
|
+
switch (purposeType) {
|
|
961
|
+
case BIP43PurposeTypeEnum.Segwit:
|
|
962
|
+
return 'p2wpkh'
|
|
963
|
+
case BIP43PurposeTypeEnum.WrappedSegwit:
|
|
964
|
+
return 'p2sh(p2wpkh)'
|
|
965
|
+
default:
|
|
966
|
+
return undefined
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
function signMessageBase64(
|
|
971
|
+
message,
|
|
972
|
+
privateKey,
|
|
973
|
+
format,
|
|
974
|
+
coin,
|
|
975
|
+
signatureFormat = 'electrum'
|
|
976
|
+
) {
|
|
942
977
|
const ECPair = getECPair()
|
|
943
978
|
const keyPair = ECPair.fromPrivateKey(Buffer.from(privateKey, 'hex'))
|
|
944
979
|
if (keyPair.privateKey == null) {
|
|
945
980
|
throw new Error('Address could not sign message')
|
|
946
981
|
}
|
|
982
|
+
// BIP137 encodes the address type in the signature's header byte. Native
|
|
983
|
+
// SegWit (bip84 / P2WPKH) and nested SegWit (bip49 / P2SH-P2WPKH) each have
|
|
984
|
+
// their own header range; verifiers such as Bringin reject a SegWit address
|
|
985
|
+
// whose message was signed with a legacy (bip44) header byte. The derivation
|
|
986
|
+
// path is what tells us the script type, so no caller has to infer it from
|
|
987
|
+
// the address string. Callers opt in, since emitting a BIP137 header to a
|
|
988
|
+
// verifier that expects the legacy Electrum encoding is just as broken.
|
|
989
|
+
// The purpose lookup stays inside the BIP137 branch on purpose:
|
|
990
|
+
// `bip43PurposeNumberToTypeEnum` throws on a purpose it does not map, so
|
|
991
|
+
// computing it unconditionally would let a future `CurrencyFormat` (bip86
|
|
992
|
+
// Taproot being the obvious candidate) break the default Electrum path,
|
|
993
|
+
// which never needs it.
|
|
994
|
+
const segwitType = getBip137SegwitType(signatureFormat, format)
|
|
995
|
+
// Magic-hash the message with the coin's own prefix (e.g. "Litecoin Signed
|
|
996
|
+
// Message:\n") so the signature verifies against that coin's addresses.
|
|
997
|
+
// Every UTXO coin routes through here, not just Bitcoin.
|
|
998
|
+
const messagePrefix = _coinmapper.getCoinFromString.call(void 0, coin).prefixes.messagePrefix[0]
|
|
947
999
|
return _bitcoinjsmessage2.default
|
|
948
|
-
.sign(message, keyPair.privateKey, keyPair.compressed
|
|
1000
|
+
.sign(message, keyPair.privateKey, keyPair.compressed, messagePrefix, {
|
|
1001
|
+
segwitType
|
|
1002
|
+
})
|
|
949
1003
|
.toString('base64')
|
|
950
1004
|
} exports.signMessageBase64 = signMessageBase64;
|
|
951
1005
|
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _cleaners = require('cleaners');
|
|
2
2
|
var _types = require('edge-core-js/types');
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* How to encode the header byte of a signed message.
|
|
6
|
+
* - `electrum`: the legacy format, whose header carries only the recovery id
|
|
7
|
+
* and key compression. Every verifier understands it, but it says nothing
|
|
8
|
+
* about the script type.
|
|
9
|
+
* - `bip137`: additionally encodes the signing address' script type, which
|
|
10
|
+
* verifiers such as Bringin require for SegWit addresses.
|
|
11
|
+
*/
|
|
12
|
+
const asUtxoSignatureFormat = _cleaners.asValue.call(void 0, 'electrum', 'bip137'); exports.asUtxoSignatureFormat = asUtxoSignatureFormat
|
|
13
|
+
|
|
14
|
+
|
|
4
15
|
|
|
5
16
|
|
|
6
17
|
|
|
@@ -27,6 +38,22 @@ function asMaybeError(name) {
|
|
|
27
38
|
}
|
|
28
39
|
}
|
|
29
40
|
|
|
41
|
+
/**
|
|
42
|
+
* The wallet cannot sign for the requested address: either it does not derive
|
|
43
|
+
* it, or the string is not an address of this chain at all. Callers get a
|
|
44
|
+
* stable `name` to branch on instead of matching against the message prose.
|
|
45
|
+
*/
|
|
46
|
+
class AddressNotOwnedError extends Error {
|
|
47
|
+
constructor() {
|
|
48
|
+
super('Wallet does not own the address to sign with')
|
|
49
|
+
this.name = 'AddressNotOwnedError'
|
|
50
|
+
}
|
|
51
|
+
} exports.AddressNotOwnedError = AddressNotOwnedError;
|
|
52
|
+
|
|
53
|
+
const asMaybeAddressNotOwnedError = asMaybeError(
|
|
54
|
+
'AddressNotOwnedError'
|
|
55
|
+
); exports.asMaybeAddressNotOwnedError = asMaybeAddressNotOwnedError
|
|
56
|
+
|
|
30
57
|
const asMaybeInsufficientFundsErrorPlus = asMaybeError(
|
|
31
58
|
// Share the same name because this error type is a subtype of
|
|
32
59
|
// InsufficientFundsError and therefore backwards compatible
|
|
@@ -177,8 +177,16 @@ var _Socket = require('./Socket');
|
|
|
177
177
|
|
|
178
178
|
|
|
179
179
|
{
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
try {
|
|
181
|
+
const value = yield { ...message }
|
|
182
|
+
deferred.resolve(value)
|
|
183
|
+
} catch (error) {
|
|
184
|
+
// The socket reports a failed request (an error response, the
|
|
185
|
+
// request timeout, the socket closing) by throwing into this
|
|
186
|
+
// generator. Without this catch the deferred stays pending forever
|
|
187
|
+
// and the caller hangs instead of seeing the failure.
|
|
188
|
+
deferred.reject(error)
|
|
189
|
+
}
|
|
182
190
|
return false
|
|
183
191
|
}
|
|
184
192
|
const generator = taskGeneratorFn()
|
|
@@ -116,7 +116,13 @@ export interface EngineInfo {
|
|
|
116
116
|
txSpecificHandling?: (tx: TransactionData, specialTx: unknown) => TransactionData;
|
|
117
117
|
}
|
|
118
118
|
export interface ServerConfig {
|
|
119
|
-
|
|
119
|
+
/**
|
|
120
|
+
* - `blockbook`: a public Blockbook HTTP server. No credentials are sent.
|
|
121
|
+
* - `blockbook-nownode`: a NOWNodes Blockbook HTTP server. Requests carry
|
|
122
|
+
* the `nowNodesApiKey` init option as the `api-key` header, and the
|
|
123
|
+
* server is skipped when no key is configured.
|
|
124
|
+
*/
|
|
125
|
+
type: 'blockbook' | 'blockbook-nownode';
|
|
120
126
|
uris: string[];
|
|
121
127
|
}
|
|
122
128
|
/**
|
|
@@ -23,6 +23,11 @@ interface ServerStateConfig {
|
|
|
23
23
|
pluginInfo: PluginInfo;
|
|
24
24
|
pluginState: PluginState;
|
|
25
25
|
walletInfo: SafeWalletInfo;
|
|
26
|
+
/**
|
|
27
|
+
* Upper bound on any single broadcast attempt. Defaults to the same 30
|
|
28
|
+
* seconds the socket layer uses for a request. Exposed for tests.
|
|
29
|
+
*/
|
|
30
|
+
broadcastTimeoutMs?: number;
|
|
26
31
|
}
|
|
27
32
|
export interface ServerStates {
|
|
28
33
|
setPickNextTaskCB: (callback: (uri: string) => AsyncGenerator<WsTask<unknown> | boolean>) => void;
|
|
@@ -46,5 +51,21 @@ export interface ServerStates {
|
|
|
46
51
|
transactionSpecialQueryTask: (serverUri: string, txId: string) => WsTaskGenerator<unknown>;
|
|
47
52
|
utxoListQueryTask: (serverUri: string, address: string) => WsTaskGenerator<AddressUtxosResponse>;
|
|
48
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* How long broadcastTx gives the first wave (our sockets and Edge's own HTTP
|
|
56
|
+
* servers) before it also sends the transaction to the NOWNodes HTTP servers.
|
|
57
|
+
* NOWNodes is a third party, so it should only see a transaction when our own
|
|
58
|
+
* infrastructure has not already carried it. A first wave that fails outright
|
|
59
|
+
* does not wait this long; the second wave fires as soon as it has all failed.
|
|
60
|
+
*/
|
|
61
|
+
export declare const NOWNODES_BROADCAST_DELAY_MS = 2000;
|
|
62
|
+
/**
|
|
63
|
+
* Every broadcast attempt is counted toward "all attempts failed", so every
|
|
64
|
+
* attempt must settle. Sockets already expire a request after 30 seconds
|
|
65
|
+
* (Socket.ts); HTTP has no such bound of its own, and a server that accepts
|
|
66
|
+
* the connection and never answers would otherwise hold the whole broadcast
|
|
67
|
+
* open. This mirrors the socket figure.
|
|
68
|
+
*/
|
|
69
|
+
export declare const BROADCAST_ATTEMPT_TIMEOUT_MS = 30000;
|
|
49
70
|
export declare function makeServerStates(config: ServerStateConfig): ServerStates;
|
|
50
71
|
export {};
|
|
@@ -2,6 +2,7 @@ import { AddressPath, ChangePath, CurrencyFormat, PluginInfo } from '../../plugi
|
|
|
2
2
|
import { ScriptTemplate } from '../info/scriptTemplates/types';
|
|
3
3
|
import { PublicKey } from '../keymanager/cleaners';
|
|
4
4
|
import { PrivateKeyEncoding } from '../keymanager/keymanager';
|
|
5
|
+
import { UtxoSignatureFormat } from '../keymanager/types';
|
|
5
6
|
import { CurrencyFormatKeys } from './utils';
|
|
6
7
|
export interface WalletToolsConfig {
|
|
7
8
|
pluginInfo: PluginInfo;
|
|
@@ -48,6 +49,7 @@ interface SignMessageArgs {
|
|
|
48
49
|
path: AddressPath;
|
|
49
50
|
message: string;
|
|
50
51
|
xprivKeys: CurrencyFormatKeys;
|
|
52
|
+
signatureFormat: UtxoSignatureFormat;
|
|
51
53
|
}
|
|
52
54
|
export declare function makeUtxoWalletTools(config: WalletToolsConfig): UtxoWalletTools;
|
|
53
55
|
export {};
|
|
@@ -23,6 +23,7 @@ export interface UtxoTxOtherParams {
|
|
|
23
23
|
export declare type UtxoSignMessageOtherParams = ReturnType<typeof asUtxoSignMessageOtherParams>;
|
|
24
24
|
export declare const asUtxoSignMessageOtherParams: import("cleaners").ObjectCleaner<{
|
|
25
25
|
publicAddress: string;
|
|
26
|
+
signatureFormat: "electrum" | "bip137";
|
|
26
27
|
}>;
|
|
27
28
|
export declare type UtxoSpendInfoOtherParams = ReturnType<typeof asUtxoSpendInfoOtherParams>;
|
|
28
29
|
export declare const asUtxoSpendInfoOtherParams: import("cleaners").ObjectCleaner<{
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { EdgeLog, EdgeMemo } from 'edge-core-js/types';
|
|
2
|
-
import { ChangePath, FeeInfo } from '../../plugin/types';
|
|
2
|
+
import { ChangePath, CurrencyFormat, FeeInfo } from '../../plugin/types';
|
|
3
3
|
import { UtxoData } from '../db/types';
|
|
4
4
|
import { ScriptTemplate, ScriptTemplates } from '../info/scriptTemplates/types';
|
|
5
|
+
import { UtxoSignatureFormat } from './types';
|
|
5
6
|
import * as utxopicker from './utxopicker';
|
|
6
7
|
export declare enum BIP43PurposeTypeEnum {
|
|
7
8
|
Airbitz = "airbitz",
|
|
@@ -202,7 +203,7 @@ export declare const xprivToPrivateKey: (args: XPrivToPrivateKeyArgs) => string;
|
|
|
202
203
|
export declare function privateKeyToWIF(args: PrivateKeyToWIFArgs): string;
|
|
203
204
|
export declare const wifToPrivateKeyEncoding: (args: WIFToPrivateKeyEncodingArgs) => PrivateKeyEncoding;
|
|
204
205
|
export declare function privateKeyEncodingToPubkey(privateKeyEncoding: PrivateKeyEncoding): string;
|
|
205
|
-
export declare function signMessageBase64(message: string, privateKey: string): string;
|
|
206
|
+
export declare function signMessageBase64(message: string, privateKey: string, format: CurrencyFormat, coin: string, signatureFormat?: UtxoSignatureFormat): string;
|
|
206
207
|
export declare function makeTx(args: MakeTxArgs): MakeTxReturn;
|
|
207
208
|
export declare function signTx(args: SignTxArgs): Promise<SignTxReturn>;
|
|
208
209
|
export {};
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { Cleaner } from 'cleaners';
|
|
2
2
|
import { EdgeTokenId, InsufficientFundsError } from 'edge-core-js/types';
|
|
3
|
+
/**
|
|
4
|
+
* How to encode the header byte of a signed message.
|
|
5
|
+
* - `electrum`: the legacy format, whose header carries only the recovery id
|
|
6
|
+
* and key compression. Every verifier understands it, but it says nothing
|
|
7
|
+
* about the script type.
|
|
8
|
+
* - `bip137`: additionally encodes the signing address' script type, which
|
|
9
|
+
* verifiers such as Bringin require for SegWit addresses.
|
|
10
|
+
*/
|
|
11
|
+
export declare const asUtxoSignatureFormat: Cleaner<"electrum" | "bip137">;
|
|
12
|
+
export declare type UtxoSignatureFormat = ReturnType<typeof asUtxoSignatureFormat>;
|
|
3
13
|
interface InsufficientFundsErrorOptsPlus {
|
|
4
14
|
tokenId: EdgeTokenId;
|
|
5
15
|
networkFee?: string;
|
|
@@ -9,5 +19,14 @@ export declare class InsufficientFundsErrorPlus extends InsufficientFundsError {
|
|
|
9
19
|
networkFeeShortage?: string;
|
|
10
20
|
constructor(opts: InsufficientFundsErrorOptsPlus);
|
|
11
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* The wallet cannot sign for the requested address: either it does not derive
|
|
24
|
+
* it, or the string is not an address of this chain at all. Callers get a
|
|
25
|
+
* stable `name` to branch on instead of matching against the message prose.
|
|
26
|
+
*/
|
|
27
|
+
export declare class AddressNotOwnedError extends Error {
|
|
28
|
+
constructor();
|
|
29
|
+
}
|
|
30
|
+
export declare const asMaybeAddressNotOwnedError: Cleaner<AddressNotOwnedError | undefined>;
|
|
12
31
|
export declare const asMaybeInsufficientFundsErrorPlus: Cleaner<InsufficientFundsErrorPlus | undefined>;
|
|
13
32
|
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { CurrencyFormat } from '../../../../../src/common/plugin/types';
|
|
1
2
|
import { AddressTypeEnum, BIP43PurposeTypeEnum, ScriptTypeEnum } from '../../../../../src/common/utxobased/keymanager/keymanager';
|
|
3
|
+
import { UtxoSignatureFormat } from '../../../../../src/common/utxobased/keymanager/types';
|
|
2
4
|
interface SeedToXPrivTests {
|
|
3
5
|
xpriv: string;
|
|
4
6
|
type: BIP43PurposeTypeEnum;
|
|
@@ -34,6 +36,9 @@ interface XPubToPubkeyTests {
|
|
|
34
36
|
interface SignMessageTests {
|
|
35
37
|
wif: string;
|
|
36
38
|
message: string;
|
|
39
|
+
format: CurrencyFormat;
|
|
40
|
+
/** Omitted to exercise the default, which must stay `electrum`. */
|
|
41
|
+
signatureFormat?: UtxoSignatureFormat;
|
|
37
42
|
signature: string;
|
|
38
43
|
}
|
|
39
44
|
interface Coin {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "edge-currency-plugins",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.13.0",
|
|
4
4
|
"description": "Edge currency plugins to fetch and process wallet accounts, balances and transactions.",
|
|
5
5
|
"homepage": "https://edge.app/",
|
|
6
6
|
"repository": "https://github.com/EdgeApp/edge-currency-plugins",
|