forked from tornado-packages/ethers.js
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f318fd9cf1 | ||
|
|
c15a89832b | ||
|
|
94b0abc240 | ||
|
|
72edcd054f | ||
|
|
e4a2f8ac6c | ||
|
|
c6d7b31a84 | ||
|
|
0ed983a264 | ||
|
|
8fab48a380 | ||
|
|
86e815999d | ||
|
|
a2306f7870 | ||
|
|
60b75c10d7 | ||
|
|
41c2c8a729 | ||
|
|
9785eed8dd | ||
|
|
527de7ba5e | ||
|
|
14484e566e | ||
|
|
429af2c40d | ||
|
|
11fffd1690 | ||
|
|
af3aed4580 | ||
|
|
3a3764bdb4 | ||
|
|
18ee2c518c | ||
|
|
36172f7f7b |
@@ -9,7 +9,7 @@ Complete Ethereum wallet implementation and utilities in JavaScript (and TypeScr
|
||||
|
||||
- Keep your private keys in your client, **safe** and sound
|
||||
- Import and export **JSON wallets** (Geth, Parity and crowdsale)
|
||||
- Import and export BIP 39 **mnemonic phrases** (12 word backup phrases) and **HD Wallets** (English, Italian, Japanese, Korean, Simplified Chinese, Traditional Chinese; more coming soon)
|
||||
- Import and export BIP 39 **mnemonic phrases** (12 word backup phrases) and **HD Wallets** (English, French, Italian, Japanese, Korean, Simplified Chinese, Spanish, Traditional Chinese)
|
||||
- Meta-classes create JavaScript objects from any contract ABI, including **ABIv2** and **Human-Readable ABI**
|
||||
- Connect to Ethereum nodes over [JSON-RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC), [INFURA](https://infura.io), [Etherscan](https://etherscan.io), or [MetaMask](https://metamask.io)
|
||||
- **ENS names** are first-class citizens; they can be used anywhere an Ethereum addresses can be used
|
||||
|
||||
2
_version.d.ts
vendored
2
_version.d.ts
vendored
@@ -1 +1 @@
|
||||
export declare const version = "4.0.23";
|
||||
export declare const version = "4.0.25";
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.version = "4.0.23";
|
||||
exports.version = "4.0.25";
|
||||
|
||||
5
contract.d.ts
vendored
5
contract.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
import { BigNumber } from './utils/bignumber';
|
||||
import { Indexed, Interface } from './utils/interface';
|
||||
import { UnsignedTransaction } from './utils/transaction';
|
||||
import { Provider } from './providers/abstract-provider';
|
||||
import { BlockTag, Provider } from './providers/abstract-provider';
|
||||
import { Signer } from './abstract-signer';
|
||||
import { Arrayish } from './utils/bytes';
|
||||
import { ParamType } from './utils/abi-coder';
|
||||
@@ -50,9 +50,10 @@ export declare class Contract {
|
||||
readonly [name: string]: ContractFunction | any;
|
||||
readonly addressPromise: Promise<string>;
|
||||
readonly deployTransaction: TransactionResponse;
|
||||
private _deployed;
|
||||
private _deployedPromise;
|
||||
constructor(addressOrName: string, contractInterface: Array<string | ParamType> | string | Interface, signerOrProvider: Signer | Provider);
|
||||
deployed(): Promise<Contract>;
|
||||
_deployed(blockTag?: BlockTag): Promise<Contract>;
|
||||
fallback(overrides?: TransactionRequest): Promise<TransactionResponse>;
|
||||
connect(signerOrProvider: Signer | Provider | string): Contract;
|
||||
attach(addressOrName: string): Contract;
|
||||
|
||||
14
contract.js
14
contract.js
@@ -135,8 +135,7 @@ function runMethod(contract, functionName, estimateOnly) {
|
||||
errors.throwError('cannot override ' + key, errors.UNSUPPORTED_OPERATION, { operation: key });
|
||||
}
|
||||
});
|
||||
// Send to the contract address (after checking the contract is deployed)
|
||||
tx.to = contract.deployed().then(function () {
|
||||
tx.to = contract._deployed(blockTag).then(function () {
|
||||
return contract.addressPromise;
|
||||
});
|
||||
return resolveAddresses(contract.provider, params, method.inputs).then(function (params) {
|
||||
@@ -332,11 +331,14 @@ var Contract = /** @class */ (function () {
|
||||
}
|
||||
// @TODO: Allow timeout?
|
||||
Contract.prototype.deployed = function () {
|
||||
return this._deployed();
|
||||
};
|
||||
Contract.prototype._deployed = function (blockTag) {
|
||||
var _this = this;
|
||||
if (!this._deployed) {
|
||||
if (!this._deployedPromise) {
|
||||
// If we were just deployed, we know the transaction we should occur in
|
||||
if (this.deployTransaction) {
|
||||
this._deployed = this.deployTransaction.wait().then(function () {
|
||||
this._deployedPromise = this.deployTransaction.wait().then(function () {
|
||||
return _this;
|
||||
});
|
||||
}
|
||||
@@ -344,7 +346,7 @@ var Contract = /** @class */ (function () {
|
||||
// @TODO: Once we allow a timeout to be passed in, we will wait
|
||||
// up to that many blocks for getCode
|
||||
// Otherwise, poll for our code to be deployed
|
||||
this._deployed = this.provider.getCode(this.address).then(function (code) {
|
||||
this._deployedPromise = this.provider.getCode(this.address, blockTag).then(function (code) {
|
||||
if (code === '0x') {
|
||||
errors.throwError('contract not deployed', errors.UNSUPPORTED_OPERATION, {
|
||||
contractAddress: _this.address,
|
||||
@@ -355,7 +357,7 @@ var Contract = /** @class */ (function () {
|
||||
});
|
||||
}
|
||||
}
|
||||
return this._deployed;
|
||||
return this._deployedPromise;
|
||||
};
|
||||
// @TODO:
|
||||
// estimateFallback(overrides?: TransactionRequest): Promise<BigNumber>
|
||||
|
||||
597
dist/ethers.js
vendored
597
dist/ethers.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/ethers.min.js
vendored
2
dist/ethers.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/ethers.min.js.map
vendored
2
dist/ethers.min.js.map
vendored
File diff suppressed because one or more lines are too long
29
dist/ethers.types.txt
vendored
29
dist/ethers.types.txt
vendored
@@ -26,7 +26,7 @@ declare module 'ethers/contract' {
|
||||
import { BigNumber } from 'ethers/utils/bignumber';
|
||||
import { Indexed, Interface } from 'ethers/utils/interface';
|
||||
import { UnsignedTransaction } from 'ethers/utils/transaction';
|
||||
import { Provider } from 'ethers/providers/abstract-provider';
|
||||
import { BlockTag, Provider } from 'ethers/providers/abstract-provider';
|
||||
import { Signer } from 'ethers/abstract-signer';
|
||||
import { Arrayish } from 'ethers/utils/bytes';
|
||||
import { ParamType } from 'ethers/utils/abi-coder';
|
||||
@@ -77,6 +77,7 @@ declare module 'ethers/contract' {
|
||||
readonly deployTransaction: TransactionResponse;
|
||||
constructor(addressOrName: string, contractInterface: Array<string | ParamType> | string | Interface, signerOrProvider: Signer | Provider);
|
||||
deployed(): Promise<Contract>;
|
||||
_deployed(blockTag?: BlockTag): Promise<Contract>;
|
||||
fallback(overrides?: TransactionRequest): Promise<TransactionResponse>;
|
||||
connect(signerOrProvider: Signer | Provider | string): Contract;
|
||||
attach(addressOrName: string): Contract;
|
||||
@@ -265,7 +266,7 @@ declare module 'ethers/utils/shims' {
|
||||
}
|
||||
|
||||
declare module 'ethers/_version' {
|
||||
export const version = "4.0.23";
|
||||
export const version = "4.0.25";
|
||||
}
|
||||
|
||||
declare module 'ethers/utils/bignumber' {
|
||||
@@ -474,6 +475,11 @@ declare module 'ethers/providers/abstract-provider' {
|
||||
address?: string;
|
||||
topics?: Array<string | Array<string>>;
|
||||
};
|
||||
export type FilterByBlock = {
|
||||
blockHash?: string;
|
||||
address?: string;
|
||||
topics?: Array<string | Array<string>>;
|
||||
};
|
||||
export interface Log {
|
||||
blockNumber?: number;
|
||||
blockHash?: string;
|
||||
@@ -538,7 +544,7 @@ declare module 'ethers/providers/abstract-provider' {
|
||||
abstract getBlock(blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>, includeTransactions?: boolean): Promise<Block>;
|
||||
abstract getTransaction(transactionHash: string): Promise<TransactionResponse>;
|
||||
abstract getTransactionReceipt(transactionHash: string): Promise<TransactionReceipt>;
|
||||
abstract getLogs(filter: Filter): Promise<Array<Log>>;
|
||||
abstract getLogs(filter: Filter | FilterByBlock): Promise<Array<Log>>;
|
||||
abstract resolveName(name: string | Promise<string>): Promise<string>;
|
||||
abstract lookupAddress(address: string | Promise<string>): Promise<string>;
|
||||
abstract on(eventName: EventType, listener: Listener): Provider;
|
||||
@@ -632,6 +638,8 @@ declare module 'ethers/utils/hdnode' {
|
||||
export class HDNode {
|
||||
readonly privateKey: string;
|
||||
readonly publicKey: string;
|
||||
readonly fingerprint: string;
|
||||
readonly parentFingerprint: string;
|
||||
readonly address: string;
|
||||
readonly mnemonic: string;
|
||||
readonly path: string;
|
||||
@@ -645,11 +653,14 @@ declare module 'ethers/utils/hdnode' {
|
||||
* - fromMnemonic
|
||||
* - fromSeed
|
||||
*/
|
||||
constructor(constructorGuard: any, privateKey: Arrayish, chainCode: Uint8Array, index: number, depth: number, mnemonic: string, path: string);
|
||||
constructor(constructorGuard: any, privateKey: string, publicKey: string, parentFingerprint: string, chainCode: string, index: number, depth: number, mnemonic: string, path: string);
|
||||
readonly extendedKey: string;
|
||||
neuter(): HDNode;
|
||||
derivePath(path: string): HDNode;
|
||||
static isHDNode(value: any): value is HDNode;
|
||||
}
|
||||
export function fromMnemonic(mnemonic: string, wordlist?: Wordlist): HDNode;
|
||||
export function fromExtendedKey(extendedKey: string): HDNode;
|
||||
export function fromMnemonic(mnemonic: string, wordlist?: Wordlist, password?: string): HDNode;
|
||||
export function fromSeed(seed: Arrayish): HDNode;
|
||||
export function mnemonicToSeed(mnemonic: string, password?: string): string;
|
||||
export function mnemonicToEntropy(mnemonic: string, wordlist?: Wordlist): string;
|
||||
@@ -717,7 +728,7 @@ declare module 'ethers/utils/secret-storage' {
|
||||
declare module 'ethers/providers/base-provider' {
|
||||
import { BigNumber } from 'ethers/utils/bignumber';
|
||||
import { Provider } from 'ethers/providers/abstract-provider';
|
||||
import { Block, BlockTag, EventType, Filter, Listener, Log, TransactionReceipt, TransactionRequest, TransactionResponse } from 'ethers/providers/abstract-provider';
|
||||
import { Block, BlockTag, EventType, Filter, FilterByBlock, Listener, Log, TransactionReceipt, TransactionRequest, TransactionResponse } from 'ethers/providers/abstract-provider';
|
||||
import { BigNumberish } from 'ethers/utils/bignumber';
|
||||
import { Transaction } from 'ethers/utils/transaction';
|
||||
import { Network, Networkish } from 'ethers/utils/networks';
|
||||
@@ -758,7 +769,7 @@ declare module 'ethers/providers/base-provider' {
|
||||
getBlock(blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>, includeTransactions?: boolean): Promise<Block>;
|
||||
getTransaction(transactionHash: string): Promise<TransactionResponse>;
|
||||
getTransactionReceipt(transactionHash: string): Promise<TransactionReceipt>;
|
||||
getLogs(filter: Filter): Promise<Array<Log>>;
|
||||
getLogs(filter: Filter | FilterByBlock): Promise<Array<Log>>;
|
||||
getEtherPrice(): Promise<number>;
|
||||
resolveName(name: string | Promise<string>): Promise<string>;
|
||||
lookupAddress(address: string | Promise<string>): Promise<string>;
|
||||
@@ -773,7 +784,7 @@ declare module 'ethers/providers/base-provider' {
|
||||
emit(eventName: EventType, ...args: Array<any>): boolean;
|
||||
listenerCount(eventName?: EventType): number;
|
||||
listeners(eventName: EventType): Array<Listener>;
|
||||
removeAllListeners(eventName: EventType): Provider;
|
||||
removeAllListeners(eventName?: EventType): Provider;
|
||||
removeListener(eventName: EventType, listener: Listener): Provider;
|
||||
}
|
||||
}
|
||||
@@ -915,6 +926,7 @@ declare module 'ethers/utils/keccak256' {
|
||||
|
||||
declare module 'ethers/utils/sha2' {
|
||||
import { Arrayish } from 'ethers/utils/bytes';
|
||||
export function ripemd160(data: Arrayish): string;
|
||||
export function sha256(data: Arrayish): string;
|
||||
export function sha512(data: Arrayish): string;
|
||||
}
|
||||
@@ -975,6 +987,7 @@ declare module 'ethers/utils/secp256k1' {
|
||||
constructor(privateKey: Arrayish | string);
|
||||
sign(digest: Arrayish | string): Signature;
|
||||
computeSharedSecret(otherKey: Arrayish | string): string;
|
||||
_addPoint(other: Arrayish | string): string;
|
||||
}
|
||||
export function computePublicKey(key: Arrayish | string, compressed?: boolean): string;
|
||||
export function computeAddress(key: Arrayish | string): string;
|
||||
|
||||
@@ -111,7 +111,7 @@ function taskBundle(name, options) {
|
||||
"elliptic/package.json" : ellipticPackage,
|
||||
|
||||
// Remove RIPEMD160 and unneeded hashing algorithms
|
||||
"hash.js/lib/hash/ripemd.js": "module.exports = {ripemd160: null}",
|
||||
//"hash.js/lib/hash/ripemd.js": "module.exports = {ripemd160: null}",
|
||||
"hash.js/lib/hash/sha/1.js": empty,
|
||||
"hash.js/lib/hash/sha/224.js": empty,
|
||||
"hash.js/lib/hash/sha/384.js": empty,
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ethers",
|
||||
"version": "4.0.23",
|
||||
"version": "4.0.25",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ethers",
|
||||
"version": "4.0.23",
|
||||
"version": "4.0.25",
|
||||
"description": "Ethereum wallet library.",
|
||||
"main": "./index.js",
|
||||
"types": "./index.d.ts",
|
||||
|
||||
7
providers/abstract-provider.d.ts
vendored
7
providers/abstract-provider.d.ts
vendored
@@ -24,6 +24,11 @@ export declare type Filter = {
|
||||
address?: string;
|
||||
topics?: Array<string | Array<string>>;
|
||||
};
|
||||
export declare type FilterByBlock = {
|
||||
blockHash?: string;
|
||||
address?: string;
|
||||
topics?: Array<string | Array<string>>;
|
||||
};
|
||||
export interface Log {
|
||||
blockNumber?: number;
|
||||
blockHash?: string;
|
||||
@@ -88,7 +93,7 @@ export declare abstract class Provider implements OnceBlockable {
|
||||
abstract getBlock(blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>, includeTransactions?: boolean): Promise<Block>;
|
||||
abstract getTransaction(transactionHash: string): Promise<TransactionResponse>;
|
||||
abstract getTransactionReceipt(transactionHash: string): Promise<TransactionReceipt>;
|
||||
abstract getLogs(filter: Filter): Promise<Array<Log>>;
|
||||
abstract getLogs(filter: Filter | FilterByBlock): Promise<Array<Log>>;
|
||||
abstract resolveName(name: string | Promise<string>): Promise<string>;
|
||||
abstract lookupAddress(address: string | Promise<string>): Promise<string>;
|
||||
abstract on(eventName: EventType, listener: Listener): Provider;
|
||||
|
||||
6
providers/base-provider.d.ts
vendored
6
providers/base-provider.d.ts
vendored
@@ -1,6 +1,6 @@
|
||||
import { BigNumber } from '../utils/bignumber';
|
||||
import { Provider } from './abstract-provider';
|
||||
import { Block, BlockTag, EventType, Filter, Listener, Log, TransactionReceipt, TransactionRequest, TransactionResponse } from './abstract-provider';
|
||||
import { Block, BlockTag, EventType, Filter, FilterByBlock, Listener, Log, TransactionReceipt, TransactionRequest, TransactionResponse } from './abstract-provider';
|
||||
import { BigNumberish } from '../utils/bignumber';
|
||||
import { Transaction } from '../utils/transaction';
|
||||
import { Network, Networkish } from '../utils/networks';
|
||||
@@ -51,7 +51,7 @@ export declare class BaseProvider extends Provider {
|
||||
getBlock(blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>, includeTransactions?: boolean): Promise<Block>;
|
||||
getTransaction(transactionHash: string): Promise<TransactionResponse>;
|
||||
getTransactionReceipt(transactionHash: string): Promise<TransactionReceipt>;
|
||||
getLogs(filter: Filter): Promise<Array<Log>>;
|
||||
getLogs(filter: Filter | FilterByBlock): Promise<Array<Log>>;
|
||||
getEtherPrice(): Promise<number>;
|
||||
private _resolveNames;
|
||||
private _getResolver;
|
||||
@@ -69,6 +69,6 @@ export declare class BaseProvider extends Provider {
|
||||
emit(eventName: EventType, ...args: Array<any>): boolean;
|
||||
listenerCount(eventName?: EventType): number;
|
||||
listeners(eventName: EventType): Array<Listener>;
|
||||
removeAllListeners(eventName: EventType): Provider;
|
||||
removeAllListeners(eventName?: EventType): Provider;
|
||||
removeListener(eventName: EventType, listener: Listener): Provider;
|
||||
}
|
||||
|
||||
@@ -326,7 +326,15 @@ var formatFilter = {
|
||||
address: allowNull(address_1.getAddress, undefined),
|
||||
topics: allowNull(checkTopics, undefined),
|
||||
};
|
||||
var formatFilterByBlock = {
|
||||
blockHash: allowNull(checkHash, undefined),
|
||||
address: allowNull(address_1.getAddress, undefined),
|
||||
topics: allowNull(checkTopics, undefined),
|
||||
};
|
||||
function checkFilter(filter) {
|
||||
if (filter && filter.blockHash) {
|
||||
return check(formatFilterByBlock, filter);
|
||||
}
|
||||
return check(formatFilter, filter);
|
||||
}
|
||||
var formatLog = {
|
||||
@@ -486,8 +494,12 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
// Sweep balances and remove addresses we no longer have events for
|
||||
var newBalances = {};
|
||||
// Find all transaction hashes we are waiting on
|
||||
var uniqueEventTags = {};
|
||||
_this._events.forEach(function (event) {
|
||||
var comps = event.tag.split(':');
|
||||
uniqueEventTags[event.tag] = true;
|
||||
});
|
||||
Object.keys(uniqueEventTags).forEach(function (tag) {
|
||||
var comps = tag.split(':');
|
||||
switch (comps[0]) {
|
||||
case 'tx': {
|
||||
var hash_2 = comps[1];
|
||||
@@ -644,17 +656,19 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
if (confirmations == null) {
|
||||
confirmations = 1;
|
||||
}
|
||||
return web_1.poll(function () {
|
||||
return _this.getTransactionReceipt(transactionHash).then(function (receipt) {
|
||||
if (confirmations === 0) {
|
||||
return receipt;
|
||||
if (confirmations === 0) {
|
||||
return this.getTransactionReceipt(transactionHash);
|
||||
}
|
||||
return new Promise(function (resolve) {
|
||||
var handler = function (receipt) {
|
||||
if (receipt.confirmations < confirmations) {
|
||||
return;
|
||||
}
|
||||
if (receipt == null || receipt.confirmations < confirmations) {
|
||||
return undefined;
|
||||
}
|
||||
return receipt;
|
||||
});
|
||||
}, { onceBlock: this });
|
||||
_this.removeListener(transactionHash, handler);
|
||||
resolve(receipt);
|
||||
};
|
||||
_this.on(transactionHash, handler);
|
||||
});
|
||||
};
|
||||
BaseProvider.prototype.getBlockNumber = function () {
|
||||
var _this = this;
|
||||
@@ -1157,13 +1171,19 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
});
|
||||
};
|
||||
BaseProvider.prototype.removeAllListeners = function (eventName) {
|
||||
var eventTag = getEventTag(eventName);
|
||||
this._events = this._events.filter(function (event) {
|
||||
return (event.tag !== eventTag);
|
||||
});
|
||||
if (eventName === 'pending') {
|
||||
if (eventName == null) {
|
||||
this._events = [];
|
||||
this._stopPending();
|
||||
}
|
||||
else {
|
||||
var eventTag_1 = getEventTag(eventName);
|
||||
this._events = this._events.filter(function (event) {
|
||||
return (event.tag !== eventTag_1);
|
||||
});
|
||||
if (eventName === 'pending') {
|
||||
this._stopPending();
|
||||
}
|
||||
}
|
||||
if (this._events.length === 0) {
|
||||
this.polling = false;
|
||||
}
|
||||
@@ -1173,13 +1193,13 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
var found = false;
|
||||
var eventTag = getEventTag(eventName);
|
||||
this._events = this._events.filter(function (event) {
|
||||
if (event.tag !== eventTag) {
|
||||
if (event.tag !== eventTag || event.listener != listener) {
|
||||
return true;
|
||||
}
|
||||
if (found) {
|
||||
return true;
|
||||
}
|
||||
found = false;
|
||||
found = true;
|
||||
return false;
|
||||
});
|
||||
if (eventName === 'pending' && this.listenerCount('pending') === 0) {
|
||||
|
||||
@@ -104,6 +104,9 @@ var EtherscanProvider = /** @class */ (function (_super) {
|
||||
case 'kovan':
|
||||
baseUrl = 'https://api-kovan.etherscan.io';
|
||||
break;
|
||||
case 'goerli':
|
||||
baseUrl = 'https://api-goerli.etherscan.io';
|
||||
break;
|
||||
default:
|
||||
throw new Error('unsupported network');
|
||||
}
|
||||
@@ -226,6 +229,16 @@ var EtherscanProvider = /** @class */ (function (_super) {
|
||||
if (params.filter.toBlock) {
|
||||
url += '&toBlock=' + checkLogTag(params.filter.toBlock);
|
||||
}
|
||||
if (params.filter.blockHash) {
|
||||
try {
|
||||
errors.throwError("Etherscan does not support blockHash filters", errors.UNSUPPORTED_OPERATION, {
|
||||
operation: "getLogs(blockHash)"
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
if (params.filter.address) {
|
||||
url += '&address=' + params.filter.address;
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const version = "4.0.23";
|
||||
export const version = "4.0.25";
|
||||
|
||||
@@ -181,8 +181,7 @@ function runMethod(contract: Contract, functionName: string, estimateOnly: boole
|
||||
}
|
||||
});
|
||||
|
||||
// Send to the contract address (after checking the contract is deployed)
|
||||
tx.to = contract.deployed().then(() => {
|
||||
tx.to = contract._deployed(blockTag).then(() => {
|
||||
return contract.addressPromise;
|
||||
});
|
||||
|
||||
@@ -211,7 +210,6 @@ function runMethod(contract: Contract, functionName: string, estimateOnly: boole
|
||||
}
|
||||
|
||||
return contract.provider.call(tx, blockTag).then((value) => {
|
||||
|
||||
if ((hexDataLength(value) % 32) === 4 && hexDataSlice(value, 0, 4) === '0x08c379a0') {
|
||||
let reason = defaultAbiCoder.decode([ 'string' ], hexDataSlice(value, 4));
|
||||
errors.throwError('call revert exception', errors.CALL_EXCEPTION, {
|
||||
@@ -360,7 +358,7 @@ export class Contract {
|
||||
// This is only set if the contract was created with a call to deploy
|
||||
readonly deployTransaction: TransactionResponse;
|
||||
|
||||
private _deployed: Promise<Contract>;
|
||||
private _deployedPromise: Promise<Contract>;
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/5453
|
||||
// Once this issue is resolved (there are open PR) we can do this nicer
|
||||
@@ -440,11 +438,15 @@ export class Contract {
|
||||
|
||||
// @TODO: Allow timeout?
|
||||
deployed(): Promise<Contract> {
|
||||
if (!this._deployed) {
|
||||
return this._deployed();
|
||||
}
|
||||
|
||||
_deployed(blockTag?: BlockTag): Promise<Contract> {
|
||||
if (!this._deployedPromise) {
|
||||
|
||||
// If we were just deployed, we know the transaction we should occur in
|
||||
if (this.deployTransaction) {
|
||||
this._deployed = this.deployTransaction.wait().then(() => {
|
||||
this._deployedPromise = this.deployTransaction.wait().then(() => {
|
||||
return this;
|
||||
});
|
||||
|
||||
@@ -453,7 +455,7 @@ export class Contract {
|
||||
// up to that many blocks for getCode
|
||||
|
||||
// Otherwise, poll for our code to be deployed
|
||||
this._deployed = this.provider.getCode(this.address).then((code) => {
|
||||
this._deployedPromise = this.provider.getCode(this.address, blockTag).then((code) => {
|
||||
if (code === '0x') {
|
||||
errors.throwError('contract not deployed', errors.UNSUPPORTED_OPERATION, {
|
||||
contractAddress: this.address,
|
||||
@@ -465,7 +467,7 @@ export class Contract {
|
||||
}
|
||||
}
|
||||
|
||||
return this._deployed;
|
||||
return this._deployedPromise;
|
||||
}
|
||||
|
||||
// @TODO:
|
||||
|
||||
@@ -41,6 +41,16 @@ export type Filter = {
|
||||
topics?: Array<string | Array<string>>,
|
||||
}
|
||||
|
||||
// @TODO: This is not supported as an EventType yet, as it will
|
||||
// need some additional work to adhere to the serialized
|
||||
// format for events. But we want to allow it for getLogs
|
||||
// for now.
|
||||
export type FilterByBlock = {
|
||||
blockHash?: string,
|
||||
address?: string,
|
||||
topics?: Array<string | Array<string>>,
|
||||
}
|
||||
|
||||
export interface Log {
|
||||
blockNumber?: number;
|
||||
blockHash?: string;
|
||||
@@ -134,7 +144,7 @@ export abstract class Provider implements OnceBlockable {
|
||||
abstract getTransaction(transactionHash: string): Promise<TransactionResponse>;
|
||||
abstract getTransactionReceipt(transactionHash: string): Promise<TransactionReceipt>;
|
||||
|
||||
abstract getLogs(filter: Filter): Promise<Array<Log>>;
|
||||
abstract getLogs(filter: Filter | FilterByBlock): Promise<Array<Log>>;
|
||||
|
||||
abstract resolveName(name: string | Promise<string>): Promise<string>;
|
||||
abstract lookupAddress(address: string | Promise<string>): Promise<string>;
|
||||
|
||||
@@ -23,7 +23,7 @@ import { Provider } from './abstract-provider';
|
||||
|
||||
import {
|
||||
Block, BlockTag,
|
||||
EventType, Filter,
|
||||
EventType, Filter, FilterByBlock,
|
||||
Listener,
|
||||
Log,
|
||||
TransactionReceipt, TransactionRequest, TransactionResponse
|
||||
@@ -366,7 +366,16 @@ const formatFilter = {
|
||||
topics: allowNull(checkTopics, undefined),
|
||||
};
|
||||
|
||||
const formatFilterByBlock = {
|
||||
blockHash: allowNull(checkHash, undefined),
|
||||
address: allowNull(getAddress, undefined),
|
||||
topics: allowNull(checkTopics, undefined),
|
||||
};
|
||||
|
||||
function checkFilter(filter: any): any {
|
||||
if (filter && filter.blockHash) {
|
||||
return check(formatFilterByBlock, filter);
|
||||
}
|
||||
return check(formatFilter, filter);
|
||||
}
|
||||
|
||||
@@ -767,15 +776,21 @@ export class BaseProvider extends Provider {
|
||||
|
||||
waitForTransaction(transactionHash: string, confirmations?: number): Promise<TransactionReceipt> {
|
||||
if (confirmations == null) { confirmations = 1; }
|
||||
return poll(() => {
|
||||
return this.getTransactionReceipt(transactionHash).then((receipt) => {
|
||||
if (confirmations === 0) { return receipt; }
|
||||
if (receipt == null || receipt.confirmations < confirmations) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.getTransactionReceipt(transactionHash).then((receipt) => {
|
||||
if (confirmations === 0 || (receipt && receipt.confirmations >= confirmations)) {
|
||||
return receipt;
|
||||
});
|
||||
}, { onceBlock: this });
|
||||
}
|
||||
|
||||
return <Promise<TransactionReceipt>>(new Promise((resolve) => {
|
||||
let handler = (receipt: TransactionReceipt) => {
|
||||
if (receipt.confirmations < confirmations) { return; }
|
||||
this.removeListener(transactionHash, handler);
|
||||
resolve(receipt);
|
||||
}
|
||||
this.on(transactionHash, handler);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
getBlockNumber(): Promise<number> {
|
||||
@@ -1071,7 +1086,7 @@ export class BaseProvider extends Provider {
|
||||
});
|
||||
}
|
||||
|
||||
getLogs(filter: Filter): Promise<Array<Log>> {
|
||||
getLogs(filter: Filter | FilterByBlock): Promise<Array<Log>> {
|
||||
return this.ready.then(() => {
|
||||
return resolveProperties(filter).then((filter) => {
|
||||
return this._resolveNames(filter, ['address']).then((filter) => {
|
||||
@@ -1297,13 +1312,18 @@ export class BaseProvider extends Provider {
|
||||
});
|
||||
}
|
||||
|
||||
removeAllListeners(eventName: EventType): Provider {
|
||||
let eventTag = getEventTag(eventName);
|
||||
this._events = this._events.filter((event) => {
|
||||
return (event.tag !== eventTag);
|
||||
});
|
||||
removeAllListeners(eventName?: EventType): Provider {
|
||||
if (eventName == null) {
|
||||
this._events = [ ];
|
||||
this._stopPending();
|
||||
} else {
|
||||
let eventTag = getEventTag(eventName);
|
||||
this._events = this._events.filter((event) => {
|
||||
return (event.tag !== eventTag);
|
||||
});
|
||||
if (eventName === 'pending') { this._stopPending(); }
|
||||
}
|
||||
|
||||
if (eventName === 'pending') { this._stopPending(); }
|
||||
if (this._events.length === 0) { this.polling = false; }
|
||||
|
||||
return this;
|
||||
@@ -1314,9 +1334,9 @@ export class BaseProvider extends Provider {
|
||||
|
||||
let eventTag = getEventTag(eventName);
|
||||
this._events = this._events.filter((event) => {
|
||||
if (event.tag !== eventTag) { return true; }
|
||||
if (event.tag !== eventTag || event.listener != listener) { return true; }
|
||||
if (found) { return true; }
|
||||
found = false;
|
||||
found = true;
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
@@ -98,6 +98,9 @@ export class EtherscanProvider extends BaseProvider{
|
||||
case 'kovan':
|
||||
baseUrl = 'https://api-kovan.etherscan.io';
|
||||
break;
|
||||
case 'goerli':
|
||||
baseUrl = 'https://api-goerli.etherscan.io';
|
||||
break;
|
||||
default:
|
||||
throw new Error('unsupported network');
|
||||
}
|
||||
@@ -234,6 +237,16 @@ export class EtherscanProvider extends BaseProvider{
|
||||
url += '&toBlock=' + checkLogTag(params.filter.toBlock);
|
||||
}
|
||||
|
||||
if (params.filter.blockHash) {
|
||||
try {
|
||||
errors.throwError("Etherscan does not support blockHash filters", errors.UNSUPPORTED_OPERATION, {
|
||||
operation: "getLogs(blockHash)"
|
||||
});
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (params.filter.address) {
|
||||
url += '&address=' + params.filter.address;
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ export class JsonRpcSigner extends Signer {
|
||||
if (tx === null) { return undefined; }
|
||||
return this.provider._wrapTransaction(tx, hash);
|
||||
});
|
||||
}, { onceBlock: this.provider }).catch((error: Error) => {
|
||||
}, { fastRetry: 250, onceBlock: this.provider }).catch((error: Error) => {
|
||||
(<any>error).transactionHash = hash;
|
||||
throw error;
|
||||
});
|
||||
|
||||
143
src.ts/utils/basex.ts
Normal file
143
src.ts/utils/basex.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* var basex = require('base-x');
|
||||
*
|
||||
* This implementation is heavily based on base-x. The main reason to
|
||||
* deviate was to prevent the dependency of Buffer.
|
||||
*
|
||||
* Contributors:
|
||||
*
|
||||
* base-x encoding
|
||||
* Forked from https://github.com/cryptocoinjs/bs58
|
||||
* Originally written by Mike Hearn for BitcoinJ
|
||||
* Copyright (c) 2011 Google Inc
|
||||
* Ported to JavaScript by Stefan Thomas
|
||||
* Merged Buffer refactorings from base58-native by Stephen Pair
|
||||
* Copyright (c) 2013 BitPay Inc
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright base-x contributors (c) 2016
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
import { arrayify, Arrayish } from "./bytes";
|
||||
import { defineReadOnly } from "./properties";
|
||||
|
||||
export class BaseX {
|
||||
readonly alphabet: string;
|
||||
readonly base: number;
|
||||
|
||||
private _alphabetMap: { [ character: string ]: number };
|
||||
private _leader: string;
|
||||
|
||||
constructor(alphabet: string) {
|
||||
defineReadOnly(this, "alphabet", alphabet);
|
||||
defineReadOnly(this, "base", alphabet.length);
|
||||
|
||||
defineReadOnly(this, "_alphabetMap", { });
|
||||
defineReadOnly(this, "_leader", alphabet.charAt(0));
|
||||
|
||||
// pre-compute lookup table
|
||||
for (let i = 0; i < alphabet.length; i++) {
|
||||
this._alphabetMap[alphabet.charAt(i)] = i;
|
||||
}
|
||||
}
|
||||
|
||||
encode(value: Arrayish | string): string {
|
||||
let source = arrayify(value);
|
||||
|
||||
if (source.length === 0) { return ''; }
|
||||
|
||||
let digits = [ 0 ]
|
||||
for (let i = 0; i < source.length; ++i) {
|
||||
let carry = source[i];
|
||||
for (let j = 0; j < digits.length; ++j) {
|
||||
carry += digits[j] << 8;
|
||||
digits[j] = carry % this.base;
|
||||
carry = (carry / this.base) | 0;
|
||||
}
|
||||
|
||||
while (carry > 0) {
|
||||
digits.push(carry % this.base);
|
||||
carry = (carry / this.base) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
let string = ''
|
||||
|
||||
// deal with leading zeros
|
||||
for (let k = 0; source[k] === 0 && k < source.length - 1; ++k) {
|
||||
string += this._leader;
|
||||
}
|
||||
|
||||
// convert digits to a string
|
||||
for (let q = digits.length - 1; q >= 0; --q) {
|
||||
string += this.alphabet[digits[q]];
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
decode(value: string): Uint8Array {
|
||||
if (typeof(value) !== 'string') {
|
||||
throw new TypeError('Expected String');
|
||||
}
|
||||
|
||||
let bytes: Array<number> = [];
|
||||
if (value.length === 0) { return new Uint8Array(bytes); }
|
||||
|
||||
bytes.push(0);
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
let byte = this._alphabetMap[value[i]];
|
||||
|
||||
if (byte === undefined) {
|
||||
throw new Error('Non-base' + this.base + ' character');
|
||||
}
|
||||
|
||||
let carry = byte;
|
||||
for (let j = 0; j < bytes.length; ++j) {
|
||||
carry += bytes[j] * this.base;
|
||||
bytes[j] = carry & 0xff;
|
||||
carry >>= 8;
|
||||
}
|
||||
|
||||
while (carry > 0) {
|
||||
bytes.push(carry & 0xff);
|
||||
carry >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
// deal with leading zeros
|
||||
for (let k = 0; value[k] === this._leader && k < value.length - 1; ++k) {
|
||||
bytes.push(0)
|
||||
}
|
||||
|
||||
return arrayify(new Uint8Array(bytes.reverse()))
|
||||
}
|
||||
}
|
||||
|
||||
const Base32 = new BaseX("abcdefghijklmnopqrstuvwxyz234567");
|
||||
const Base58 = new BaseX("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
|
||||
|
||||
export { Base32, Base58 };
|
||||
|
||||
//console.log(Base58.decode("Qmd2V777o5XvJbYMeMb8k2nU5f8d3ciUQ5YpYuWhzv8iDj"))
|
||||
//console.log(Base58.encode(Base58.decode("Qmd2V777o5XvJbYMeMb8k2nU5f8d3ciUQ5YpYuWhzv8iDj")))
|
||||
@@ -40,7 +40,7 @@ function addSlice(array: Uint8Array): Uint8Array {
|
||||
|
||||
array.slice = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
return new Uint8Array(Array.prototype.slice.apply(array, args));
|
||||
return addSlice(new Uint8Array(Array.prototype.slice.apply(array, args)));
|
||||
}
|
||||
|
||||
return array;
|
||||
@@ -168,6 +168,15 @@ export function hexlify(value: Arrayish | Hexable | number): string {
|
||||
errors.throwError('cannot hexlify negative value', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
||||
}
|
||||
|
||||
// @TODO: Roll this into the above error as a numeric fault (overflow); next version, not backward compatible
|
||||
// We can about (value == MAX_INT) to as well, since that may indicate we underflowed already
|
||||
if (value >= 9007199254740991) {
|
||||
errors.throwError("out-of-range", errors.NUMERIC_FAULT, {
|
||||
operartion: "hexlify",
|
||||
fault: "out-of-safe-range"
|
||||
});
|
||||
}
|
||||
|
||||
var hex = '';
|
||||
while (value) {
|
||||
hex = HexCharacters[value & 0x0f] + hex;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
// See: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
||||
// See: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
|
||||
@@ -13,14 +13,15 @@ import { langEn } from '../wordlists/lang-en';
|
||||
//import { register } from '../wordlists/wordlist';
|
||||
//register(langEn);
|
||||
|
||||
import { arrayify, hexlify } from './bytes';
|
||||
import { bigNumberify } from './bignumber';
|
||||
import { Base58 } from "./basex";
|
||||
import { arrayify, concat, hexDataSlice, hexZeroPad, hexlify } from './bytes';
|
||||
import { BigNumber, bigNumberify } from './bignumber';
|
||||
import { toUtf8Bytes, UnicodeNormalizationForm } from './utf8';
|
||||
import { pbkdf2 } from './pbkdf2';
|
||||
import { computeHmac, SupportedAlgorithms } from './hmac';
|
||||
import { defineReadOnly, isType, setType } from './properties';
|
||||
import { computeAddress, KeyPair } from './secp256k1';
|
||||
import { sha256 } from './sha2';
|
||||
import { ripemd160, sha256 } from './sha2';
|
||||
|
||||
const N = bigNumberify("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
|
||||
|
||||
@@ -30,9 +31,9 @@ import { Wordlist } from './wordlist';
|
||||
|
||||
|
||||
// "Bitcoin seed"
|
||||
var MasterSecret = toUtf8Bytes('Bitcoin seed');
|
||||
const MasterSecret = toUtf8Bytes('Bitcoin seed');
|
||||
|
||||
var HardenedBit = 0x80000000;
|
||||
const HardenedBit = 0x80000000;
|
||||
|
||||
// Returns a byte with the MSB bits set
|
||||
function getUpperMask(bits: number): number {
|
||||
@@ -44,16 +45,26 @@ function getLowerMask(bits: number): number {
|
||||
return (1 << bits) - 1;
|
||||
}
|
||||
|
||||
function bytes32(value: Arrayish | BigNumber | number): string {
|
||||
return hexZeroPad(hexlify(value), 32);
|
||||
}
|
||||
|
||||
function base58check(data: Uint8Array): string {
|
||||
let checksum = hexDataSlice(sha256(sha256(data)), 0, 4);
|
||||
return Base58.encode(concat([ data, checksum ]));
|
||||
}
|
||||
|
||||
const _constructorGuard: any = {};
|
||||
|
||||
export const defaultPath = "m/44'/60'/0'/0/0";
|
||||
|
||||
export class HDNode {
|
||||
private readonly keyPair: KeyPair;
|
||||
|
||||
readonly privateKey: string;
|
||||
readonly publicKey: string;
|
||||
|
||||
readonly fingerprint: string;
|
||||
readonly parentFingerprint: string;
|
||||
|
||||
readonly address: string;
|
||||
|
||||
readonly mnemonic: string;
|
||||
@@ -71,21 +82,28 @@ export class HDNode {
|
||||
* - fromMnemonic
|
||||
* - fromSeed
|
||||
*/
|
||||
constructor(constructorGuard: any, privateKey: Arrayish, chainCode: Uint8Array, index: number, depth: number, mnemonic: string, path: string) {
|
||||
constructor(constructorGuard: any, privateKey: string, publicKey: string, parentFingerprint: string, chainCode: string, index: number, depth: number, mnemonic: string, path: string) {
|
||||
errors.checkNew(this, HDNode);
|
||||
|
||||
if (constructorGuard !== _constructorGuard) {
|
||||
throw new Error('HDNode constructor cannot be called directly');
|
||||
}
|
||||
|
||||
defineReadOnly(this, 'keyPair', new KeyPair(privateKey));
|
||||
if (privateKey) {
|
||||
let keyPair = new KeyPair(privateKey);
|
||||
defineReadOnly(this, 'privateKey', keyPair.privateKey);
|
||||
defineReadOnly(this, 'publicKey', keyPair.compressedPublicKey);
|
||||
} else {
|
||||
defineReadOnly(this, 'privateKey', null);
|
||||
defineReadOnly(this, 'publicKey', hexlify(publicKey));
|
||||
}
|
||||
|
||||
defineReadOnly(this, 'privateKey', this.keyPair.privateKey);
|
||||
defineReadOnly(this, 'publicKey', this.keyPair.compressedPublicKey);
|
||||
defineReadOnly(this, 'parentFingerprint', parentFingerprint);
|
||||
defineReadOnly(this, 'fingerprint', hexDataSlice(ripemd160(sha256(this.publicKey)), 0, 4));
|
||||
|
||||
defineReadOnly(this, 'address', computeAddress(this.publicKey));
|
||||
|
||||
defineReadOnly(this, 'chainCode', hexlify(chainCode));
|
||||
defineReadOnly(this, 'chainCode', chainCode);
|
||||
|
||||
defineReadOnly(this, 'index', index);
|
||||
defineReadOnly(this, 'depth', depth);
|
||||
@@ -96,22 +114,43 @@ export class HDNode {
|
||||
setType(this, 'HDNode');
|
||||
}
|
||||
|
||||
get extendedKey(): string {
|
||||
// We only support the mainnet values for now, but if anyone needs
|
||||
// testnet values, let me know. I believe current senitment is that
|
||||
// we should always use mainnet, and use BIP-44 to derive the network
|
||||
// - Mainnet: public=0x0488B21E, private=0x0488ADE4
|
||||
// - Testnet: public=0x043587CF, private=0x04358394
|
||||
|
||||
if (this.depth >= 256) { throw new Error("Depth too large!"); }
|
||||
|
||||
return base58check(concat([
|
||||
((this.privateKey != null) ? "0x0488ADE4": "0x0488B21E"),
|
||||
hexlify(this.depth),
|
||||
this.parentFingerprint,
|
||||
hexZeroPad(hexlify(this.index), 4),
|
||||
this.chainCode,
|
||||
((this.privateKey != null) ? concat([ "0x00", this.privateKey ]): this.publicKey),
|
||||
]));
|
||||
}
|
||||
|
||||
neuter(): HDNode {
|
||||
return new HDNode(_constructorGuard, null, this.publicKey, this.parentFingerprint, this.chainCode, this.index, this.depth, null, this.path);
|
||||
}
|
||||
|
||||
private _derive(index: number): HDNode {
|
||||
|
||||
// Public parent key -> public child key
|
||||
if (!this.privateKey) {
|
||||
if (index >= HardenedBit) { throw new Error('cannot derive child of neutered node'); }
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
var data = new Uint8Array(37);
|
||||
if (index > 0xffffffff) { throw new Error("invalid index - " + String(index)); }
|
||||
|
||||
// Base path
|
||||
var mnemonic = this.mnemonic;
|
||||
var path = this.path;
|
||||
let path = this.path;
|
||||
if (path) { path += '/' + (index & ~HardenedBit); }
|
||||
|
||||
let data = new Uint8Array(37);
|
||||
|
||||
if (index & HardenedBit) {
|
||||
if (!this.privateKey) {
|
||||
throw new Error('cannot derive child of neutered node');
|
||||
}
|
||||
|
||||
// Data = 0x00 || ser_256(k_par)
|
||||
data.set(arrayify(this.privateKey), 1);
|
||||
|
||||
@@ -120,39 +159,50 @@ export class HDNode {
|
||||
|
||||
} else {
|
||||
// Data = ser_p(point(k_par))
|
||||
data.set(this.keyPair.publicKeyBytes);
|
||||
data.set(arrayify(this.publicKey));
|
||||
}
|
||||
|
||||
// Data += ser_32(i)
|
||||
for (var i = 24; i >= 0; i -= 8) { data[33 + (i >> 3)] = ((index >> (24 - i)) & 0xff); }
|
||||
for (let i = 24; i >= 0; i -= 8) { data[33 + (i >> 3)] = ((index >> (24 - i)) & 0xff); }
|
||||
|
||||
var I = computeHmac(SupportedAlgorithms.sha512, this.chainCode, data);
|
||||
var IL = bigNumberify(I.slice(0, 32));
|
||||
var IR = I.slice(32);
|
||||
let I = computeHmac(SupportedAlgorithms.sha512, this.chainCode, data);
|
||||
let IL = I.slice(0, 32);
|
||||
let IR = I.slice(32);
|
||||
|
||||
var ki = IL.add(this.keyPair.privateKey).mod(N);
|
||||
// The private key
|
||||
|
||||
return new HDNode(_constructorGuard, arrayify(ki), IR, index, this.depth + 1, mnemonic, path);
|
||||
let ki: string = null
|
||||
// The public key
|
||||
let Ki: string = null;
|
||||
|
||||
if (this.privateKey) {
|
||||
ki = bytes32(bigNumberify(IL).add(this.privateKey).mod(N));
|
||||
} else {
|
||||
let ek = new KeyPair(hexlify(IL));
|
||||
Ki = ek._addPoint(this.publicKey);
|
||||
}
|
||||
|
||||
return new HDNode(_constructorGuard, ki, Ki, this.fingerprint, bytes32(IR), index, this.depth + 1, this.mnemonic, path);
|
||||
}
|
||||
|
||||
derivePath(path: string): HDNode {
|
||||
var components = path.split('/');
|
||||
let components = path.split('/');
|
||||
|
||||
if (components.length === 0 || (components[0] === 'm' && this.depth !== 0)) {
|
||||
throw new Error('invalid path');
|
||||
throw new Error('invalid path - ' + path);
|
||||
}
|
||||
|
||||
if (components[0] === 'm') { components.shift(); }
|
||||
|
||||
var result: HDNode = this;
|
||||
for (var i = 0; i < components.length; i++) {
|
||||
var component = components[i];
|
||||
let result: HDNode = this;
|
||||
for (let i = 0; i < components.length; i++) {
|
||||
let component = components[i];
|
||||
if (component.match(/^[0-9]+'$/)) {
|
||||
var index = parseInt(component.substring(0, component.length - 1));
|
||||
let index = parseInt(component.substring(0, component.length - 1));
|
||||
if (index >= HardenedBit) { throw new Error('invalid path index - ' + component); }
|
||||
result = result._derive(HardenedBit + index);
|
||||
} else if (component.match(/^[0-9]+$/)) {
|
||||
var index = parseInt(component);
|
||||
let index = parseInt(component);
|
||||
if (index >= HardenedBit) { throw new Error('invalid path index - ' + component); }
|
||||
result = result._derive(index);
|
||||
} else {
|
||||
@@ -168,22 +218,53 @@ export class HDNode {
|
||||
}
|
||||
}
|
||||
|
||||
export function fromExtendedKey(extendedKey: string): HDNode {
|
||||
let bytes = Base58.decode(extendedKey);
|
||||
|
||||
if (bytes.length !== 82 || base58check(bytes.slice(0, 78)) !== extendedKey) {
|
||||
errors.throwError("invalid extended key", errors.INVALID_ARGUMENT, {
|
||||
argument: "extendedKey",
|
||||
value: "[REDACTED]"
|
||||
});
|
||||
}
|
||||
|
||||
let depth = bytes[4];
|
||||
let parentFingerprint = hexlify(bytes.slice(5, 9));
|
||||
let index = parseInt(hexlify(bytes.slice(9, 13)).substring(2), 16);
|
||||
let chainCode = hexlify(bytes.slice(13, 45));
|
||||
let key = bytes.slice(45, 78);
|
||||
|
||||
switch (hexlify(bytes.slice(0, 4))) {
|
||||
// Public Key
|
||||
case "0x0488b21e": case "0x043587cf":
|
||||
return new HDNode(_constructorGuard, null, hexlify(key), parentFingerprint, chainCode, index, depth, null, null);
|
||||
|
||||
// Private Key
|
||||
case "0x0488ade4": case "0x04358394 ":
|
||||
if (key[0] !== 0) { break; }
|
||||
return new HDNode(_constructorGuard, hexlify(key.slice(1)), null, parentFingerprint, chainCode, index, depth, null, null);
|
||||
}
|
||||
|
||||
return errors.throwError("invalid extended key", errors.INVALID_ARGUMENT, {
|
||||
argument: "extendedKey",
|
||||
value: "[REDACTED]"
|
||||
});
|
||||
}
|
||||
|
||||
function _fromSeed(seed: Arrayish, mnemonic: string): HDNode {
|
||||
let seedArray: Uint8Array = arrayify(seed);
|
||||
if (seedArray.length < 16 || seedArray.length > 64) { throw new Error('invalid seed'); }
|
||||
|
||||
var I: Uint8Array = arrayify(computeHmac(SupportedAlgorithms.sha512, MasterSecret, seedArray));
|
||||
let I: Uint8Array = arrayify(computeHmac(SupportedAlgorithms.sha512, MasterSecret, seedArray));
|
||||
|
||||
return new HDNode(_constructorGuard, I.slice(0, 32), I.slice(32), 0, 0, mnemonic, 'm');
|
||||
return new HDNode(_constructorGuard, bytes32(I.slice(0, 32)), null, "0x00000000", bytes32(I.slice(32)), 0, 0, mnemonic, 'm');
|
||||
}
|
||||
|
||||
export function fromMnemonic(mnemonic: string, wordlist?: Wordlist): HDNode {
|
||||
export function fromMnemonic(mnemonic: string, wordlist?: Wordlist, password?: string): HDNode {
|
||||
// Check that the checksum s valid (will throw an error)
|
||||
mnemonicToEntropy(mnemonic, wordlist);
|
||||
|
||||
return _fromSeed(mnemonicToSeed(mnemonic), mnemonic);
|
||||
return _fromSeed(mnemonicToSeed(mnemonic, password), mnemonic);
|
||||
}
|
||||
|
||||
export function fromSeed(seed: Arrayish): HDNode {
|
||||
@@ -193,7 +274,7 @@ export function fromSeed(seed: Arrayish): HDNode {
|
||||
export function mnemonicToSeed(mnemonic: string, password?: string): string {
|
||||
if (!password) { password = ''; }
|
||||
|
||||
var salt = toUtf8Bytes('mnemonic' + password, UnicodeNormalizationForm.NFKD);
|
||||
let salt = toUtf8Bytes('mnemonic' + password, UnicodeNormalizationForm.NFKD);
|
||||
|
||||
return hexlify(pbkdf2(toUtf8Bytes(mnemonic, UnicodeNormalizationForm.NFKD), salt, 2048, 64, 'sha512'));
|
||||
}
|
||||
@@ -202,18 +283,18 @@ export function mnemonicToEntropy(mnemonic: string, wordlist?: Wordlist): string
|
||||
if (!wordlist) { wordlist = langEn; }
|
||||
|
||||
errors.checkNormalize();
|
||||
|
||||
var words = wordlist.split(mnemonic);
|
||||
|
||||
let words = wordlist.split(mnemonic);
|
||||
if ((words.length % 3) !== 0) { throw new Error('invalid mnemonic'); }
|
||||
|
||||
var entropy = arrayify(new Uint8Array(Math.ceil(11 * words.length / 8)));
|
||||
let entropy = arrayify(new Uint8Array(Math.ceil(11 * words.length / 8)));
|
||||
|
||||
var offset = 0;
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
var index = wordlist.getWordIndex(words[i].normalize('NFKD'));
|
||||
let offset = 0;
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
let index = wordlist.getWordIndex(words[i].normalize('NFKD'));
|
||||
if (index === -1) { throw new Error('invalid mnemonic'); }
|
||||
|
||||
for (var bit = 0; bit < 11; bit++) {
|
||||
for (let bit = 0; bit < 11; bit++) {
|
||||
if (index & (1 << (10 - bit))) {
|
||||
entropy[offset >> 3] |= (1 << (7 - (offset % 8)));
|
||||
}
|
||||
@@ -221,12 +302,12 @@ export function mnemonicToEntropy(mnemonic: string, wordlist?: Wordlist): string
|
||||
}
|
||||
}
|
||||
|
||||
var entropyBits = 32 * words.length / 3;
|
||||
let entropyBits = 32 * words.length / 3;
|
||||
|
||||
var checksumBits = words.length / 3;
|
||||
var checksumMask = getUpperMask(checksumBits);
|
||||
let checksumBits = words.length / 3;
|
||||
let checksumMask = getUpperMask(checksumBits);
|
||||
|
||||
var checksum = arrayify(sha256(entropy.slice(0, entropyBits / 8)))[0];
|
||||
let checksum = arrayify(sha256(entropy.slice(0, entropyBits / 8)))[0];
|
||||
checksum &= checksumMask;
|
||||
|
||||
if (checksum !== (entropy[entropy.length - 1] & checksumMask)) {
|
||||
@@ -243,10 +324,10 @@ export function entropyToMnemonic(entropy: Arrayish, wordlist?: Wordlist): strin
|
||||
throw new Error('invalid entropy');
|
||||
}
|
||||
|
||||
var indices: Array<number> = [ 0 ];
|
||||
let indices: Array<number> = [ 0 ];
|
||||
|
||||
var remainingBits = 11;
|
||||
for (var i = 0; i < entropy.length; i++) {
|
||||
let remainingBits = 11;
|
||||
for (let i = 0; i < entropy.length; i++) {
|
||||
|
||||
// Consume the whole byte (with still more to go)
|
||||
if (remainingBits > 8) {
|
||||
@@ -268,8 +349,8 @@ export function entropyToMnemonic(entropy: Arrayish, wordlist?: Wordlist): strin
|
||||
}
|
||||
|
||||
// Compute the checksum bits
|
||||
var checksum = arrayify(sha256(entropy))[0];
|
||||
var checksumBits = entropy.length / 4;
|
||||
let checksum = arrayify(sha256(entropy))[0];
|
||||
let checksumBits = entropy.length / 4;
|
||||
checksum &= getUpperMask(checksumBits);
|
||||
|
||||
// Shift the checksum into the word indices
|
||||
|
||||
@@ -82,6 +82,18 @@ const networks: { [name: string]: Network } = {
|
||||
_defaultProvider: ethDefaultProvider('rinkeby')
|
||||
},
|
||||
|
||||
goerli: {
|
||||
chainId: 5,
|
||||
ensAddress: "0x112234455c3a32fd11230c42e7bccd4a84e02010",
|
||||
name: "goerli",
|
||||
_defaultProvider: (providers: any): any => {
|
||||
if (providers.EtherscanProvider) {
|
||||
return new providers.EtherscanProvider("goerli");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
kovan: {
|
||||
chainId: 42,
|
||||
name: 'kovan',
|
||||
|
||||
@@ -62,6 +62,12 @@ export class KeyPair {
|
||||
let otherKeyPair = getCurve().keyFromPublic(arrayify(computePublicKey(otherKey)));
|
||||
return hexZeroPad('0x' + keyPair.derive(otherKeyPair.getPublic()).toString(16), 32);
|
||||
}
|
||||
|
||||
_addPoint(other: Arrayish | string): string {
|
||||
let p0 = getCurve().keyFromPublic(arrayify(this.publicKey));
|
||||
let p1 = getCurve().keyFromPublic(arrayify(other));
|
||||
return "0x" + p0.pub.add(p1.pub).encodeCompressed("hex");
|
||||
}
|
||||
}
|
||||
|
||||
export function computePublicKey(key: Arrayish | string, compressed?: boolean): string {
|
||||
|
||||
@@ -7,6 +7,10 @@ import { arrayify } from './bytes';
|
||||
// Types
|
||||
import { Arrayish } from './bytes';
|
||||
|
||||
export function ripemd160(data: Arrayish): string {
|
||||
return '0x' + (hash.ripemd160().update(arrayify(data)).digest('hex'));
|
||||
}
|
||||
|
||||
export function sha256(data: Arrayish): string {
|
||||
return '0x' + (hash.sha256().update(arrayify(data)).digest('hex'));
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ export type PollOptions = {
|
||||
floor?: number,
|
||||
ceiling?: number,
|
||||
interval?: number,
|
||||
onceBlock?: OnceBlockable
|
||||
onceBlock?: OnceBlockable,
|
||||
fastRetry?: number
|
||||
};
|
||||
|
||||
|
||||
@@ -208,6 +209,8 @@ export function poll(func: () => Promise<any>, options?: PollOptions): Promise<a
|
||||
}, options.timeout)
|
||||
}
|
||||
|
||||
let fastTimeout = options.fastRetry || null;
|
||||
|
||||
let attempt = 0;
|
||||
function check() {
|
||||
return func().then(function(result) {
|
||||
@@ -227,6 +230,13 @@ export function poll(func: () => Promise<any>, options?: PollOptions): Promise<a
|
||||
if (timeout < options.floor) { timeout = options.floor; }
|
||||
if (timeout > options.ceiling) { timeout = options.ceiling; }
|
||||
|
||||
// Fast Timeout, means we quickly try again the first time
|
||||
if (fastTimeout) {
|
||||
attempt--;
|
||||
timeout = fastTimeout;
|
||||
fastTimeout = null;
|
||||
}
|
||||
|
||||
setTimeout(check, timeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@ function getHD(seed) {
|
||||
path: 'm',
|
||||
privateKey: '0x' + privateKey.toString('hex'),
|
||||
address: '0x' + ethereumUtil.privateToAddress(privateKey).toString('hex'),
|
||||
parentFingerprint: rootNode.parentFingerprint,
|
||||
xpriv: rootNode.toBase58(),
|
||||
xpub: rootNode.neutered().toBase58(),
|
||||
}];
|
||||
|
||||
for (var j = 0; j < 5; j++) {
|
||||
@@ -42,6 +45,9 @@ function getHD(seed) {
|
||||
path: path,
|
||||
privateKey: '0x' + privateKey.toString('hex'),
|
||||
address: '0x' + ethereumUtil.privateToAddress(privateKey).toString('hex'),
|
||||
parentFingerprint: node.parentFingerprint,
|
||||
xpriv: node.toBase58(),
|
||||
xpub: node.neutered().toBase58(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -96,6 +102,8 @@ Testcases['axic'] = {
|
||||
path: "m/44'/60'/0'/0/0",
|
||||
address: '0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9',
|
||||
privateKey: '0xb96e9ccb774cc33213cbcb2c69d3cdae17b0fe4888a1ccd343cbd1a17fd98b18',
|
||||
xpriv: "xprvA2xEQ2iTe9QB22rvf5cbfpUxEBmMdvc7stEFxLhiMXmdLrwLbqugPCHRZiRfEq2puC5vTgwyFneV38hppF8oTf9aoaUv7M8u2XvnACTe6r4",
|
||||
xpub: "xpub6FwaoYFMUWxUEWwPm79c2xRgnDbr3PKyF79rkj7KusJcDfGV9PDvvzbuQz32JYu3y2EpqY7xUag5Zw89YXokCKVtWLrfJ1RDUAYLLzTR8En"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,21 +9,76 @@ describe('Test HD Node Derivation', function(test) {
|
||||
|
||||
var tests = utils.loadTests('hdnode');
|
||||
tests.forEach(function(test) {
|
||||
it('Derives the HD nodes - ' + test.name, function() {
|
||||
it('Derives the HD nodes - ' + test.name, function() {
|
||||
this.timeout(10000);
|
||||
|
||||
var rootNode = new ethers.utils.HDNode.fromSeed(test.seed);
|
||||
test.hdnodes.forEach(function(nodeTest) {
|
||||
//var rootNode = new ethers.utils.HDNode.fromSeed(test.seed);
|
||||
var rootNode = new ethers.utils.HDNode.fromMnemonic(test.mnemonic, null, test.password || null);
|
||||
|
||||
test.hdnodes.forEach(function(nodeTest) {
|
||||
var node = rootNode.derivePath(nodeTest.path);
|
||||
assert.equal(node.privateKey, nodeTest.privateKey,
|
||||
'Generates privateKey - ' + nodeTest.privateKey);
|
||||
|
||||
assert.equal(node.extendedKey, nodeTest.xpriv,
|
||||
"Child Extended privateKey - " + nodeTest.privateKey);
|
||||
assert.equal(node.neuter().extendedKey, nodeTest.xpub,
|
||||
"Child Extended privateKey - " + nodeTest.privateKey);
|
||||
|
||||
var wallet = new ethers.Wallet(node.privateKey);
|
||||
assert.equal(wallet.address.toLowerCase(), nodeTest.address,
|
||||
'Generates address - ' + nodeTest.privateKey);
|
||||
|
||||
assert.equal(node.address, (new ethers.Wallet(node)).address, 'HDNode address matches - ' + nodeTest.privateKey);
|
||||
assert.equal(node.address, (new ethers.Wallet(node)).address,
|
||||
'HDNode address matches - ' + nodeTest.privateKey);
|
||||
|
||||
// Test public extended key derivation
|
||||
var lastHardened = nodeTest.path.match(/^(.*)'([^']*)$/);
|
||||
if (lastHardened && lastHardened[2].trim() !== "") {
|
||||
|
||||
// Derive as far as we can for hardened, then derive the remaining from neutered
|
||||
var hardNode = rootNode.derivePath(lastHardened[1] + "'");
|
||||
var neutered = hardNode.neuter();
|
||||
var nodeXpriv = ethers.utils.HDNode.fromExtendedKey(hardNode.extendedKey);
|
||||
nodeXpriv = nodeXpriv.derivePath(lastHardened[2].substring(1));
|
||||
var nodeXpub = ethers.utils.HDNode.fromExtendedKey(neutered.extendedKey);
|
||||
nodeXpub = nodeXpub.derivePath(lastHardened[2].substring(1));
|
||||
|
||||
assert.equal(neutered.privateKey, null,
|
||||
'Neutered HDNode privateKey null - ' + nodeTest.privateKey);
|
||||
assert.equal(neutered.xpriv, null,
|
||||
'Neutered HDNode xpriv null - ' + nodeTest.privateKey);
|
||||
|
||||
neutered = neutered.derivePath(lastHardened[2].substring(1));
|
||||
|
||||
assert.equal(neutered.address.toLowerCase(), nodeTest.address,
|
||||
'Derived Neutered HDNode address matches - ' + nodeTest.privateKey);
|
||||
|
||||
assert.equal(neutered.xpub, node.xpub,
|
||||
'Derived Neutered HDNode xpub matches - ' + nodeTest.privateKey);
|
||||
|
||||
assert.equal(neutered.privateKey, null,
|
||||
'Derived Neutered HDNode privateKey null - ' + nodeTest.privateKey);
|
||||
assert.equal(neutered.xpriv, null,
|
||||
'Neutered HDNode xpriv null - ' + nodeTest.privateKey);
|
||||
|
||||
// Test extended key derivation
|
||||
assert.equal(nodeXpub.xpriv, null,
|
||||
'Serialized Neutered HDNode xpriv null - ' + nodeTest.privateKey);
|
||||
assert.equal(nodeXpriv.extendedKey, node.extendedKey,
|
||||
'Serialized HDNode xpriv matches - ' + nodeTest.privateKey);
|
||||
assert.equal(nodeXpub.extendedKey, neutered.extendedKey,
|
||||
'Serialized Neutered HDNode xpub matches - ' + nodeTest.privateKey);
|
||||
}
|
||||
|
||||
// Test serialization
|
||||
var deserializedNode = ethers.utils.HDNode.fromExtendedKey(nodeTest.xpriv);
|
||||
|
||||
assert.equal(deserializedNode.extendedKey, nodeTest.xpriv,
|
||||
'Neutered HDNode xpriv null - ' + nodeTest.privateKey);
|
||||
assert.equal(deserializedNode.neuter().extendedKey, nodeTest.xpub,
|
||||
'Neutered HDNode xpriv null - ' + nodeTest.privateKey);
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -223,6 +223,39 @@ var blockchainData = {
|
||||
transactionIndex: 0x2
|
||||
},
|
||||
},
|
||||
goerli: {
|
||||
balance: {
|
||||
address: "0x06B5955A67D827CDF91823E3bB8F069e6c89c1D6",
|
||||
balance: bigNumberify("314159000000000000")
|
||||
},
|
||||
block3: {
|
||||
hash: '0xd5daa825732729bb0d2fd187a1b888e6bfc890f1fc5333984740d9052afb2920',
|
||||
parentHash: '0xe675f1362d82cdd1ec260b16fb046c17f61d8a84808150f5d715ccce775f575e',
|
||||
number: 3,
|
||||
timestamp: 1548947483,
|
||||
difficulty: 2,
|
||||
gasLimit: bigNumberify('10455073'),
|
||||
gasUsed: bigNumberify('0'),
|
||||
miner: '0x0000000000000000000000000000000000000000',
|
||||
extraData: '0x506172697479205465636820417574686f7269747900000000000000000000002822e1b202411c38084d96c84302b8361ec4840a51cd2fad9cb4bd9921cad7e64bc2e5dc7b41f3f75b33358be3aec718cf4d4317ace940e01b3581a95c9259ac01',
|
||||
transactions: []
|
||||
},
|
||||
transactionReceipt: {
|
||||
blockHash: '0x2384e8e8bdcf6eb87ec7c138fa503ac34adb32cac817e4b35f14d4339eaa1993',
|
||||
blockNumber: 47464,
|
||||
byzantium: true,
|
||||
contractAddress: null,
|
||||
cumulativeGasUsed: bigNumberify(21000),
|
||||
from: '0x8c1e1e5b47980D214965f3bd8ea34C413E120ae4',
|
||||
gasUsed: bigNumberify(21000),
|
||||
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
to: '0x58Bb4221245461E1d4cf886f18a01E3Df40Bd359',
|
||||
transactionHash: '0xec8b1ac5d787f36c738cc7793fec606283b41f1efa69df4ae6b2a014dcd12797',
|
||||
transactionIndex: 0,
|
||||
logs: [],
|
||||
status: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blockchainData['default'] = blockchainData.homestead;
|
||||
@@ -378,9 +411,15 @@ function testProvider(providerName, networkName) {
|
||||
});
|
||||
}
|
||||
|
||||
['default', 'homestead', 'ropsten', 'rinkeby', 'kovan'].forEach(function(networkName) {
|
||||
['default', 'homestead', 'ropsten', 'rinkeby', 'kovan', 'goerli'].forEach(function(networkName) {
|
||||
['getDefaultProvider', 'InfuraProvider', 'EtherscanProvider', 'Web3Provider'].forEach(function(providerName) {
|
||||
|
||||
if (networkName === "goerli") {
|
||||
if (providerName === "InfuraProvider" || providerName === "Web3Provider") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO: Remove this! Temporary because Etherscan is down
|
||||
//if (providerName === 'EtherscanProvider') {
|
||||
// console.log("******** Remove this soon! Etherscan is having issues.");
|
||||
|
||||
@@ -348,3 +348,20 @@ describe('Test BigNumber', function() {
|
||||
].forEach(testAbs);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Hexlify", function() {
|
||||
it("hexlify on string of unsafe number", function() {
|
||||
assert(ethers.utils.hexlify(ethers.utils.bigNumberify("9985956830000000000")), "0x8a953ed43a892c00", "hexlify on large BigNumber");
|
||||
});
|
||||
|
||||
[9007199254740991, 9985956830000000000].forEach(function(value) {
|
||||
it('hexlify fails on unsafe number - ' + value, function() {
|
||||
assert.throws(function() {
|
||||
var result = ethers.utils.hexlify(value);
|
||||
console.log('Result', result);
|
||||
}, function(error) {
|
||||
return (error.code === "NUMERIC_FAULT" && error.fault === "out-of-safe-range");
|
||||
}, "hexlify throws on out-of-range value - " + value);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Binary file not shown.
8
thirdparty.d.ts
vendored
8
thirdparty.d.ts
vendored
@@ -65,6 +65,11 @@ declare module "elliptic" {
|
||||
recoveryParam: number
|
||||
}
|
||||
|
||||
interface Point {
|
||||
add(point: Point): Point;
|
||||
encodeCompressed(enc: string): string
|
||||
}
|
||||
|
||||
interface KeyPair {
|
||||
sign(message: Uint8Array, options: { canonical?: boolean }): Signature;
|
||||
getPublic(compressed: boolean, encoding?: string): string;
|
||||
@@ -72,6 +77,7 @@ declare module "elliptic" {
|
||||
getPrivate(encoding?: string): string;
|
||||
encode(encoding: string, compressed: boolean): string;
|
||||
derive(publicKey: BN): BN;
|
||||
pub: Point;
|
||||
priv: BN;
|
||||
}
|
||||
|
||||
@@ -83,6 +89,8 @@ declare module "elliptic" {
|
||||
keyFromPublic(publicKey: string | Uint8Array): KeyPair;
|
||||
keyFromPrivate(privateKey: string | Uint8Array): KeyPair;
|
||||
recoverPubKey(data: Uint8Array, signature: BasicSignature, recoveryParam: number): KeyPair;
|
||||
|
||||
// curve: Curve;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
52
utils/basex.d.ts
vendored
Normal file
52
utils/basex.d.ts
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* var basex = require('base-x');
|
||||
*
|
||||
* This implementation is heavily based on base-x. The main reason to
|
||||
* deviate was to prevent the dependency of Buffer.
|
||||
*
|
||||
* Contributors:
|
||||
*
|
||||
* base-x encoding
|
||||
* Forked from https://github.com/cryptocoinjs/bs58
|
||||
* Originally written by Mike Hearn for BitcoinJ
|
||||
* Copyright (c) 2011 Google Inc
|
||||
* Ported to JavaScript by Stefan Thomas
|
||||
* Merged Buffer refactorings from base58-native by Stephen Pair
|
||||
* Copyright (c) 2013 BitPay Inc
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright base-x contributors (c) 2016
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
import { Arrayish } from "./bytes";
|
||||
export declare class BaseX {
|
||||
readonly alphabet: string;
|
||||
readonly base: number;
|
||||
private _alphabetMap;
|
||||
private _leader;
|
||||
constructor(alphabet: string);
|
||||
encode(value: Arrayish | string): string;
|
||||
decode(value: string): Uint8Array;
|
||||
}
|
||||
declare const Base32: BaseX;
|
||||
declare const Base58: BaseX;
|
||||
export { Base32, Base58 };
|
||||
123
utils/basex.js
Normal file
123
utils/basex.js
Normal file
@@ -0,0 +1,123 @@
|
||||
"use strict";
|
||||
/**
|
||||
* var basex = require('base-x');
|
||||
*
|
||||
* This implementation is heavily based on base-x. The main reason to
|
||||
* deviate was to prevent the dependency of Buffer.
|
||||
*
|
||||
* Contributors:
|
||||
*
|
||||
* base-x encoding
|
||||
* Forked from https://github.com/cryptocoinjs/bs58
|
||||
* Originally written by Mike Hearn for BitcoinJ
|
||||
* Copyright (c) 2011 Google Inc
|
||||
* Ported to JavaScript by Stefan Thomas
|
||||
* Merged Buffer refactorings from base58-native by Stephen Pair
|
||||
* Copyright (c) 2013 BitPay Inc
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright base-x contributors (c) 2016
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var bytes_1 = require("./bytes");
|
||||
var properties_1 = require("./properties");
|
||||
var BaseX = /** @class */ (function () {
|
||||
function BaseX(alphabet) {
|
||||
properties_1.defineReadOnly(this, "alphabet", alphabet);
|
||||
properties_1.defineReadOnly(this, "base", alphabet.length);
|
||||
properties_1.defineReadOnly(this, "_alphabetMap", {});
|
||||
properties_1.defineReadOnly(this, "_leader", alphabet.charAt(0));
|
||||
// pre-compute lookup table
|
||||
for (var i = 0; i < alphabet.length; i++) {
|
||||
this._alphabetMap[alphabet.charAt(i)] = i;
|
||||
}
|
||||
}
|
||||
BaseX.prototype.encode = function (value) {
|
||||
var source = bytes_1.arrayify(value);
|
||||
if (source.length === 0) {
|
||||
return '';
|
||||
}
|
||||
var digits = [0];
|
||||
for (var i = 0; i < source.length; ++i) {
|
||||
var carry = source[i];
|
||||
for (var j = 0; j < digits.length; ++j) {
|
||||
carry += digits[j] << 8;
|
||||
digits[j] = carry % this.base;
|
||||
carry = (carry / this.base) | 0;
|
||||
}
|
||||
while (carry > 0) {
|
||||
digits.push(carry % this.base);
|
||||
carry = (carry / this.base) | 0;
|
||||
}
|
||||
}
|
||||
var string = '';
|
||||
// deal with leading zeros
|
||||
for (var k = 0; source[k] === 0 && k < source.length - 1; ++k) {
|
||||
string += this._leader;
|
||||
}
|
||||
// convert digits to a string
|
||||
for (var q = digits.length - 1; q >= 0; --q) {
|
||||
string += this.alphabet[digits[q]];
|
||||
}
|
||||
return string;
|
||||
};
|
||||
BaseX.prototype.decode = function (value) {
|
||||
if (typeof (value) !== 'string') {
|
||||
throw new TypeError('Expected String');
|
||||
}
|
||||
var bytes = [];
|
||||
if (value.length === 0) {
|
||||
return new Uint8Array(bytes);
|
||||
}
|
||||
bytes.push(0);
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
var byte = this._alphabetMap[value[i]];
|
||||
if (byte === undefined) {
|
||||
throw new Error('Non-base' + this.base + ' character');
|
||||
}
|
||||
var carry = byte;
|
||||
for (var j = 0; j < bytes.length; ++j) {
|
||||
carry += bytes[j] * this.base;
|
||||
bytes[j] = carry & 0xff;
|
||||
carry >>= 8;
|
||||
}
|
||||
while (carry > 0) {
|
||||
bytes.push(carry & 0xff);
|
||||
carry >>= 8;
|
||||
}
|
||||
}
|
||||
// deal with leading zeros
|
||||
for (var k = 0; value[k] === this._leader && k < value.length - 1; ++k) {
|
||||
bytes.push(0);
|
||||
}
|
||||
return bytes_1.arrayify(new Uint8Array(bytes.reverse()));
|
||||
};
|
||||
return BaseX;
|
||||
}());
|
||||
exports.BaseX = BaseX;
|
||||
var Base32 = new BaseX("abcdefghijklmnopqrstuvwxyz234567");
|
||||
exports.Base32 = Base32;
|
||||
var Base58 = new BaseX("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
|
||||
exports.Base58 = Base58;
|
||||
//console.log(Base58.decode("Qmd2V777o5XvJbYMeMb8k2nU5f8d3ciUQ5YpYuWhzv8iDj"))
|
||||
//console.log(Base58.encode(Base58.decode("Qmd2V777o5XvJbYMeMb8k2nU5f8d3ciUQ5YpYuWhzv8iDj")))
|
||||
@@ -23,7 +23,7 @@ function addSlice(array) {
|
||||
}
|
||||
array.slice = function () {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
return new Uint8Array(Array.prototype.slice.apply(array, args));
|
||||
return addSlice(new Uint8Array(Array.prototype.slice.apply(array, args)));
|
||||
};
|
||||
return array;
|
||||
}
|
||||
@@ -135,6 +135,14 @@ function hexlify(value) {
|
||||
if (value < 0) {
|
||||
errors.throwError('cannot hexlify negative value', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
||||
}
|
||||
// @TODO: Roll this into the above error as a numeric fault (overflow); next version, not backward compatible
|
||||
// We can about (value == MAX_INT) to as well, since that may indicate we underflowed already
|
||||
if (value >= 9007199254740991) {
|
||||
errors.throwError("out-of-range", errors.NUMERIC_FAULT, {
|
||||
operartion: "hexlify",
|
||||
fault: "out-of-safe-range"
|
||||
});
|
||||
}
|
||||
var hex = '';
|
||||
while (value) {
|
||||
hex = HexCharacters[value & 0x0f] + hex;
|
||||
|
||||
10
utils/hdnode.d.ts
vendored
10
utils/hdnode.d.ts
vendored
@@ -2,9 +2,10 @@ import { Arrayish } from './bytes';
|
||||
import { Wordlist } from './wordlist';
|
||||
export declare const defaultPath = "m/44'/60'/0'/0/0";
|
||||
export declare class HDNode {
|
||||
private readonly keyPair;
|
||||
readonly privateKey: string;
|
||||
readonly publicKey: string;
|
||||
readonly fingerprint: string;
|
||||
readonly parentFingerprint: string;
|
||||
readonly address: string;
|
||||
readonly mnemonic: string;
|
||||
readonly path: string;
|
||||
@@ -18,12 +19,15 @@ export declare class HDNode {
|
||||
* - fromMnemonic
|
||||
* - fromSeed
|
||||
*/
|
||||
constructor(constructorGuard: any, privateKey: Arrayish, chainCode: Uint8Array, index: number, depth: number, mnemonic: string, path: string);
|
||||
constructor(constructorGuard: any, privateKey: string, publicKey: string, parentFingerprint: string, chainCode: string, index: number, depth: number, mnemonic: string, path: string);
|
||||
readonly extendedKey: string;
|
||||
neuter(): HDNode;
|
||||
private _derive;
|
||||
derivePath(path: string): HDNode;
|
||||
static isHDNode(value: any): value is HDNode;
|
||||
}
|
||||
export declare function fromMnemonic(mnemonic: string, wordlist?: Wordlist): HDNode;
|
||||
export declare function fromExtendedKey(extendedKey: string): HDNode;
|
||||
export declare function fromMnemonic(mnemonic: string, wordlist?: Wordlist, password?: string): HDNode;
|
||||
export declare function fromSeed(seed: Arrayish): HDNode;
|
||||
export declare function mnemonicToSeed(mnemonic: string, password?: string): string;
|
||||
export declare function mnemonicToEntropy(mnemonic: string, wordlist?: Wordlist): string;
|
||||
|
||||
125
utils/hdnode.js
125
utils/hdnode.js
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
@@ -16,6 +16,7 @@ var lang_en_1 = require("../wordlists/lang-en");
|
||||
// Automatically register English?
|
||||
//import { register } from '../wordlists/wordlist';
|
||||
//register(langEn);
|
||||
var basex_1 = require("./basex");
|
||||
var bytes_1 = require("./bytes");
|
||||
var bignumber_1 = require("./bignumber");
|
||||
var utf8_1 = require("./utf8");
|
||||
@@ -36,6 +37,13 @@ function getUpperMask(bits) {
|
||||
function getLowerMask(bits) {
|
||||
return (1 << bits) - 1;
|
||||
}
|
||||
function bytes32(value) {
|
||||
return bytes_1.hexZeroPad(bytes_1.hexlify(value), 32);
|
||||
}
|
||||
function base58check(data) {
|
||||
var checksum = bytes_1.hexDataSlice(sha2_1.sha256(sha2_1.sha256(data)), 0, 4);
|
||||
return basex_1.Base58.encode(bytes_1.concat([data, checksum]));
|
||||
}
|
||||
var _constructorGuard = {};
|
||||
exports.defaultPath = "m/44'/60'/0'/0/0";
|
||||
var HDNode = /** @class */ (function () {
|
||||
@@ -46,38 +54,69 @@ var HDNode = /** @class */ (function () {
|
||||
* - fromMnemonic
|
||||
* - fromSeed
|
||||
*/
|
||||
function HDNode(constructorGuard, privateKey, chainCode, index, depth, mnemonic, path) {
|
||||
function HDNode(constructorGuard, privateKey, publicKey, parentFingerprint, chainCode, index, depth, mnemonic, path) {
|
||||
errors.checkNew(this, HDNode);
|
||||
if (constructorGuard !== _constructorGuard) {
|
||||
throw new Error('HDNode constructor cannot be called directly');
|
||||
}
|
||||
properties_1.defineReadOnly(this, 'keyPair', new secp256k1_1.KeyPair(privateKey));
|
||||
properties_1.defineReadOnly(this, 'privateKey', this.keyPair.privateKey);
|
||||
properties_1.defineReadOnly(this, 'publicKey', this.keyPair.compressedPublicKey);
|
||||
if (privateKey) {
|
||||
var keyPair = new secp256k1_1.KeyPair(privateKey);
|
||||
properties_1.defineReadOnly(this, 'privateKey', keyPair.privateKey);
|
||||
properties_1.defineReadOnly(this, 'publicKey', keyPair.compressedPublicKey);
|
||||
}
|
||||
else {
|
||||
properties_1.defineReadOnly(this, 'privateKey', null);
|
||||
properties_1.defineReadOnly(this, 'publicKey', bytes_1.hexlify(publicKey));
|
||||
}
|
||||
properties_1.defineReadOnly(this, 'parentFingerprint', parentFingerprint);
|
||||
properties_1.defineReadOnly(this, 'fingerprint', bytes_1.hexDataSlice(sha2_1.ripemd160(sha2_1.sha256(this.publicKey)), 0, 4));
|
||||
properties_1.defineReadOnly(this, 'address', secp256k1_1.computeAddress(this.publicKey));
|
||||
properties_1.defineReadOnly(this, 'chainCode', bytes_1.hexlify(chainCode));
|
||||
properties_1.defineReadOnly(this, 'chainCode', chainCode);
|
||||
properties_1.defineReadOnly(this, 'index', index);
|
||||
properties_1.defineReadOnly(this, 'depth', depth);
|
||||
properties_1.defineReadOnly(this, 'mnemonic', mnemonic);
|
||||
properties_1.defineReadOnly(this, 'path', path);
|
||||
properties_1.setType(this, 'HDNode');
|
||||
}
|
||||
HDNode.prototype._derive = function (index) {
|
||||
// Public parent key -> public child key
|
||||
if (!this.privateKey) {
|
||||
if (index >= HardenedBit) {
|
||||
throw new Error('cannot derive child of neutered node');
|
||||
Object.defineProperty(HDNode.prototype, "extendedKey", {
|
||||
get: function () {
|
||||
// We only support the mainnet values for now, but if anyone needs
|
||||
// testnet values, let me know. I believe current senitment is that
|
||||
// we should always use mainnet, and use BIP-44 to derive the network
|
||||
// - Mainnet: public=0x0488B21E, private=0x0488ADE4
|
||||
// - Testnet: public=0x043587CF, private=0x04358394
|
||||
if (this.depth >= 256) {
|
||||
throw new Error("Depth too large!");
|
||||
}
|
||||
throw new Error('not implemented');
|
||||
return base58check(bytes_1.concat([
|
||||
((this.privateKey != null) ? "0x0488ADE4" : "0x0488B21E"),
|
||||
bytes_1.hexlify(this.depth),
|
||||
this.parentFingerprint,
|
||||
bytes_1.hexZeroPad(bytes_1.hexlify(this.index), 4),
|
||||
this.chainCode,
|
||||
((this.privateKey != null) ? bytes_1.concat(["0x00", this.privateKey]) : this.publicKey),
|
||||
]));
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
HDNode.prototype.neuter = function () {
|
||||
return new HDNode(_constructorGuard, null, this.publicKey, this.parentFingerprint, this.chainCode, this.index, this.depth, null, this.path);
|
||||
};
|
||||
HDNode.prototype._derive = function (index) {
|
||||
if (index > 0xffffffff) {
|
||||
throw new Error("invalid index - " + String(index));
|
||||
}
|
||||
var data = new Uint8Array(37);
|
||||
// Base path
|
||||
var mnemonic = this.mnemonic;
|
||||
var path = this.path;
|
||||
if (path) {
|
||||
path += '/' + (index & ~HardenedBit);
|
||||
}
|
||||
var data = new Uint8Array(37);
|
||||
if (index & HardenedBit) {
|
||||
if (!this.privateKey) {
|
||||
throw new Error('cannot derive child of neutered node');
|
||||
}
|
||||
// Data = 0x00 || ser_256(k_par)
|
||||
data.set(bytes_1.arrayify(this.privateKey), 1);
|
||||
// Hardened path
|
||||
@@ -87,22 +126,32 @@ var HDNode = /** @class */ (function () {
|
||||
}
|
||||
else {
|
||||
// Data = ser_p(point(k_par))
|
||||
data.set(this.keyPair.publicKeyBytes);
|
||||
data.set(bytes_1.arrayify(this.publicKey));
|
||||
}
|
||||
// Data += ser_32(i)
|
||||
for (var i = 24; i >= 0; i -= 8) {
|
||||
data[33 + (i >> 3)] = ((index >> (24 - i)) & 0xff);
|
||||
}
|
||||
var I = hmac_1.computeHmac(hmac_1.SupportedAlgorithms.sha512, this.chainCode, data);
|
||||
var IL = bignumber_1.bigNumberify(I.slice(0, 32));
|
||||
var IL = I.slice(0, 32);
|
||||
var IR = I.slice(32);
|
||||
var ki = IL.add(this.keyPair.privateKey).mod(N);
|
||||
return new HDNode(_constructorGuard, bytes_1.arrayify(ki), IR, index, this.depth + 1, mnemonic, path);
|
||||
// The private key
|
||||
var ki = null;
|
||||
// The public key
|
||||
var Ki = null;
|
||||
if (this.privateKey) {
|
||||
ki = bytes32(bignumber_1.bigNumberify(IL).add(this.privateKey).mod(N));
|
||||
}
|
||||
else {
|
||||
var ek = new secp256k1_1.KeyPair(bytes_1.hexlify(IL));
|
||||
Ki = ek._addPoint(this.publicKey);
|
||||
}
|
||||
return new HDNode(_constructorGuard, ki, Ki, this.fingerprint, bytes32(IR), index, this.depth + 1, this.mnemonic, path);
|
||||
};
|
||||
HDNode.prototype.derivePath = function (path) {
|
||||
var components = path.split('/');
|
||||
if (components.length === 0 || (components[0] === 'm' && this.depth !== 0)) {
|
||||
throw new Error('invalid path');
|
||||
throw new Error('invalid path - ' + path);
|
||||
}
|
||||
if (components[0] === 'm') {
|
||||
components.shift();
|
||||
@@ -136,18 +185,50 @@ var HDNode = /** @class */ (function () {
|
||||
return HDNode;
|
||||
}());
|
||||
exports.HDNode = HDNode;
|
||||
function fromExtendedKey(extendedKey) {
|
||||
var bytes = basex_1.Base58.decode(extendedKey);
|
||||
if (bytes.length !== 82 || base58check(bytes.slice(0, 78)) !== extendedKey) {
|
||||
errors.throwError("invalid extended key", errors.INVALID_ARGUMENT, {
|
||||
argument: "extendedKey",
|
||||
value: "[REDACTED]"
|
||||
});
|
||||
}
|
||||
var depth = bytes[4];
|
||||
var parentFingerprint = bytes_1.hexlify(bytes.slice(5, 9));
|
||||
var index = parseInt(bytes_1.hexlify(bytes.slice(9, 13)).substring(2), 16);
|
||||
var chainCode = bytes_1.hexlify(bytes.slice(13, 45));
|
||||
var key = bytes.slice(45, 78);
|
||||
switch (bytes_1.hexlify(bytes.slice(0, 4))) {
|
||||
// Public Key
|
||||
case "0x0488b21e":
|
||||
case "0x043587cf":
|
||||
return new HDNode(_constructorGuard, null, bytes_1.hexlify(key), parentFingerprint, chainCode, index, depth, null, null);
|
||||
// Private Key
|
||||
case "0x0488ade4":
|
||||
case "0x04358394 ":
|
||||
if (key[0] !== 0) {
|
||||
break;
|
||||
}
|
||||
return new HDNode(_constructorGuard, bytes_1.hexlify(key.slice(1)), null, parentFingerprint, chainCode, index, depth, null, null);
|
||||
}
|
||||
return errors.throwError("invalid extended key", errors.INVALID_ARGUMENT, {
|
||||
argument: "extendedKey",
|
||||
value: "[REDACTED]"
|
||||
});
|
||||
}
|
||||
exports.fromExtendedKey = fromExtendedKey;
|
||||
function _fromSeed(seed, mnemonic) {
|
||||
var seedArray = bytes_1.arrayify(seed);
|
||||
if (seedArray.length < 16 || seedArray.length > 64) {
|
||||
throw new Error('invalid seed');
|
||||
}
|
||||
var I = bytes_1.arrayify(hmac_1.computeHmac(hmac_1.SupportedAlgorithms.sha512, MasterSecret, seedArray));
|
||||
return new HDNode(_constructorGuard, I.slice(0, 32), I.slice(32), 0, 0, mnemonic, 'm');
|
||||
return new HDNode(_constructorGuard, bytes32(I.slice(0, 32)), null, "0x00000000", bytes32(I.slice(32)), 0, 0, mnemonic, 'm');
|
||||
}
|
||||
function fromMnemonic(mnemonic, wordlist) {
|
||||
function fromMnemonic(mnemonic, wordlist, password) {
|
||||
// Check that the checksum s valid (will throw an error)
|
||||
mnemonicToEntropy(mnemonic, wordlist);
|
||||
return _fromSeed(mnemonicToSeed(mnemonic), mnemonic);
|
||||
return _fromSeed(mnemonicToSeed(mnemonic, password), mnemonic);
|
||||
}
|
||||
exports.fromMnemonic = fromMnemonic;
|
||||
function fromSeed(seed) {
|
||||
|
||||
@@ -66,6 +66,17 @@ var networks = {
|
||||
name: 'rinkeby',
|
||||
_defaultProvider: ethDefaultProvider('rinkeby')
|
||||
},
|
||||
goerli: {
|
||||
chainId: 5,
|
||||
ensAddress: "0x112234455c3a32fd11230c42e7bccd4a84e02010",
|
||||
name: "goerli",
|
||||
_defaultProvider: function (providers) {
|
||||
if (providers.EtherscanProvider) {
|
||||
return new providers.EtherscanProvider("goerli");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
kovan: {
|
||||
chainId: 42,
|
||||
name: 'kovan',
|
||||
|
||||
1
utils/secp256k1.d.ts
vendored
1
utils/secp256k1.d.ts
vendored
@@ -7,6 +7,7 @@ export declare class KeyPair {
|
||||
constructor(privateKey: Arrayish | string);
|
||||
sign(digest: Arrayish | string): Signature;
|
||||
computeSharedSecret(otherKey: Arrayish | string): string;
|
||||
_addPoint(other: Arrayish | string): string;
|
||||
}
|
||||
export declare function computePublicKey(key: Arrayish | string, compressed?: boolean): string;
|
||||
export declare function computeAddress(key: Arrayish | string): string;
|
||||
|
||||
@@ -45,6 +45,11 @@ var KeyPair = /** @class */ (function () {
|
||||
var otherKeyPair = getCurve().keyFromPublic(bytes_1.arrayify(computePublicKey(otherKey)));
|
||||
return bytes_1.hexZeroPad('0x' + keyPair.derive(otherKeyPair.getPublic()).toString(16), 32);
|
||||
};
|
||||
KeyPair.prototype._addPoint = function (other) {
|
||||
var p0 = getCurve().keyFromPublic(bytes_1.arrayify(this.publicKey));
|
||||
var p1 = getCurve().keyFromPublic(bytes_1.arrayify(other));
|
||||
return "0x" + p0.pub.add(p1.pub).encodeCompressed("hex");
|
||||
};
|
||||
return KeyPair;
|
||||
}());
|
||||
exports.KeyPair = KeyPair;
|
||||
|
||||
1
utils/sha2.d.ts
vendored
1
utils/sha2.d.ts
vendored
@@ -1,3 +1,4 @@
|
||||
import { Arrayish } from './bytes';
|
||||
export declare function ripemd160(data: Arrayish): string;
|
||||
export declare function sha256(data: Arrayish): string;
|
||||
export declare function sha512(data: Arrayish): string;
|
||||
|
||||
@@ -5,6 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var hash_js_1 = __importDefault(require("hash.js"));
|
||||
var bytes_1 = require("./bytes");
|
||||
function ripemd160(data) {
|
||||
return '0x' + (hash_js_1.default.ripemd160().update(bytes_1.arrayify(data)).digest('hex'));
|
||||
}
|
||||
exports.ripemd160 = ripemd160;
|
||||
function sha256(data) {
|
||||
return '0x' + (hash_js_1.default.sha256().update(bytes_1.arrayify(data)).digest('hex'));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user