@talismn/crypto 0.2.0 → 0.2.1
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/dist/declarations/src/address/encodeAnyAddress.d.ts +5 -0
- package/dist/declarations/src/address/encoding/index.d.ts +1 -1
- package/dist/declarations/src/address/encoding/solana.d.ts +2 -0
- package/dist/declarations/src/address/index.d.ts +2 -1
- package/dist/declarations/src/address/isAddressValid.d.ts +1 -0
- package/dist/declarations/src/derivation/utils.d.ts +3 -12
- package/dist/declarations/src/platform/index.d.ts +4 -4
- package/dist/declarations/src/types/index.d.ts +2 -2
- package/dist/declarations/src/utils/exports.d.ts +2 -1
- package/dist/talismn-crypto.cjs.dev.js +86 -78
- package/dist/talismn-crypto.cjs.prod.js +86 -78
- package/dist/talismn-crypto.esm.js +66 -69
- package/package.json +3 -4
- package/dist/declarations/src/address/encoding/base58.d.ts +0 -3
- package/dist/declarations/src/address/isValidAddress.d.ts +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isAddressValid: (address: string) => boolean;
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { KeypairCurve } from "../types";
|
|
1
|
+
import { AccountPlatform, KeypairCurve } from "../types";
|
|
2
2
|
export declare const deriveKeypair: (seed: Uint8Array, derivationPath: string, curve: KeypairCurve) => import("../types").Keypair;
|
|
3
3
|
export declare const getPublicKeyFromSecret: (secretKey: Uint8Array, curve: KeypairCurve) => Uint8Array;
|
|
4
|
-
export declare const
|
|
5
|
-
/**
|
|
6
|
-
* @dev we only expect suri to contain a mnemonic and derivation path.
|
|
7
|
-
* for other cases see https://polkadot.js.org/docs/keyring/start/suri/
|
|
8
|
-
*/
|
|
9
|
-
export declare const parseSuri: (suri: string) => {
|
|
10
|
-
mnemonic: string;
|
|
11
|
-
derivationPath: string;
|
|
12
|
-
password: string | undefined;
|
|
13
|
-
};
|
|
4
|
+
export declare const addressFromMnemonic: (mnemonic: string, derivationPath: string, curve: KeypairCurve) => Promise<string>;
|
|
14
5
|
export declare const removeHexPrefix: (secretKey: string) => string;
|
|
15
|
-
export declare const parseSecretKey: (secretKey: string,
|
|
6
|
+
export declare const parseSecretKey: (secretKey: string, platform: AccountPlatform) => Uint8Array<ArrayBufferLike>;
|
|
16
7
|
export declare const isValidDerivationPath: (derivationPath: string, curve: KeypairCurve) => Promise<boolean>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AddressEncoding, KeypairCurve
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
1
|
+
import { AccountPlatform, AddressEncoding, KeypairCurve } from "../types";
|
|
2
|
+
export declare const getAccountPlatformFromCurve: (curve: KeypairCurve) => AccountPlatform;
|
|
3
|
+
export declare const getAccountPlatformFromEncoding: (encoding: AddressEncoding) => AccountPlatform;
|
|
4
|
+
export declare const getAccountPlatformFromAddress: (address: string) => AccountPlatform;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export type KeypairCurve = "ecdsa" | "ed25519" | "sr25519" | "ethereum" | "bitcoin-ed25519" | "bitcoin-ecdsa" | "solana";
|
|
2
|
-
export type AddressEncoding = "ss58" | "ethereum" | "bech32m" | "bech32" | "base58check" | "
|
|
2
|
+
export type AddressEncoding = "ss58" | "ethereum" | "bech32m" | "bech32" | "base58check" | "base58solana";
|
|
3
3
|
export type Keypair = {
|
|
4
4
|
type: KeypairCurve;
|
|
5
5
|
secretKey: Uint8Array;
|
|
6
6
|
publicKey: Uint8Array;
|
|
7
7
|
address: string;
|
|
8
8
|
};
|
|
9
|
-
export type
|
|
9
|
+
export type AccountPlatform = "ethereum" | "polkadot" | "bitcoin" | "solana";
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { base58, base64, hex, utf8 } from "@scure/base";
|
|
2
|
+
export { ed25519 } from "@noble/curves/ed25519";
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
var bip39 = require('@scure/bip39');
|
|
4
4
|
var english = require('@scure/bip39/wordlists/english');
|
|
5
5
|
var base = require('@scure/base');
|
|
6
|
+
var ed25519 = require('@noble/curves/ed25519');
|
|
7
|
+
var secp256k1 = require('@noble/curves/secp256k1');
|
|
6
8
|
var bech32 = require('bech32');
|
|
7
9
|
var bs58check = require('bs58check');
|
|
8
10
|
var sha3 = require('@noble/hashes/sha3');
|
|
9
11
|
var utils = require('@noble/hashes/utils');
|
|
10
12
|
var blake2b = require('@noble/hashes/blake2b');
|
|
11
13
|
var blake3$1 = require('@noble/hashes/blake3');
|
|
12
|
-
var secp256k1 = require('@noble/curves/secp256k1');
|
|
13
14
|
var scaleTs = require('scale-ts');
|
|
14
|
-
var ed25519 = require('@noble/curves/ed25519');
|
|
15
15
|
var bip32 = require('@scure/bip32');
|
|
16
16
|
var hmac = require('@noble/hashes/hmac');
|
|
17
17
|
var sha512 = require('@noble/hashes/sha512');
|
|
@@ -140,18 +140,18 @@ const addressEncodingFromCurve = curve => {
|
|
|
140
140
|
case "ethereum":
|
|
141
141
|
return "ethereum";
|
|
142
142
|
case "solana":
|
|
143
|
-
return "
|
|
143
|
+
return "base58solana";
|
|
144
144
|
}
|
|
145
145
|
};
|
|
146
146
|
|
|
147
|
-
const
|
|
147
|
+
const encodeAddressSolana = publicKey => {
|
|
148
|
+
if (publicKey.length !== 32) throw new Error("Public key must be 32 bytes long for Solana base58 encoding");
|
|
148
149
|
return base.base58.encode(publicKey);
|
|
149
150
|
};
|
|
150
|
-
|
|
151
|
-
function isBase58Address(address) {
|
|
151
|
+
function isSolanaAddress(address) {
|
|
152
152
|
try {
|
|
153
|
-
base.base58.decode(address);
|
|
154
|
-
return
|
|
153
|
+
const bytes = base.base58.decode(address);
|
|
154
|
+
return bytes.length === 32;
|
|
155
155
|
} catch (error) {
|
|
156
156
|
return false;
|
|
157
157
|
}
|
|
@@ -287,7 +287,7 @@ const blake2b512 = msg => blake2b.blake2b(msg, {
|
|
|
287
287
|
const getSafeHash = bytes => {
|
|
288
288
|
// cryptographically secure one way hash
|
|
289
289
|
// outputs 44 characters without special characters
|
|
290
|
-
return base.
|
|
290
|
+
return base.base58.encode(blake3$1.blake3(bytes));
|
|
291
291
|
};
|
|
292
292
|
|
|
293
293
|
// Inspired from MIT licensed @polkadot-labs/hdkd-helpers
|
|
@@ -336,10 +336,10 @@ const CACHE$1 = new Map();
|
|
|
336
336
|
const detectAddressEncodingInner = address => {
|
|
337
337
|
if (isEthereumAddress(address)) return "ethereum";
|
|
338
338
|
if (isSs58Address(address)) return "ss58";
|
|
339
|
+
if (isSolanaAddress(address)) return "base58solana";
|
|
339
340
|
if (isBech32mAddress(address)) return "bech32m";
|
|
340
341
|
if (isBech32Address(address)) return "bech32";
|
|
341
342
|
if (isBase58CheckAddress(address)) return "base58check";
|
|
342
|
-
if (isBase58Address(address)) return "base58";
|
|
343
343
|
throw new Error(`Unknown address encoding`);
|
|
344
344
|
};
|
|
345
345
|
const detectAddressEncoding = address => {
|
|
@@ -353,12 +353,12 @@ const addressFromPublicKey = (publicKey, encoding, options) => {
|
|
|
353
353
|
return encodeAddressSs58(publicKey, options?.ss58Prefix);
|
|
354
354
|
case "ethereum":
|
|
355
355
|
return encodeAddressEthereum(publicKey);
|
|
356
|
+
case "base58solana":
|
|
357
|
+
return encodeAddressSolana(publicKey);
|
|
356
358
|
case "bech32m":
|
|
357
359
|
case "bech32":
|
|
358
360
|
case "base58check":
|
|
359
361
|
throw new Error("addressFromPublicKey is not implemented for Bitcoin");
|
|
360
|
-
case "base58":
|
|
361
|
-
return encodeAddressBase58(publicKey);
|
|
362
362
|
}
|
|
363
363
|
};
|
|
364
364
|
|
|
@@ -382,7 +382,7 @@ const normalizeAnyAddress = address => {
|
|
|
382
382
|
case "bech32m":
|
|
383
383
|
case "bech32":
|
|
384
384
|
case "base58check":
|
|
385
|
-
case "
|
|
385
|
+
case "base58solana":
|
|
386
386
|
return address;
|
|
387
387
|
case "ss58":
|
|
388
388
|
{
|
|
@@ -401,9 +401,23 @@ const isAddressEqual = (address1, address2) => {
|
|
|
401
401
|
}
|
|
402
402
|
};
|
|
403
403
|
|
|
404
|
-
const
|
|
404
|
+
const encodeAnyAddress = (address, options) => {
|
|
405
|
+
// this leverages cache
|
|
406
|
+
const encoding = detectAddressEncoding(address);
|
|
407
|
+
|
|
408
|
+
// this does NOT leverage cache
|
|
409
|
+
if (encoding === "ss58" && options?.ss58Format !== undefined) {
|
|
410
|
+
const [publicKey] = decodeSs58Address(address);
|
|
411
|
+
return encodeAddressSs58(publicKey, options?.ss58Format ?? 42);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// this leverages cache
|
|
415
|
+
return normalizeAddress(address);
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
const isAddressValid = address => {
|
|
405
419
|
try {
|
|
406
|
-
|
|
420
|
+
detectAddressEncoding(address);
|
|
407
421
|
return true;
|
|
408
422
|
} catch {
|
|
409
423
|
return false;
|
|
@@ -544,7 +558,7 @@ const deriveSolana = (seed, derivationPath) => {
|
|
|
544
558
|
type: "solana",
|
|
545
559
|
secretKey,
|
|
546
560
|
publicKey,
|
|
547
|
-
address: addressFromPublicKey(publicKey, "
|
|
561
|
+
address: addressFromPublicKey(publicKey, "base58solana")
|
|
548
562
|
};
|
|
549
563
|
};
|
|
550
564
|
const getPublicKeySolana = secretKey => {
|
|
@@ -602,60 +616,42 @@ const getPublicKeyFromSecret = (secretKey, curve) => {
|
|
|
602
616
|
return getPublicKeySolana(secretKey);
|
|
603
617
|
}
|
|
604
618
|
};
|
|
605
|
-
const
|
|
606
|
-
const {
|
|
607
|
-
mnemonic,
|
|
608
|
-
derivationPath,
|
|
609
|
-
password
|
|
610
|
-
} = parseSuri(suri);
|
|
619
|
+
const addressFromMnemonic = async (mnemonic, derivationPath, curve) => {
|
|
611
620
|
const entropy = mnemonicToEntropy(mnemonic);
|
|
612
|
-
const seed = await entropyToSeed(entropy,
|
|
621
|
+
const seed = await entropyToSeed(entropy, curve);
|
|
613
622
|
const {
|
|
614
|
-
|
|
615
|
-
} = deriveKeypair(seed, derivationPath,
|
|
616
|
-
|
|
617
|
-
const encoding = addressEncodingFromCurve(type);
|
|
618
|
-
return addressFromPublicKey(publicKey, encoding);
|
|
619
|
-
};
|
|
620
|
-
|
|
621
|
-
/**
|
|
622
|
-
* @dev we only expect suri to contain a mnemonic and derivation path.
|
|
623
|
-
* for other cases see https://polkadot.js.org/docs/keyring/start/suri/
|
|
624
|
-
*/
|
|
625
|
-
const parseSuri = suri => {
|
|
626
|
-
// extract password if any
|
|
627
|
-
const indexOfPassword = suri.indexOf("///");
|
|
628
|
-
const password = indexOfPassword === -1 ? undefined : suri.slice(indexOfPassword + 3);
|
|
629
|
-
if (password) suri = suri.slice(0, indexOfPassword);
|
|
630
|
-
|
|
631
|
-
// split mnemonic and derivation path
|
|
632
|
-
const indexOfSlash = suri.indexOf("/");
|
|
633
|
-
const mnemonic = indexOfSlash === -1 ? suri : suri.slice(0, indexOfSlash);
|
|
634
|
-
let derivationPath = indexOfSlash === -1 ? "" : suri.slice(indexOfSlash);
|
|
635
|
-
|
|
636
|
-
// if BIP44, leading slash must be removed
|
|
637
|
-
if (derivationPath.startsWith("/m/")) derivationPath = derivationPath.slice(1);
|
|
638
|
-
if (!isValidMnemonic(mnemonic)) throw new Error("Invalid mnemonic");
|
|
639
|
-
return {
|
|
640
|
-
mnemonic,
|
|
641
|
-
derivationPath,
|
|
642
|
-
password
|
|
643
|
-
};
|
|
623
|
+
address
|
|
624
|
+
} = deriveKeypair(seed, derivationPath, curve);
|
|
625
|
+
return address;
|
|
644
626
|
};
|
|
645
627
|
const removeHexPrefix = secretKey => {
|
|
646
628
|
if (secretKey.startsWith("0x")) return secretKey.slice(2);
|
|
647
629
|
return secretKey;
|
|
648
630
|
};
|
|
649
|
-
const parseSecretKey = (secretKey,
|
|
650
|
-
switch (
|
|
631
|
+
const parseSecretKey = (secretKey, platform) => {
|
|
632
|
+
switch (platform) {
|
|
651
633
|
case "ethereum":
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
case "bitcoin-ecdsa":
|
|
657
|
-
case "bitcoin-ed25519":
|
|
634
|
+
{
|
|
635
|
+
const privateKey = removeHexPrefix(secretKey);
|
|
636
|
+
return base.hex.decode(privateKey);
|
|
637
|
+
}
|
|
658
638
|
case "solana":
|
|
639
|
+
{
|
|
640
|
+
const bytes = secretKey.startsWith("[") ?
|
|
641
|
+
// JSON bytes array (ex: solflare)
|
|
642
|
+
Uint8Array.from(JSON.parse(secretKey)) :
|
|
643
|
+
// base58 encoded string (ex: phantom)
|
|
644
|
+
base.base58.decode(secretKey);
|
|
645
|
+
if (bytes.length === 64) {
|
|
646
|
+
const privateKey = bytes.slice(0, 32);
|
|
647
|
+
const publicKey = bytes.slice(32, 64);
|
|
648
|
+
const computedPublicKey = getPublicKeySolana(privateKey);
|
|
649
|
+
if (!publicKey.every((b, i) => b === computedPublicKey[i])) throw new Error("Invalid Solana secret key: public key does not match");
|
|
650
|
+
return privateKey;
|
|
651
|
+
} else if (bytes.length === 32) return bytes;
|
|
652
|
+
throw new Error("Invalid Solana secret key length");
|
|
653
|
+
}
|
|
654
|
+
default:
|
|
659
655
|
throw new Error("Not implemented");
|
|
660
656
|
}
|
|
661
657
|
};
|
|
@@ -670,7 +666,7 @@ const isValidDerivationPath = async (derivationPath, curve) => {
|
|
|
670
666
|
}
|
|
671
667
|
};
|
|
672
668
|
|
|
673
|
-
const
|
|
669
|
+
const getAccountPlatformFromCurve = curve => {
|
|
674
670
|
switch (curve) {
|
|
675
671
|
case "sr25519":
|
|
676
672
|
case "ed25519":
|
|
@@ -685,7 +681,7 @@ const platformFromCurve = curve => {
|
|
|
685
681
|
return "solana";
|
|
686
682
|
}
|
|
687
683
|
};
|
|
688
|
-
const
|
|
684
|
+
const getAccountPlatformFromEncoding = encoding => {
|
|
689
685
|
switch (encoding) {
|
|
690
686
|
case "ss58":
|
|
691
687
|
return "polkadot";
|
|
@@ -695,28 +691,40 @@ const platformFromEncoding = encoding => {
|
|
|
695
691
|
case "bech32":
|
|
696
692
|
case "base58check":
|
|
697
693
|
return "bitcoin";
|
|
698
|
-
case "
|
|
694
|
+
case "base58solana":
|
|
699
695
|
return "solana";
|
|
700
696
|
}
|
|
701
697
|
};
|
|
702
|
-
const
|
|
698
|
+
const getAccountPlatformFromAddress = address => {
|
|
703
699
|
const encoding = detectAddressEncoding(address);
|
|
704
|
-
return
|
|
700
|
+
return getAccountPlatformFromEncoding(encoding);
|
|
705
701
|
};
|
|
706
702
|
|
|
707
|
-
Object.defineProperty(exports, "
|
|
703
|
+
Object.defineProperty(exports, "base58", {
|
|
704
|
+
enumerable: true,
|
|
705
|
+
get: function () { return base.base58; }
|
|
706
|
+
});
|
|
707
|
+
Object.defineProperty(exports, "base64", {
|
|
708
|
+
enumerable: true,
|
|
709
|
+
get: function () { return base.base64; }
|
|
710
|
+
});
|
|
711
|
+
Object.defineProperty(exports, "hex", {
|
|
712
|
+
enumerable: true,
|
|
713
|
+
get: function () { return base.hex; }
|
|
714
|
+
});
|
|
715
|
+
Object.defineProperty(exports, "utf8", {
|
|
708
716
|
enumerable: true,
|
|
709
|
-
get: function () { return base.
|
|
717
|
+
get: function () { return base.utf8; }
|
|
710
718
|
});
|
|
711
|
-
Object.defineProperty(exports, "
|
|
719
|
+
Object.defineProperty(exports, "ed25519", {
|
|
712
720
|
enumerable: true,
|
|
713
|
-
get: function () { return
|
|
721
|
+
get: function () { return ed25519.ed25519; }
|
|
714
722
|
});
|
|
715
723
|
exports.DEV_MNEMONIC_ETHEREUM = DEV_MNEMONIC_ETHEREUM;
|
|
716
724
|
exports.DEV_MNEMONIC_POLKADOT = DEV_MNEMONIC_POLKADOT;
|
|
717
725
|
exports.addressEncodingFromCurve = addressEncodingFromCurve;
|
|
726
|
+
exports.addressFromMnemonic = addressFromMnemonic;
|
|
718
727
|
exports.addressFromPublicKey = addressFromPublicKey;
|
|
719
|
-
exports.addressFromSuri = addressFromSuri;
|
|
720
728
|
exports.blake2b256 = blake2b256;
|
|
721
729
|
exports.blake2b512 = blake2b512;
|
|
722
730
|
exports.blake3 = blake3;
|
|
@@ -724,35 +732,35 @@ exports.checksumEthereumAddress = checksumEthereumAddress;
|
|
|
724
732
|
exports.decodeSs58Address = decodeSs58Address;
|
|
725
733
|
exports.deriveKeypair = deriveKeypair;
|
|
726
734
|
exports.detectAddressEncoding = detectAddressEncoding;
|
|
727
|
-
exports.encodeAddressBase58 = encodeAddressBase58;
|
|
728
735
|
exports.encodeAddressEthereum = encodeAddressEthereum;
|
|
736
|
+
exports.encodeAddressSolana = encodeAddressSolana;
|
|
729
737
|
exports.encodeAddressSs58 = encodeAddressSs58;
|
|
738
|
+
exports.encodeAnyAddress = encodeAnyAddress;
|
|
730
739
|
exports.entropyToMnemonic = entropyToMnemonic;
|
|
731
740
|
exports.entropyToSeed = entropyToSeed;
|
|
732
741
|
exports.fromBase58Check = fromBase58Check;
|
|
733
742
|
exports.fromBech32 = fromBech32;
|
|
734
743
|
exports.fromBech32m = fromBech32m;
|
|
735
744
|
exports.generateMnemonic = generateMnemonic;
|
|
745
|
+
exports.getAccountPlatformFromAddress = getAccountPlatformFromAddress;
|
|
746
|
+
exports.getAccountPlatformFromCurve = getAccountPlatformFromCurve;
|
|
747
|
+
exports.getAccountPlatformFromEncoding = getAccountPlatformFromEncoding;
|
|
736
748
|
exports.getDevSeed = getDevSeed;
|
|
737
749
|
exports.getPublicKeyFromSecret = getPublicKeyFromSecret;
|
|
738
750
|
exports.getSafeHash = getSafeHash;
|
|
739
751
|
exports.isAddressEqual = isAddressEqual;
|
|
740
|
-
exports.
|
|
752
|
+
exports.isAddressValid = isAddressValid;
|
|
741
753
|
exports.isBase58CheckAddress = isBase58CheckAddress;
|
|
742
754
|
exports.isBech32Address = isBech32Address;
|
|
743
755
|
exports.isBech32mAddress = isBech32mAddress;
|
|
744
756
|
exports.isBitcoinAddress = isBitcoinAddress;
|
|
745
757
|
exports.isEthereumAddress = isEthereumAddress;
|
|
758
|
+
exports.isSolanaAddress = isSolanaAddress;
|
|
746
759
|
exports.isSs58Address = isSs58Address;
|
|
747
|
-
exports.isValidAddress = isValidAddress;
|
|
748
760
|
exports.isValidDerivationPath = isValidDerivationPath;
|
|
749
761
|
exports.isValidMnemonic = isValidMnemonic;
|
|
750
762
|
exports.mnemonicToEntropy = mnemonicToEntropy;
|
|
751
763
|
exports.normalizeAddress = normalizeAddress;
|
|
752
764
|
exports.parseSecretKey = parseSecretKey;
|
|
753
|
-
exports.parseSuri = parseSuri;
|
|
754
765
|
exports.pbkdf2 = pbkdf2;
|
|
755
|
-
exports.platformFromAddress = platformFromAddress;
|
|
756
|
-
exports.platformFromCurve = platformFromCurve;
|
|
757
|
-
exports.platformFromEncoding = platformFromEncoding;
|
|
758
766
|
exports.removeHexPrefix = removeHexPrefix;
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
var bip39 = require('@scure/bip39');
|
|
4
4
|
var english = require('@scure/bip39/wordlists/english');
|
|
5
5
|
var base = require('@scure/base');
|
|
6
|
+
var ed25519 = require('@noble/curves/ed25519');
|
|
7
|
+
var secp256k1 = require('@noble/curves/secp256k1');
|
|
6
8
|
var bech32 = require('bech32');
|
|
7
9
|
var bs58check = require('bs58check');
|
|
8
10
|
var sha3 = require('@noble/hashes/sha3');
|
|
9
11
|
var utils = require('@noble/hashes/utils');
|
|
10
12
|
var blake2b = require('@noble/hashes/blake2b');
|
|
11
13
|
var blake3$1 = require('@noble/hashes/blake3');
|
|
12
|
-
var secp256k1 = require('@noble/curves/secp256k1');
|
|
13
14
|
var scaleTs = require('scale-ts');
|
|
14
|
-
var ed25519 = require('@noble/curves/ed25519');
|
|
15
15
|
var bip32 = require('@scure/bip32');
|
|
16
16
|
var hmac = require('@noble/hashes/hmac');
|
|
17
17
|
var sha512 = require('@noble/hashes/sha512');
|
|
@@ -140,18 +140,18 @@ const addressEncodingFromCurve = curve => {
|
|
|
140
140
|
case "ethereum":
|
|
141
141
|
return "ethereum";
|
|
142
142
|
case "solana":
|
|
143
|
-
return "
|
|
143
|
+
return "base58solana";
|
|
144
144
|
}
|
|
145
145
|
};
|
|
146
146
|
|
|
147
|
-
const
|
|
147
|
+
const encodeAddressSolana = publicKey => {
|
|
148
|
+
if (publicKey.length !== 32) throw new Error("Public key must be 32 bytes long for Solana base58 encoding");
|
|
148
149
|
return base.base58.encode(publicKey);
|
|
149
150
|
};
|
|
150
|
-
|
|
151
|
-
function isBase58Address(address) {
|
|
151
|
+
function isSolanaAddress(address) {
|
|
152
152
|
try {
|
|
153
|
-
base.base58.decode(address);
|
|
154
|
-
return
|
|
153
|
+
const bytes = base.base58.decode(address);
|
|
154
|
+
return bytes.length === 32;
|
|
155
155
|
} catch (error) {
|
|
156
156
|
return false;
|
|
157
157
|
}
|
|
@@ -287,7 +287,7 @@ const blake2b512 = msg => blake2b.blake2b(msg, {
|
|
|
287
287
|
const getSafeHash = bytes => {
|
|
288
288
|
// cryptographically secure one way hash
|
|
289
289
|
// outputs 44 characters without special characters
|
|
290
|
-
return base.
|
|
290
|
+
return base.base58.encode(blake3$1.blake3(bytes));
|
|
291
291
|
};
|
|
292
292
|
|
|
293
293
|
// Inspired from MIT licensed @polkadot-labs/hdkd-helpers
|
|
@@ -336,10 +336,10 @@ const CACHE$1 = new Map();
|
|
|
336
336
|
const detectAddressEncodingInner = address => {
|
|
337
337
|
if (isEthereumAddress(address)) return "ethereum";
|
|
338
338
|
if (isSs58Address(address)) return "ss58";
|
|
339
|
+
if (isSolanaAddress(address)) return "base58solana";
|
|
339
340
|
if (isBech32mAddress(address)) return "bech32m";
|
|
340
341
|
if (isBech32Address(address)) return "bech32";
|
|
341
342
|
if (isBase58CheckAddress(address)) return "base58check";
|
|
342
|
-
if (isBase58Address(address)) return "base58";
|
|
343
343
|
throw new Error(`Unknown address encoding`);
|
|
344
344
|
};
|
|
345
345
|
const detectAddressEncoding = address => {
|
|
@@ -353,12 +353,12 @@ const addressFromPublicKey = (publicKey, encoding, options) => {
|
|
|
353
353
|
return encodeAddressSs58(publicKey, options?.ss58Prefix);
|
|
354
354
|
case "ethereum":
|
|
355
355
|
return encodeAddressEthereum(publicKey);
|
|
356
|
+
case "base58solana":
|
|
357
|
+
return encodeAddressSolana(publicKey);
|
|
356
358
|
case "bech32m":
|
|
357
359
|
case "bech32":
|
|
358
360
|
case "base58check":
|
|
359
361
|
throw new Error("addressFromPublicKey is not implemented for Bitcoin");
|
|
360
|
-
case "base58":
|
|
361
|
-
return encodeAddressBase58(publicKey);
|
|
362
362
|
}
|
|
363
363
|
};
|
|
364
364
|
|
|
@@ -382,7 +382,7 @@ const normalizeAnyAddress = address => {
|
|
|
382
382
|
case "bech32m":
|
|
383
383
|
case "bech32":
|
|
384
384
|
case "base58check":
|
|
385
|
-
case "
|
|
385
|
+
case "base58solana":
|
|
386
386
|
return address;
|
|
387
387
|
case "ss58":
|
|
388
388
|
{
|
|
@@ -401,9 +401,23 @@ const isAddressEqual = (address1, address2) => {
|
|
|
401
401
|
}
|
|
402
402
|
};
|
|
403
403
|
|
|
404
|
-
const
|
|
404
|
+
const encodeAnyAddress = (address, options) => {
|
|
405
|
+
// this leverages cache
|
|
406
|
+
const encoding = detectAddressEncoding(address);
|
|
407
|
+
|
|
408
|
+
// this does NOT leverage cache
|
|
409
|
+
if (encoding === "ss58" && options?.ss58Format !== undefined) {
|
|
410
|
+
const [publicKey] = decodeSs58Address(address);
|
|
411
|
+
return encodeAddressSs58(publicKey, options?.ss58Format ?? 42);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// this leverages cache
|
|
415
|
+
return normalizeAddress(address);
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
const isAddressValid = address => {
|
|
405
419
|
try {
|
|
406
|
-
|
|
420
|
+
detectAddressEncoding(address);
|
|
407
421
|
return true;
|
|
408
422
|
} catch {
|
|
409
423
|
return false;
|
|
@@ -544,7 +558,7 @@ const deriveSolana = (seed, derivationPath) => {
|
|
|
544
558
|
type: "solana",
|
|
545
559
|
secretKey,
|
|
546
560
|
publicKey,
|
|
547
|
-
address: addressFromPublicKey(publicKey, "
|
|
561
|
+
address: addressFromPublicKey(publicKey, "base58solana")
|
|
548
562
|
};
|
|
549
563
|
};
|
|
550
564
|
const getPublicKeySolana = secretKey => {
|
|
@@ -602,60 +616,42 @@ const getPublicKeyFromSecret = (secretKey, curve) => {
|
|
|
602
616
|
return getPublicKeySolana(secretKey);
|
|
603
617
|
}
|
|
604
618
|
};
|
|
605
|
-
const
|
|
606
|
-
const {
|
|
607
|
-
mnemonic,
|
|
608
|
-
derivationPath,
|
|
609
|
-
password
|
|
610
|
-
} = parseSuri(suri);
|
|
619
|
+
const addressFromMnemonic = async (mnemonic, derivationPath, curve) => {
|
|
611
620
|
const entropy = mnemonicToEntropy(mnemonic);
|
|
612
|
-
const seed = await entropyToSeed(entropy,
|
|
621
|
+
const seed = await entropyToSeed(entropy, curve);
|
|
613
622
|
const {
|
|
614
|
-
|
|
615
|
-
} = deriveKeypair(seed, derivationPath,
|
|
616
|
-
|
|
617
|
-
const encoding = addressEncodingFromCurve(type);
|
|
618
|
-
return addressFromPublicKey(publicKey, encoding);
|
|
619
|
-
};
|
|
620
|
-
|
|
621
|
-
/**
|
|
622
|
-
* @dev we only expect suri to contain a mnemonic and derivation path.
|
|
623
|
-
* for other cases see https://polkadot.js.org/docs/keyring/start/suri/
|
|
624
|
-
*/
|
|
625
|
-
const parseSuri = suri => {
|
|
626
|
-
// extract password if any
|
|
627
|
-
const indexOfPassword = suri.indexOf("///");
|
|
628
|
-
const password = indexOfPassword === -1 ? undefined : suri.slice(indexOfPassword + 3);
|
|
629
|
-
if (password) suri = suri.slice(0, indexOfPassword);
|
|
630
|
-
|
|
631
|
-
// split mnemonic and derivation path
|
|
632
|
-
const indexOfSlash = suri.indexOf("/");
|
|
633
|
-
const mnemonic = indexOfSlash === -1 ? suri : suri.slice(0, indexOfSlash);
|
|
634
|
-
let derivationPath = indexOfSlash === -1 ? "" : suri.slice(indexOfSlash);
|
|
635
|
-
|
|
636
|
-
// if BIP44, leading slash must be removed
|
|
637
|
-
if (derivationPath.startsWith("/m/")) derivationPath = derivationPath.slice(1);
|
|
638
|
-
if (!isValidMnemonic(mnemonic)) throw new Error("Invalid mnemonic");
|
|
639
|
-
return {
|
|
640
|
-
mnemonic,
|
|
641
|
-
derivationPath,
|
|
642
|
-
password
|
|
643
|
-
};
|
|
623
|
+
address
|
|
624
|
+
} = deriveKeypair(seed, derivationPath, curve);
|
|
625
|
+
return address;
|
|
644
626
|
};
|
|
645
627
|
const removeHexPrefix = secretKey => {
|
|
646
628
|
if (secretKey.startsWith("0x")) return secretKey.slice(2);
|
|
647
629
|
return secretKey;
|
|
648
630
|
};
|
|
649
|
-
const parseSecretKey = (secretKey,
|
|
650
|
-
switch (
|
|
631
|
+
const parseSecretKey = (secretKey, platform) => {
|
|
632
|
+
switch (platform) {
|
|
651
633
|
case "ethereum":
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
case "bitcoin-ecdsa":
|
|
657
|
-
case "bitcoin-ed25519":
|
|
634
|
+
{
|
|
635
|
+
const privateKey = removeHexPrefix(secretKey);
|
|
636
|
+
return base.hex.decode(privateKey);
|
|
637
|
+
}
|
|
658
638
|
case "solana":
|
|
639
|
+
{
|
|
640
|
+
const bytes = secretKey.startsWith("[") ?
|
|
641
|
+
// JSON bytes array (ex: solflare)
|
|
642
|
+
Uint8Array.from(JSON.parse(secretKey)) :
|
|
643
|
+
// base58 encoded string (ex: phantom)
|
|
644
|
+
base.base58.decode(secretKey);
|
|
645
|
+
if (bytes.length === 64) {
|
|
646
|
+
const privateKey = bytes.slice(0, 32);
|
|
647
|
+
const publicKey = bytes.slice(32, 64);
|
|
648
|
+
const computedPublicKey = getPublicKeySolana(privateKey);
|
|
649
|
+
if (!publicKey.every((b, i) => b === computedPublicKey[i])) throw new Error("Invalid Solana secret key: public key does not match");
|
|
650
|
+
return privateKey;
|
|
651
|
+
} else if (bytes.length === 32) return bytes;
|
|
652
|
+
throw new Error("Invalid Solana secret key length");
|
|
653
|
+
}
|
|
654
|
+
default:
|
|
659
655
|
throw new Error("Not implemented");
|
|
660
656
|
}
|
|
661
657
|
};
|
|
@@ -670,7 +666,7 @@ const isValidDerivationPath = async (derivationPath, curve) => {
|
|
|
670
666
|
}
|
|
671
667
|
};
|
|
672
668
|
|
|
673
|
-
const
|
|
669
|
+
const getAccountPlatformFromCurve = curve => {
|
|
674
670
|
switch (curve) {
|
|
675
671
|
case "sr25519":
|
|
676
672
|
case "ed25519":
|
|
@@ -685,7 +681,7 @@ const platformFromCurve = curve => {
|
|
|
685
681
|
return "solana";
|
|
686
682
|
}
|
|
687
683
|
};
|
|
688
|
-
const
|
|
684
|
+
const getAccountPlatformFromEncoding = encoding => {
|
|
689
685
|
switch (encoding) {
|
|
690
686
|
case "ss58":
|
|
691
687
|
return "polkadot";
|
|
@@ -695,28 +691,40 @@ const platformFromEncoding = encoding => {
|
|
|
695
691
|
case "bech32":
|
|
696
692
|
case "base58check":
|
|
697
693
|
return "bitcoin";
|
|
698
|
-
case "
|
|
694
|
+
case "base58solana":
|
|
699
695
|
return "solana";
|
|
700
696
|
}
|
|
701
697
|
};
|
|
702
|
-
const
|
|
698
|
+
const getAccountPlatformFromAddress = address => {
|
|
703
699
|
const encoding = detectAddressEncoding(address);
|
|
704
|
-
return
|
|
700
|
+
return getAccountPlatformFromEncoding(encoding);
|
|
705
701
|
};
|
|
706
702
|
|
|
707
|
-
Object.defineProperty(exports, "
|
|
703
|
+
Object.defineProperty(exports, "base58", {
|
|
704
|
+
enumerable: true,
|
|
705
|
+
get: function () { return base.base58; }
|
|
706
|
+
});
|
|
707
|
+
Object.defineProperty(exports, "base64", {
|
|
708
|
+
enumerable: true,
|
|
709
|
+
get: function () { return base.base64; }
|
|
710
|
+
});
|
|
711
|
+
Object.defineProperty(exports, "hex", {
|
|
712
|
+
enumerable: true,
|
|
713
|
+
get: function () { return base.hex; }
|
|
714
|
+
});
|
|
715
|
+
Object.defineProperty(exports, "utf8", {
|
|
708
716
|
enumerable: true,
|
|
709
|
-
get: function () { return base.
|
|
717
|
+
get: function () { return base.utf8; }
|
|
710
718
|
});
|
|
711
|
-
Object.defineProperty(exports, "
|
|
719
|
+
Object.defineProperty(exports, "ed25519", {
|
|
712
720
|
enumerable: true,
|
|
713
|
-
get: function () { return
|
|
721
|
+
get: function () { return ed25519.ed25519; }
|
|
714
722
|
});
|
|
715
723
|
exports.DEV_MNEMONIC_ETHEREUM = DEV_MNEMONIC_ETHEREUM;
|
|
716
724
|
exports.DEV_MNEMONIC_POLKADOT = DEV_MNEMONIC_POLKADOT;
|
|
717
725
|
exports.addressEncodingFromCurve = addressEncodingFromCurve;
|
|
726
|
+
exports.addressFromMnemonic = addressFromMnemonic;
|
|
718
727
|
exports.addressFromPublicKey = addressFromPublicKey;
|
|
719
|
-
exports.addressFromSuri = addressFromSuri;
|
|
720
728
|
exports.blake2b256 = blake2b256;
|
|
721
729
|
exports.blake2b512 = blake2b512;
|
|
722
730
|
exports.blake3 = blake3;
|
|
@@ -724,35 +732,35 @@ exports.checksumEthereumAddress = checksumEthereumAddress;
|
|
|
724
732
|
exports.decodeSs58Address = decodeSs58Address;
|
|
725
733
|
exports.deriveKeypair = deriveKeypair;
|
|
726
734
|
exports.detectAddressEncoding = detectAddressEncoding;
|
|
727
|
-
exports.encodeAddressBase58 = encodeAddressBase58;
|
|
728
735
|
exports.encodeAddressEthereum = encodeAddressEthereum;
|
|
736
|
+
exports.encodeAddressSolana = encodeAddressSolana;
|
|
729
737
|
exports.encodeAddressSs58 = encodeAddressSs58;
|
|
738
|
+
exports.encodeAnyAddress = encodeAnyAddress;
|
|
730
739
|
exports.entropyToMnemonic = entropyToMnemonic;
|
|
731
740
|
exports.entropyToSeed = entropyToSeed;
|
|
732
741
|
exports.fromBase58Check = fromBase58Check;
|
|
733
742
|
exports.fromBech32 = fromBech32;
|
|
734
743
|
exports.fromBech32m = fromBech32m;
|
|
735
744
|
exports.generateMnemonic = generateMnemonic;
|
|
745
|
+
exports.getAccountPlatformFromAddress = getAccountPlatformFromAddress;
|
|
746
|
+
exports.getAccountPlatformFromCurve = getAccountPlatformFromCurve;
|
|
747
|
+
exports.getAccountPlatformFromEncoding = getAccountPlatformFromEncoding;
|
|
736
748
|
exports.getDevSeed = getDevSeed;
|
|
737
749
|
exports.getPublicKeyFromSecret = getPublicKeyFromSecret;
|
|
738
750
|
exports.getSafeHash = getSafeHash;
|
|
739
751
|
exports.isAddressEqual = isAddressEqual;
|
|
740
|
-
exports.
|
|
752
|
+
exports.isAddressValid = isAddressValid;
|
|
741
753
|
exports.isBase58CheckAddress = isBase58CheckAddress;
|
|
742
754
|
exports.isBech32Address = isBech32Address;
|
|
743
755
|
exports.isBech32mAddress = isBech32mAddress;
|
|
744
756
|
exports.isBitcoinAddress = isBitcoinAddress;
|
|
745
757
|
exports.isEthereumAddress = isEthereumAddress;
|
|
758
|
+
exports.isSolanaAddress = isSolanaAddress;
|
|
746
759
|
exports.isSs58Address = isSs58Address;
|
|
747
|
-
exports.isValidAddress = isValidAddress;
|
|
748
760
|
exports.isValidDerivationPath = isValidDerivationPath;
|
|
749
761
|
exports.isValidMnemonic = isValidMnemonic;
|
|
750
762
|
exports.mnemonicToEntropy = mnemonicToEntropy;
|
|
751
763
|
exports.normalizeAddress = normalizeAddress;
|
|
752
764
|
exports.parseSecretKey = parseSecretKey;
|
|
753
|
-
exports.parseSuri = parseSuri;
|
|
754
765
|
exports.pbkdf2 = pbkdf2;
|
|
755
|
-
exports.platformFromAddress = platformFromAddress;
|
|
756
|
-
exports.platformFromCurve = platformFromCurve;
|
|
757
|
-
exports.platformFromEncoding = platformFromEncoding;
|
|
758
766
|
exports.removeHexPrefix = removeHexPrefix;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { mnemonicToEntropy as mnemonicToEntropy$1, entropyToMnemonic as entropyToMnemonic$1, validateMnemonic, generateMnemonic as generateMnemonic$1 } from '@scure/bip39';
|
|
2
2
|
import { wordlist } from '@scure/bip39/wordlists/english';
|
|
3
|
-
import { base58,
|
|
4
|
-
export {
|
|
3
|
+
import { base58, hex } from '@scure/base';
|
|
4
|
+
export { base58, base64, hex, utf8 } from '@scure/base';
|
|
5
|
+
import { ed25519 } from '@noble/curves/ed25519';
|
|
6
|
+
export { ed25519 } from '@noble/curves/ed25519';
|
|
7
|
+
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
5
8
|
import { bech32m, bech32 } from 'bech32';
|
|
6
9
|
import bs58check from 'bs58check';
|
|
7
10
|
import { keccak_256 } from '@noble/hashes/sha3';
|
|
8
11
|
import { bytesToHex, randomBytes } from '@noble/hashes/utils';
|
|
9
12
|
import { blake2b } from '@noble/hashes/blake2b';
|
|
10
13
|
import { blake3 as blake3$1 } from '@noble/hashes/blake3';
|
|
11
|
-
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
12
14
|
import { Tuple, str, Bytes, u32 } from 'scale-ts';
|
|
13
|
-
import { ed25519 } from '@noble/curves/ed25519';
|
|
14
15
|
import { HDKey } from '@scure/bip32';
|
|
15
16
|
import { hmac } from '@noble/hashes/hmac';
|
|
16
17
|
import { sha512 } from '@noble/hashes/sha512';
|
|
@@ -135,18 +136,18 @@ const addressEncodingFromCurve = curve => {
|
|
|
135
136
|
case "ethereum":
|
|
136
137
|
return "ethereum";
|
|
137
138
|
case "solana":
|
|
138
|
-
return "
|
|
139
|
+
return "base58solana";
|
|
139
140
|
}
|
|
140
141
|
};
|
|
141
142
|
|
|
142
|
-
const
|
|
143
|
+
const encodeAddressSolana = publicKey => {
|
|
144
|
+
if (publicKey.length !== 32) throw new Error("Public key must be 32 bytes long for Solana base58 encoding");
|
|
143
145
|
return base58.encode(publicKey);
|
|
144
146
|
};
|
|
145
|
-
|
|
146
|
-
function isBase58Address(address) {
|
|
147
|
+
function isSolanaAddress(address) {
|
|
147
148
|
try {
|
|
148
|
-
base58.decode(address);
|
|
149
|
-
return
|
|
149
|
+
const bytes = base58.decode(address);
|
|
150
|
+
return bytes.length === 32;
|
|
150
151
|
} catch (error) {
|
|
151
152
|
return false;
|
|
152
153
|
}
|
|
@@ -282,7 +283,7 @@ const blake2b512 = msg => blake2b(msg, {
|
|
|
282
283
|
const getSafeHash = bytes => {
|
|
283
284
|
// cryptographically secure one way hash
|
|
284
285
|
// outputs 44 characters without special characters
|
|
285
|
-
return
|
|
286
|
+
return base58.encode(blake3$1(bytes));
|
|
286
287
|
};
|
|
287
288
|
|
|
288
289
|
// Inspired from MIT licensed @polkadot-labs/hdkd-helpers
|
|
@@ -331,10 +332,10 @@ const CACHE$1 = new Map();
|
|
|
331
332
|
const detectAddressEncodingInner = address => {
|
|
332
333
|
if (isEthereumAddress(address)) return "ethereum";
|
|
333
334
|
if (isSs58Address(address)) return "ss58";
|
|
335
|
+
if (isSolanaAddress(address)) return "base58solana";
|
|
334
336
|
if (isBech32mAddress(address)) return "bech32m";
|
|
335
337
|
if (isBech32Address(address)) return "bech32";
|
|
336
338
|
if (isBase58CheckAddress(address)) return "base58check";
|
|
337
|
-
if (isBase58Address(address)) return "base58";
|
|
338
339
|
throw new Error(`Unknown address encoding`);
|
|
339
340
|
};
|
|
340
341
|
const detectAddressEncoding = address => {
|
|
@@ -348,12 +349,12 @@ const addressFromPublicKey = (publicKey, encoding, options) => {
|
|
|
348
349
|
return encodeAddressSs58(publicKey, options?.ss58Prefix);
|
|
349
350
|
case "ethereum":
|
|
350
351
|
return encodeAddressEthereum(publicKey);
|
|
352
|
+
case "base58solana":
|
|
353
|
+
return encodeAddressSolana(publicKey);
|
|
351
354
|
case "bech32m":
|
|
352
355
|
case "bech32":
|
|
353
356
|
case "base58check":
|
|
354
357
|
throw new Error("addressFromPublicKey is not implemented for Bitcoin");
|
|
355
|
-
case "base58":
|
|
356
|
-
return encodeAddressBase58(publicKey);
|
|
357
358
|
}
|
|
358
359
|
};
|
|
359
360
|
|
|
@@ -377,7 +378,7 @@ const normalizeAnyAddress = address => {
|
|
|
377
378
|
case "bech32m":
|
|
378
379
|
case "bech32":
|
|
379
380
|
case "base58check":
|
|
380
|
-
case "
|
|
381
|
+
case "base58solana":
|
|
381
382
|
return address;
|
|
382
383
|
case "ss58":
|
|
383
384
|
{
|
|
@@ -396,9 +397,23 @@ const isAddressEqual = (address1, address2) => {
|
|
|
396
397
|
}
|
|
397
398
|
};
|
|
398
399
|
|
|
399
|
-
const
|
|
400
|
+
const encodeAnyAddress = (address, options) => {
|
|
401
|
+
// this leverages cache
|
|
402
|
+
const encoding = detectAddressEncoding(address);
|
|
403
|
+
|
|
404
|
+
// this does NOT leverage cache
|
|
405
|
+
if (encoding === "ss58" && options?.ss58Format !== undefined) {
|
|
406
|
+
const [publicKey] = decodeSs58Address(address);
|
|
407
|
+
return encodeAddressSs58(publicKey, options?.ss58Format ?? 42);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// this leverages cache
|
|
411
|
+
return normalizeAddress(address);
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const isAddressValid = address => {
|
|
400
415
|
try {
|
|
401
|
-
|
|
416
|
+
detectAddressEncoding(address);
|
|
402
417
|
return true;
|
|
403
418
|
} catch {
|
|
404
419
|
return false;
|
|
@@ -539,7 +554,7 @@ const deriveSolana = (seed, derivationPath) => {
|
|
|
539
554
|
type: "solana",
|
|
540
555
|
secretKey,
|
|
541
556
|
publicKey,
|
|
542
|
-
address: addressFromPublicKey(publicKey, "
|
|
557
|
+
address: addressFromPublicKey(publicKey, "base58solana")
|
|
543
558
|
};
|
|
544
559
|
};
|
|
545
560
|
const getPublicKeySolana = secretKey => {
|
|
@@ -597,60 +612,42 @@ const getPublicKeyFromSecret = (secretKey, curve) => {
|
|
|
597
612
|
return getPublicKeySolana(secretKey);
|
|
598
613
|
}
|
|
599
614
|
};
|
|
600
|
-
const
|
|
601
|
-
const {
|
|
602
|
-
mnemonic,
|
|
603
|
-
derivationPath,
|
|
604
|
-
password
|
|
605
|
-
} = parseSuri(suri);
|
|
615
|
+
const addressFromMnemonic = async (mnemonic, derivationPath, curve) => {
|
|
606
616
|
const entropy = mnemonicToEntropy(mnemonic);
|
|
607
|
-
const seed = await entropyToSeed(entropy,
|
|
617
|
+
const seed = await entropyToSeed(entropy, curve);
|
|
608
618
|
const {
|
|
609
|
-
|
|
610
|
-
} = deriveKeypair(seed, derivationPath,
|
|
611
|
-
|
|
612
|
-
const encoding = addressEncodingFromCurve(type);
|
|
613
|
-
return addressFromPublicKey(publicKey, encoding);
|
|
614
|
-
};
|
|
615
|
-
|
|
616
|
-
/**
|
|
617
|
-
* @dev we only expect suri to contain a mnemonic and derivation path.
|
|
618
|
-
* for other cases see https://polkadot.js.org/docs/keyring/start/suri/
|
|
619
|
-
*/
|
|
620
|
-
const parseSuri = suri => {
|
|
621
|
-
// extract password if any
|
|
622
|
-
const indexOfPassword = suri.indexOf("///");
|
|
623
|
-
const password = indexOfPassword === -1 ? undefined : suri.slice(indexOfPassword + 3);
|
|
624
|
-
if (password) suri = suri.slice(0, indexOfPassword);
|
|
625
|
-
|
|
626
|
-
// split mnemonic and derivation path
|
|
627
|
-
const indexOfSlash = suri.indexOf("/");
|
|
628
|
-
const mnemonic = indexOfSlash === -1 ? suri : suri.slice(0, indexOfSlash);
|
|
629
|
-
let derivationPath = indexOfSlash === -1 ? "" : suri.slice(indexOfSlash);
|
|
630
|
-
|
|
631
|
-
// if BIP44, leading slash must be removed
|
|
632
|
-
if (derivationPath.startsWith("/m/")) derivationPath = derivationPath.slice(1);
|
|
633
|
-
if (!isValidMnemonic(mnemonic)) throw new Error("Invalid mnemonic");
|
|
634
|
-
return {
|
|
635
|
-
mnemonic,
|
|
636
|
-
derivationPath,
|
|
637
|
-
password
|
|
638
|
-
};
|
|
619
|
+
address
|
|
620
|
+
} = deriveKeypair(seed, derivationPath, curve);
|
|
621
|
+
return address;
|
|
639
622
|
};
|
|
640
623
|
const removeHexPrefix = secretKey => {
|
|
641
624
|
if (secretKey.startsWith("0x")) return secretKey.slice(2);
|
|
642
625
|
return secretKey;
|
|
643
626
|
};
|
|
644
|
-
const parseSecretKey = (secretKey,
|
|
645
|
-
switch (
|
|
627
|
+
const parseSecretKey = (secretKey, platform) => {
|
|
628
|
+
switch (platform) {
|
|
646
629
|
case "ethereum":
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
case "bitcoin-ecdsa":
|
|
652
|
-
case "bitcoin-ed25519":
|
|
630
|
+
{
|
|
631
|
+
const privateKey = removeHexPrefix(secretKey);
|
|
632
|
+
return hex.decode(privateKey);
|
|
633
|
+
}
|
|
653
634
|
case "solana":
|
|
635
|
+
{
|
|
636
|
+
const bytes = secretKey.startsWith("[") ?
|
|
637
|
+
// JSON bytes array (ex: solflare)
|
|
638
|
+
Uint8Array.from(JSON.parse(secretKey)) :
|
|
639
|
+
// base58 encoded string (ex: phantom)
|
|
640
|
+
base58.decode(secretKey);
|
|
641
|
+
if (bytes.length === 64) {
|
|
642
|
+
const privateKey = bytes.slice(0, 32);
|
|
643
|
+
const publicKey = bytes.slice(32, 64);
|
|
644
|
+
const computedPublicKey = getPublicKeySolana(privateKey);
|
|
645
|
+
if (!publicKey.every((b, i) => b === computedPublicKey[i])) throw new Error("Invalid Solana secret key: public key does not match");
|
|
646
|
+
return privateKey;
|
|
647
|
+
} else if (bytes.length === 32) return bytes;
|
|
648
|
+
throw new Error("Invalid Solana secret key length");
|
|
649
|
+
}
|
|
650
|
+
default:
|
|
654
651
|
throw new Error("Not implemented");
|
|
655
652
|
}
|
|
656
653
|
};
|
|
@@ -665,7 +662,7 @@ const isValidDerivationPath = async (derivationPath, curve) => {
|
|
|
665
662
|
}
|
|
666
663
|
};
|
|
667
664
|
|
|
668
|
-
const
|
|
665
|
+
const getAccountPlatformFromCurve = curve => {
|
|
669
666
|
switch (curve) {
|
|
670
667
|
case "sr25519":
|
|
671
668
|
case "ed25519":
|
|
@@ -680,7 +677,7 @@ const platformFromCurve = curve => {
|
|
|
680
677
|
return "solana";
|
|
681
678
|
}
|
|
682
679
|
};
|
|
683
|
-
const
|
|
680
|
+
const getAccountPlatformFromEncoding = encoding => {
|
|
684
681
|
switch (encoding) {
|
|
685
682
|
case "ss58":
|
|
686
683
|
return "polkadot";
|
|
@@ -690,13 +687,13 @@ const platformFromEncoding = encoding => {
|
|
|
690
687
|
case "bech32":
|
|
691
688
|
case "base58check":
|
|
692
689
|
return "bitcoin";
|
|
693
|
-
case "
|
|
690
|
+
case "base58solana":
|
|
694
691
|
return "solana";
|
|
695
692
|
}
|
|
696
693
|
};
|
|
697
|
-
const
|
|
694
|
+
const getAccountPlatformFromAddress = address => {
|
|
698
695
|
const encoding = detectAddressEncoding(address);
|
|
699
|
-
return
|
|
696
|
+
return getAccountPlatformFromEncoding(encoding);
|
|
700
697
|
};
|
|
701
698
|
|
|
702
|
-
export { DEV_MNEMONIC_ETHEREUM, DEV_MNEMONIC_POLKADOT, addressEncodingFromCurve,
|
|
699
|
+
export { DEV_MNEMONIC_ETHEREUM, DEV_MNEMONIC_POLKADOT, addressEncodingFromCurve, addressFromMnemonic, addressFromPublicKey, blake2b256, blake2b512, blake3, checksumEthereumAddress, decodeSs58Address, deriveKeypair, detectAddressEncoding, encodeAddressEthereum, encodeAddressSolana, encodeAddressSs58, encodeAnyAddress, entropyToMnemonic, entropyToSeed, fromBase58Check, fromBech32, fromBech32m, generateMnemonic, getAccountPlatformFromAddress, getAccountPlatformFromCurve, getAccountPlatformFromEncoding, getDevSeed, getPublicKeyFromSecret, getSafeHash, isAddressEqual, isAddressValid, isBase58CheckAddress, isBech32Address, isBech32mAddress, isBitcoinAddress, isEthereumAddress, isSolanaAddress, isSs58Address, isValidDerivationPath, isValidMnemonic, mnemonicToEntropy, normalizeAddress, parseSecretKey, pbkdf2, removeHexPrefix };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@talismn/crypto",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"author": "Talisman",
|
|
5
5
|
"homepage": "https://talisman.xyz",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
"main": "dist/talismn-crypto.cjs.js",
|
|
16
16
|
"module": "dist/talismn-crypto.esm.js",
|
|
17
17
|
"files": [
|
|
18
|
-
"/dist"
|
|
19
|
-
"/plugins"
|
|
18
|
+
"/dist"
|
|
20
19
|
],
|
|
21
20
|
"engines": {
|
|
22
21
|
"node": ">=18"
|
|
@@ -55,6 +54,6 @@
|
|
|
55
54
|
"scripts": {
|
|
56
55
|
"test": "jest --detectOpenHandles",
|
|
57
56
|
"lint": "eslint src --max-warnings 0",
|
|
58
|
-
"clean": "rm -rf dist
|
|
57
|
+
"clean": "rm -rf dist .turbo node_modules"
|
|
59
58
|
}
|
|
60
59
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const isValidAddress: (address: string) => boolean;
|