@harmony-js/account
Version:
account and wallet for harmony
584 lines • 24 kB
JavaScript
"use strict";
/**
* @packageDocumentation
* @module harmony-account
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Account = void 0;
var tslib_1 = require("tslib");
var crypto_1 = require("@harmony-js/crypto");
var utils_1 = require("@harmony-js/utils");
var transaction_1 = require("@harmony-js/transaction");
var network_1 = require("@harmony-js/network");
var utils_2 = require("./utils");
var Account = /** @class */ (function () {
/**
* Generate an account object
*
* @param key import an existing privateKey, or create a random one
* @param messenger you can setMessage later, or set message on `new`
*
* @example
* ```javascript
* // import the Account class
* const { Account } = require('@harmony-js/account');
*
* // Messenger is optional, by default, we have a defaultMessenger
* // If you like to change, you will import related package here.
* const { HttpProvider, Messenger } = require('@harmony-js/network');
* const { ChainType, ChainID } = require('@harmony-js/utils');
*
* // create a custom messenger
* const customMessenger = new Messenger(
* new HttpProvider('http://localhost:9500'),
* ChainType.Harmony, // if you are connected to Harmony's blockchain
* ChainID.HmyLocal, // check if the chainId is correct
* )
*
* // setMessenger later
* const randomAccount = new Account()
* randomAccount.setMessenger(customMessenger)
*
* // or you can set messenger on `new`
* const randomAccountWithCustomMessenger = new Account(undefined, customMessenger)
*
* // NOTED: Key with or without `0x` are accepted, makes no different
* // NOTED: DO NOT import `mnemonic phrase` using `Account` class, use `Wallet` instead
* const myPrivateKey = '0xe19d05c5452598e24caad4a0d85a49146f7be089515c905ae6a19e8a578a6930'
* const myAccountWithMyPrivateKey = new Account(myPrivateKey)
* ```
*/
function Account(key, messenger) {
if (messenger === void 0) { messenger = utils_2.defaultMessenger; }
/**@hidden */
this.balance = '0';
/**@hidden */
this.nonce = 0;
/**@hidden */
this.encrypted = false;
this.messenger = messenger;
if (!key) {
this._new();
}
else {
this._import(key);
}
this.shardID = this.messenger.currentShard || 0;
this.shards = new Map();
this.shards.set(this.shardID, {
address: "" + this.bech32Address + utils_1.AddressSuffix + "0",
balance: this.balance || '0',
nonce: this.nonce || 0,
});
}
/**
* static method create account
*
* @example
* ```javascript
* const account = new Account();
* console.log(account);
* ```
*/
Account.new = function () {
var newAcc = new Account()._new();
return newAcc;
};
/**
* Static Method: add a private key to Account
* @param {string} key - private Key
*
* @example
* ```javascript
* const account = new Account.add(key_1);
* console.log(account);
* ```
*/
Account.add = function (key) {
var newAcc = new Account()._import(key);
return newAcc;
};
Object.defineProperty(Account.prototype, "checksumAddress", {
/**
* check sum address
*
* @example
* ```javascript
* console.log(account.checksumAddress);
* ```
*/
get: function () {
return this.address ? crypto_1.getAddress(this.address).checksum : '';
},
enumerable: false,
configurable: true
});
Object.defineProperty(Account.prototype, "bech32Address", {
/**
* Get bech32 Address
*
* @example
* ```javascript
* console.log(account.bech32Address);
* ```
*/
get: function () {
return this.address ? crypto_1.getAddress(this.address).bech32 : '';
},
enumerable: false,
configurable: true
});
Object.defineProperty(Account.prototype, "bech32TestNetAddress", {
/**
* get Bech32 TestNet Address
*
* @example
* ```javascript
* console.log(account.bech32TestNetAddress);
* ```
*/
get: function () {
return this.address ? crypto_1.getAddress(this.address).bech32TestNet : '';
},
enumerable: false,
configurable: true
});
Object.defineProperty(Account.prototype, "getShardsCount", {
/**
* get Shards number with this Account
*
* @example
* ```javascript
* console.log(account.getShardsCount);
* ```
*/
get: function () {
return this.shards.size;
},
enumerable: false,
configurable: true
});
Account.prototype.toFile = function (password, options) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var file;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(this.privateKey && utils_1.isPrivateKey(this.privateKey))) return [3 /*break*/, 2];
return [4 /*yield*/, crypto_1.encrypt(this.privateKey, password, options)];
case 1:
file = _a.sent();
this.privateKey = file;
this.encrypted = true;
return [2 /*return*/, file];
case 2: throw new Error('Encryption failed because PrivateKey is not correct');
}
});
});
};
Account.prototype.fromFile = function (keyStore, password) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var file, decyptedPrivateKey, error_1;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
if (typeof password !== 'string') {
throw new Error('you must provide password');
}
file = JSON.parse(keyStore.toLowerCase());
return [4 /*yield*/, crypto_1.decrypt(file, password)];
case 1:
decyptedPrivateKey = _a.sent();
if (utils_1.isPrivateKey(decyptedPrivateKey)) {
return [2 /*return*/, this._import(decyptedPrivateKey)];
}
else {
throw new Error('decrypted failed');
}
return [3 /*break*/, 3];
case 2:
error_1 = _a.sent();
throw error_1;
case 3: return [2 /*return*/];
}
});
});
};
/**
* Get the account balance
*
* @param blockNumber by default, it's `latest`
*
* @example
* ```javascript
* account.getBalance().then((value) => {
* console.log(value);
* });
* ```
*/
Account.prototype.getBalance = function (blockNumber) {
if (blockNumber === void 0) { blockNumber = 'latest'; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var balance, nonce, error_2;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 5, , 6]);
if (!this.messenger) return [3 /*break*/, 3];
return [4 /*yield*/, this.messenger.send(network_1.RPCMethod.GetBalance, [this.address, blockNumber], this.messenger.chainPrefix, this.messenger.currentShard || 0)];
case 1:
balance = _a.sent();
return [4 /*yield*/, this.messenger.send(network_1.RPCMethod.GetTransactionCount, [this.address, blockNumber], this.messenger.chainPrefix, this.messenger.currentShard || 0)];
case 2:
nonce = _a.sent();
if (balance.isError()) {
throw balance.error.message;
}
if (nonce.isError()) {
throw nonce.error.message;
}
this.balance = utils_1.hexToNumber(balance.result);
this.nonce = Number.parseInt(utils_1.hexToNumber(nonce.result), 10);
this.shardID = this.messenger.currentShard || 0;
return [3 /*break*/, 4];
case 3: throw new Error('No Messenger found');
case 4: return [2 /*return*/, {
balance: this.balance,
nonce: this.nonce,
shardID: this.shardID,
}];
case 5:
error_2 = _a.sent();
throw error_2;
case 6: return [2 /*return*/];
}
});
});
};
/**
* @function updateShards
*/
Account.prototype.updateBalances = function (blockNumber) {
if (blockNumber === void 0) { blockNumber = 'latest'; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var shardProviders, shardProviders_1, shardProviders_1_1, _a, name_1, val, balanceObject, e_1_1, currentShard;
var e_1, _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
shardProviders = this.messenger.shardProviders;
if (!(shardProviders.size > 1)) return [3 /*break*/, 10];
_c.label = 1;
case 1:
_c.trys.push([1, 7, 8, 9]);
shardProviders_1 = tslib_1.__values(shardProviders), shardProviders_1_1 = shardProviders_1.next();
_c.label = 2;
case 2:
if (!!shardProviders_1_1.done) return [3 /*break*/, 6];
_a = tslib_1.__read(shardProviders_1_1.value, 2), name_1 = _a[0], val = _a[1];
return [4 /*yield*/, this.getShardBalance(val.shardID, blockNumber)];
case 3:
balanceObject = _c.sent();
return [4 /*yield*/, this.shards.set(name_1 === val.shardID ? name_1 : val.shardID, balanceObject)];
case 4:
_c.sent();
_c.label = 5;
case 5:
shardProviders_1_1 = shardProviders_1.next();
return [3 /*break*/, 2];
case 6: return [3 /*break*/, 9];
case 7:
e_1_1 = _c.sent();
e_1 = { error: e_1_1 };
return [3 /*break*/, 9];
case 8:
try {
if (shardProviders_1_1 && !shardProviders_1_1.done && (_b = shardProviders_1.return)) _b.call(shardProviders_1);
}
finally { if (e_1) throw e_1.error; }
return [7 /*endfinally*/];
case 9: return [3 /*break*/, 12];
case 10: return [4 /*yield*/, this.getShardBalance(this.messenger.currentShard || 0, blockNumber)];
case 11:
currentShard = _c.sent();
this.shards.set(this.messenger.currentShard || 0, currentShard);
_c.label = 12;
case 12: return [2 /*return*/];
}
});
});
};
/**
* @function signTransaction
*/
Account.prototype.signTransaction = function (transaction, updateNonce, encodeMode, blockNumber) {
if (updateNonce === void 0) { updateNonce = true; }
if (encodeMode === void 0) { encodeMode = 'rlp'; }
if (blockNumber === void 0) { blockNumber = 'latest'; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var txShardID, shardNonce, _a, signature_1, rawTransaction_1;
var _this = this;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!this.privateKey || !utils_1.isPrivateKey(this.privateKey)) {
throw new Error(this.privateKey + " is not found or not correct");
}
if (!updateNonce) return [3 /*break*/, 2];
txShardID = transaction.txParams.shardID;
return [4 /*yield*/, this.getShardNonce(typeof txShardID === 'string' ? Number.parseInt(txShardID, 10) : txShardID, blockNumber)];
case 1:
shardNonce = _b.sent();
transaction.setParams(tslib_1.__assign(tslib_1.__assign({}, transaction.txParams), { from: this.messenger.chainPrefix === utils_1.ChainType.Harmony
? this.bech32Address
: this.checksumAddress || '0x', nonce: shardNonce }));
_b.label = 2;
case 2:
if (encodeMode === 'rlp') {
_a = tslib_1.__read(transaction_1.RLPSign(transaction, this.privateKey), 2), signature_1 = _a[0], rawTransaction_1 = _a[1];
return [2 /*return*/, transaction.map(function (obj) {
return tslib_1.__assign(tslib_1.__assign({}, obj), { signature: signature_1,
rawTransaction: rawTransaction_1, from: _this.messenger.chainPrefix === utils_1.ChainType.Harmony
? _this.bech32Address
: _this.checksumAddress || '0x' });
})];
}
else {
// TODO: if we use other encode method, eg. protobuf, we should implement this
return [2 /*return*/, transaction];
}
return [2 /*return*/];
}
});
});
};
/**
* This function is still in development, coming soon!
*
* @param staking
* @param updateNonce
* @param encodeMode
* @param blockNumber
* @param shardID
*/
Account.prototype.signStaking = function (staking, updateNonce, encodeMode, blockNumber, shardID) {
if (updateNonce === void 0) { updateNonce = true; }
if (encodeMode === void 0) { encodeMode = 'rlp'; }
if (blockNumber === void 0) { blockNumber = 'latest'; }
if (shardID === void 0) { shardID = this.messenger.currentShard; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var txShardID, shardNonce, _a, signature, rawTransaction;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!this.privateKey || !utils_1.isPrivateKey(this.privateKey)) {
throw new Error(this.privateKey + " is not found or not correct");
}
if (!updateNonce) return [3 /*break*/, 2];
txShardID = shardID;
return [4 /*yield*/, this.getShardNonce(typeof txShardID === 'string' ? Number.parseInt(txShardID, 10) : txShardID, blockNumber)];
case 1:
shardNonce = _b.sent();
staking.setFromAddress(this.messenger.chainPrefix === utils_1.ChainType.Harmony
? this.bech32Address
: this.checksumAddress || '0x');
staking.setNonce(shardNonce);
_b.label = 2;
case 2:
if (encodeMode === 'rlp') {
_a = tslib_1.__read(staking.rlpSign(this.privateKey), 2), signature = _a[0], rawTransaction = _a[1];
staking.setRawTransaction(rawTransaction);
staking.setSignature(signature);
staking.setFromAddress(this.messenger.chainPrefix === utils_1.ChainType.Harmony
? this.bech32Address
: this.checksumAddress || '0x');
return [2 /*return*/, staking];
}
else {
// TODO: if we use other encode method, eg. protobuf, we should implement this
return [2 /*return*/, staking];
}
return [2 /*return*/];
}
});
});
};
/**
* @param messenger
*
* @example
* ```javascript
* // create a custom messenger
* const customMessenger = new Messenger(
* new HttpProvider('http://localhost:9500'),
* ChainType.Harmony, // if you are connected to Harmony's blockchain
* ChainID.HmyLocal, // check if the chainId is correct
* )
*
* // to create an Account with random privateKey
* // and you can setMessenger later
* const randomAccount = new Account()
* randomAccount.setMessenger(customMessenger)
* ```
*/
Account.prototype.setMessenger = function (messenger) {
this.messenger = messenger;
};
/**
* Get account address from shard ID
* @param shardID
*
* @example
* ```javascript
* console.log(account.getAddressFromShardID(0));
*
* > one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7-0
* ```
*/
Account.prototype.getAddressFromShardID = function (shardID) {
var shardObject = this.shards.get(shardID);
if (shardObject) {
return shardObject.address;
}
else {
return undefined;
}
};
/**
* Get all shards' addresses from the account
*
* @example
* ```javascript
* console.log(account.getAddresses());
* ```
*/
Account.prototype.getAddresses = function () {
var e_2, _a;
var addressArray = [];
try {
for (var _b = tslib_1.__values(this.shards), _c = _b.next(); !_c.done; _c = _b.next()) {
var _d = tslib_1.__read(_c.value, 2), name_2 = _d[0], val = _d[1];
var index = typeof name_2 === 'string' ? Number.parseInt(name_2, 10) : name_2;
addressArray[index] = val.address;
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
return addressArray;
};
/**
* Get the specific shard's balance
*
* @param shardID `shardID` is binding with the endpoint, IGNORE it!
* @param blockNumber by default, it's `latest`
*
* @example
* ```
* account.getShardBalance().then((value) => {
* console.log(value);
* });
* ```
*/
Account.prototype.getShardBalance = function (shardID, blockNumber) {
if (blockNumber === void 0) { blockNumber = 'latest'; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var balance, nonce;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.messenger.send(network_1.RPCMethod.GetBalance, [this.address, blockNumber], this.messenger.chainPrefix, shardID)];
case 1:
balance = _a.sent();
return [4 /*yield*/, this.messenger.send(network_1.RPCMethod.GetTransactionCount, [this.address, blockNumber], this.messenger.chainPrefix, shardID)];
case 2:
nonce = _a.sent();
if (balance.isError()) {
throw balance.error.message;
}
if (nonce.isError()) {
throw nonce.error.message;
}
return [2 /*return*/, {
address: "" + this.bech32Address + utils_1.AddressSuffix + shardID,
balance: utils_1.hexToNumber(balance.result),
nonce: Number.parseInt(utils_1.hexToNumber(nonce.result), 10),
}];
}
});
});
};
/**
* Get the specific shard's nonce
*
* @param shardID `shardID` is binding with the endpoint, IGNORE it!
* @param blockNumber by default, it's `latest`
*
* @example
* ```
* account.getShardNonce().then((value) => {
* console.log(value);
* });
* ```
*/
Account.prototype.getShardNonce = function (shardID, blockNumber) {
if (blockNumber === void 0) { blockNumber = 'latest'; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var nonce;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.messenger.send(network_1.RPCMethod.GetAccountNonce, [this.address, blockNumber], this.messenger.chainPrefix, shardID)];
case 1:
nonce = _a.sent();
if (nonce.isError()) {
throw nonce.error.message;
}
return [2 /*return*/, nonce.result];
}
});
});
};
/**
* @function _new private method create Account
* @return {Account} Account instance
* @ignore
*/
Account.prototype._new = function () {
var prv = crypto_1.generatePrivateKey();
if (!utils_1.isPrivateKey(prv)) {
throw new Error('key gen failed');
}
return this._import(prv);
};
/**
* @function _import private method import a private Key
* @param {string} key - private key
* @return {Account} Account instance
* @ignore
*/
Account.prototype._import = function (key) {
if (!utils_1.isPrivateKey(key)) {
throw new Error(key + " is not PrivateKey");
}
this.privateKey = utils_1.add0xToString(key);
this.publicKey = crypto_1.getPubkeyFromPrivateKey(this.privateKey);
this.address = crypto_1.getAddressFromPrivateKey(this.privateKey);
this.shardID = this.messenger.currentShard || 0;
this.shards = new Map();
this.shards.set(this.shardID, {
address: "" + this.bech32Address + utils_1.AddressSuffix + "0",
balance: this.balance || '0',
nonce: this.nonce || 0,
});
this.encrypted = false;
return this;
};
return Account;
}());
exports.Account = Account;
//# sourceMappingURL=account.js.map