@aeternity/aepp-sdk
Version:
SDK for the æternity blockchain
358 lines (324 loc) • 13.4 kB
JavaScript
import _T from "ramda/src/T";
import _lte from "ramda/src/lte";
import _always from "ramda/src/always";
import _lt from "ramda/src/lt";
import _cond from "ramda/src/cond";
import _slicedToArray from "@babel/runtime-corejs3/helpers/slicedToArray";
import _toConsumableArray from "@babel/runtime-corejs3/helpers/toConsumableArray";
import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat";
import _padStartInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/pad-start";
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
import _sliceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/slice";
import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map";
import _Object$assign from "@babel/runtime-corejs3/core-js-stable/object/assign";
import _endsWithInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/ends-with";
import _findInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/find";
import BigNumber from 'bignumber.js';
import { assertedType, decodeBase58Check, decodeBase64Check, encodeBase58Check, encodeBase64Check, hash, salt } from '../../utils/crypto';
import { toBytes } from '../../utils/bytes';
import { ID_TAG_PREFIX, PREFIX_ID_TAG, NAME_BID_RANGES, NAME_BID_MAX_LENGTH, NAME_FEE, NAME_FEE_BID_INCREMENT, NAME_BID_TIMEOUTS, NAME_ID_KEY } from './schema';
import { ceil } from '../../utils/bignumber';
/**
* JavaScript-based Transaction builder helper function's
* @module @aeternity/aepp-sdk/es/tx/builder/helpers
* @export TxBuilderHelper
* @example import { TxBuilderHelper } from '@aeternity/aepp-sdk'
*/
export var createSalt = salt;
var base64Types = ['tx', 'st', 'ss', 'pi', 'ov', 'or', 'cb', 'cs', 'ba'];
/**
* Build a contract public key
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {string} ownerId The public key of the owner account
* @param {number} nonce the nonce of the transaction
* @return {string} Contract public key
*/
export function buildContractId(ownerId, nonce) {
var _context;
var ownerIdAndNonce = Buffer.from(_concatInstanceProperty(_context = []).call(_context, _toConsumableArray(decode(ownerId, 'ak')), _toConsumableArray(toBytes(nonce))));
var b2bHash = hash(ownerIdAndNonce);
return encode(b2bHash, 'ct');
}
/**
* Build hash
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {String} prefix Transaction hash prefix
* @param {Buffer} data Rlp encoded transaction buffer
* @param {Object} options
* @param {Boolean} options.raw
* @return {String} Transaction hash
*/
export function buildHash(prefix, data) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
return options.raw ? hash(data) : encode(hash(data), prefix);
}
/**
* Build a oracle query id
* @function
* @function* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {String} senderId The public key of the sender account
* @param {Number} nonce the nonce of the transaction
* @param {Number} oracleId The oracle public key
* @return {string} Contract public key
*/
export function oracleQueryId(senderId, nonce, oracleId) {
var _context2;
function _int32(val) {
var nonceBE = toBytes(val, true);
return _concatInstanceProperty(Buffer).call(Buffer, [Buffer.alloc(32 - nonceBE.length), nonceBE]);
}
var b2bHash = hash(Buffer.from(_concatInstanceProperty(_context2 = []).call(_context2, _toConsumableArray(decode(senderId, 'ak')), _toConsumableArray(_int32(nonce)), _toConsumableArray(decode(oracleId, 'ok')))));
return encode(b2bHash, 'oq');
}
/**
* Format the salt into a 64-byte hex string
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {number} salt
* @return {string} Zero-padded hex string of salt
*/
export function formatSalt(salt) {
var _context3;
return Buffer.from(_padStartInstanceProperty(_context3 = salt.toString(16)).call(_context3, 64, '0'), 'hex');
}
/**
* Encode a domain name
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {String} name Name to encode
* @return {String} `nm_` prefixed encoded domain name
*/
export function produceNameId(name) {
ensureNameValid(name);
return encode(hash(name.toLowerCase()), 'nm');
}
/**
* Generate the commitment hash by hashing the formatted salt and
* name, base 58 encoding the result and prepending 'cm_'
*
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @function commitmentHash
* @category async
* @rtype (name: String, salt?: String) => hash: Promise[String]
* @param {String} name - Name to be registered
* @param {Number} salt Random salt
* @return {String} Commitment hash
*/
export function commitmentHash(name) {
var salt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : createSalt();
ensureNameValid(name);
return "cm_".concat(encodeBase58Check(hash(_concatInstanceProperty(Buffer).call(Buffer, [Buffer.from(name.toLowerCase()), formatSalt(salt)]))));
}
/**
* Decode data using the default encoding/decoding algorithm
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {string} data An encoded and prefixed string (ex tx_..., sg_..., ak_....)
* @param {string} type Prefix of Transaction
* @return {Buffer} Buffer of decoded Base58check or Base64check data
*/
export function decode(data) {
var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
if (!type) type = data.split('_')[0];
return _includesInstanceProperty(base64Types).call(base64Types, type) ? decodeBase64Check(assertedType(data, type)) : decodeBase58Check(assertedType(data, type));
}
/**
* Encode data using the default encoding/decoding algorithm
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {Buffer|String} data An decoded data
* @param {string} type Prefix of Transaction
* @return {String} Encoded string Base58check or Base64check data
*/
export function encode(data, type) {
var _context4;
return _concatInstanceProperty(_context4 = "".concat(type, "_")).call(_context4, _includesInstanceProperty(base64Types).call(base64Types, type) ? encodeBase64Check(data) : encodeBase58Check(data));
}
/**
* Utility function to create and _id type
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {string} hashId Encoded hash
* @return {Buffer} Buffer Buffer with ID tag and decoded HASh
*/
export function writeId(hashId) {
var _context5;
var prefix = _sliceInstanceProperty(hashId).call(hashId, 0, 2);
var idTag = PREFIX_ID_TAG[prefix];
if (!idTag) throw new Error("Id tag for prefix ".concat(prefix, " not found."));
return Buffer.from(_concatInstanceProperty(_context5 = []).call(_context5, _toConsumableArray(toBytes(idTag)), _toConsumableArray(decode(hashId, prefix))));
}
/**
* Utility function to read and _id type
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {Buffer} buf Data
* @return {String} Encoided hash string with prefix
*/
export function readId(buf) {
var tag = buf.readUIntBE(0, 1);
var prefix = ID_TAG_PREFIX[tag];
if (!prefix) throw new Error("Prefix for id-tag ".concat(tag, " not found."));
return encode(_sliceInstanceProperty(buf).call(buf, 1, buf.length), prefix);
}
/**
* Utility function to convert int to bytes
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {Number|String|BigNumber} val Value
* @return {Buffer} Buffer Buffer from number(BigEndian)
*/
export function writeInt(val) {
return toBytes(val, true);
}
/**
* Utility function to convert bytes to int
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {Buffer} buf Value
* @return {String} Buffer Buffer from number(BigEndian)
*/
export function readInt() {
var buf = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Buffer.from([]);
return BigNumber(buf.toString('hex'), 16).toString(10);
}
/**
* Helper function to build pointers for name update TX
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {Array} pointers - Array of pointers ([ { key: 'account_pubkey', id: 'ak_32klj5j23k23j5423l434l2j3423'} ])
* @return {Array} Serialized pointers array
*/
export function buildPointers(pointers) {
return _mapInstanceProperty(pointers).call(pointers, function (p) {
return [toBytes(p.key), writeId(p.id)];
});
}
/**
* Helper function to read pointers from name update TX
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {Array} pointers - Array of pointers ([ { key: 'account_pubkey', id: 'ak_32klj5j23k23j5423l434l2j3423'} ])
* @return {Array} Deserialize pointer array
*/
export function readPointers(pointers) {
return _mapInstanceProperty(pointers).call(pointers, function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
key = _ref2[0],
id = _ref2[1];
return _Object$assign({
key: key.toString(),
id: readId(id)
});
});
}
/**
* Ensure that name is valid
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {string} name
* @return void
* @throws Error
*/
export function ensureNameValid(name) {
if (!name || typeof name !== 'string') throw new Error('Name must be a string');
if (!_endsWithInstanceProperty(name).call(name, '.chain')) throw new Error("Name should end with .chain: ".concat(name));
}
/**
* Is name valid
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {string} name
* @return Boolean
*/
export function isNameValid(name) {
try {
ensureNameValid(name);
return true;
} catch (error) {
return false;
}
}
/**
* What kind of a hash is this? If it begins with 'ak_' it is an
* account key, if with 'ok_' it's an oracle key.
*
* @param s - the hash.
* returns the type, or throws an exception if type not found.
*/
export function classify(s) {
if (!s.match(/^[a-z]{2}_.+/)) {
throw new Error('Not a valid hash');
}
var klass = s.substr(0, 2);
if (klass in NAME_ID_KEY) {
return NAME_ID_KEY[klass];
} else {
throw new Error("Unknown class ".concat(klass));
}
}
/**
* Validate name pointers array
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {String[]} pointers Pointers array. Allowed values is: account(ak_), oracle(ok_), contract(ct_), channel(ch_)
* @return {Boolean}
*/
export function validatePointers() {
var pointers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
return !_findInstanceProperty(pointers).call(pointers, function (p) {
var _context6;
return !p || typeof p !== 'string' || !_includesInstanceProperty(_context6 = ['ak', 'ok', 'ct', 'ch']).call(_context6, p.split('_')[0]);
});
}
/**
* Get the minimum name fee for a domain
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {String} domain the domain name to get the fee for
* @return {String} the minimum fee for the domain auction
*/
export function getMinimumNameFee(domain) {
var nameLength = domain.replace('.chain', '').length;
return NAME_BID_RANGES[nameLength >= NAME_BID_MAX_LENGTH ? NAME_BID_MAX_LENGTH : nameLength];
}
/**
* Compute bid fee for AENS auction
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {String} domain the domain name to get the fee for
* @param {Number|String} startFee Auction start fee
* @param {Number} [increment=0.5] Bid multiplier(In percentage, must be between 0 and 1)
* @return {String} Bid fee
*/
export function computeBidFee(domain) {
var startFee = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : NAME_FEE;
var increment = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : NAME_FEE_BID_INCREMENT;
if (!(Number(increment) === increment && increment % 1 !== 0)) throw new Error("Increment must be float. Current increment ".concat(increment));
if (increment < NAME_FEE_BID_INCREMENT) throw new Error("minimum increment percentage is ".concat(NAME_FEE_BID_INCREMENT));
return ceil(BigNumber(BigNumber(startFee).eq(NAME_FEE) ? getMinimumNameFee(domain) : startFee).times(BigNumber(NAME_FEE_BID_INCREMENT).plus(1)));
}
/**
* Compute auction end height
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {String} domain the domain name to get the fee for
* @param {Number|String} claimHeight Auction starting height
* @return {String} Auction end height
*/
export function computeAuctionEndBlock(domain, claimHeight) {
return _cond([[_lt(5), _always(NAME_BID_TIMEOUTS[4].plus(claimHeight))], [_lt(9), _always(NAME_BID_TIMEOUTS[8].plus(claimHeight))], [_lte(NAME_BID_MAX_LENGTH), _always(NAME_BID_TIMEOUTS[12].plus(claimHeight))], [_T, _always(BigNumber(claimHeight))]])(domain.replace('.chain', '').length).toString(10);
}
/**
* Is name accept going to auction
* @function
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @param {String} name Transaction abiVersion
* @return {Boolean}
*/
export function isAuctionName(name) {
return name.replace('.chain', '').length < 13;
}
//# sourceMappingURL=helpers.js.map