UNPKG

@alayanetwork/ethjs-ens

Version:
1,862 lines (1,660 loc) 1.05 MB
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ module.exports=[ { "constant": true, "inputs": [ { "name": "node", "type": "bytes32" } ], "name": "resolver", "outputs": [ { "name": "", "type": "address" } ], "type": "function" }, { "constant": true, "inputs": [ { "name": "node", "type": "bytes32" } ], "name": "owner", "outputs": [ { "name": "", "type": "address" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "node", "type": "bytes32" }, { "name": "resolver", "type": "address" } ], "name": "setResolver", "outputs": [], "type": "function" }, { "constant": false, "inputs": [ { "name": "node", "type": "bytes32" }, { "name": "label", "type": "bytes32" }, { "name": "owner", "type": "address" } ], "name": "setSubnodeOwner", "outputs": [], "type": "function" }, { "constant": false, "inputs": [ { "name": "node", "type": "bytes32" }, { "name": "owner", "type": "address" } ], "name": "setOwner", "outputs": [], "type": "function" } ] },{}],2:[function(require,module,exports){ module.exports=[ { "constant": true, "inputs": [ { "name": "node", "type": "bytes32" } ], "name": "addr", "outputs": [ { "name": "", "type": "address" } ], "type": "function" }, { "constant": true, "inputs": [ { "name": "node", "type": "bytes32" } ], "name": "content", "outputs": [ { "name": "", "type": "bytes32" } ], "type": "function" }, { "constant": true, "inputs": [ { "name": "node", "type": "bytes32" } ], "name": "name", "outputs": [ { "name": "", "type": "string" } ], "type": "function" }, { "constant": true, "inputs": [ { "name": "node", "type": "bytes32" }, { "name": "kind", "type": "bytes32" } ], "name": "has", "outputs": [ { "name": "", "type": "bool" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "node", "type": "bytes32" }, { "name": "addr", "type": "address" } ], "name": "setAddr", "outputs": [], "type": "function" }, { "constant": false, "inputs": [ { "name": "node", "type": "bytes32" }, { "name": "hash", "type": "bytes32" } ], "name": "setContent", "outputs": [], "type": "function" }, { "constant": false, "inputs": [ { "name": "node", "type": "bytes32" }, { "name": "name", "type": "string" } ], "name": "setName", "outputs": [], "type": "function" }, { "constant": true, "inputs": [ { "name": "node", "type": "bytes32" }, { "name": "contentType", "type": "uint256" } ], "name": "ABI", "outputs": [ { "name": "", "type": "uint256" }, { "name": "", "type": "bytes" } ], "payable": false, "type": "function" } ] },{}],3:[function(require,module,exports){ const ENS = require('../') const HttpProvider = require('ethjs-provider-http') const networkMap = require('../lib/network-map.json') let ens // For MetaMask or Mist compatibility: window.addEventListener('load', function() { if (typeof window.web3 !== 'undefined') { console.log('web3 browser detected, using.') web3.version.getNetwork(function (err, network) { if (err) { return resultField.innerText = 'There was a problem: ' + err.message } ens = new ENS({ provider: web3.currentProvider, network: network }) }) } else { console.log('no web3 browser detected, using infura.') const provider = new HttpProvider('https://mainnet.infura.io') ens = new ENS({ provider, network: '1' }) } }) searchButton.addEventListener('click', function() { console.log('clicked button.') var query = lookupField.value console.log('querying for ' + query) ens.lookup(query) .then((address) => { console.log('ens returned ' + address) resultField.innerText = address }) .catch((reason) => { console.log('ens failed!') console.error(reason) resultField.innerText = 'There was a problem: ' + reason.message }) }) },{"../":4,"../lib/network-map.json":5,"ethjs-provider-http":131}],4:[function(require,module,exports){ // External Deps const Eth = require('@alayanetwork/ethjs-query') const EthContract = require('@alayanetwork/ethjs-contract') const namehash = require('eth-ens-namehash') // ABIs const registryAbi = require('./abis/registry.json') const resolverAbi = require('./abis/resolver.json') // Map network to known ENS registries const networkMap = require('ethereum-ens-network-map') const emptyHash = '0x0000000000000000000000000000000000000000000000000000000000000000' const emptyAddr = '0x0000000000000000000000000000000000000000' const NotFoundError = new Error('ENS name not defined.') const BadCharacterError = new Error('Illegal Character for ENS.') class Ens { constructor (opts = {}) { const { provider, network } = opts let { registryAddress } = opts // Validations if (!provider) { throw new Error('The EthJsENS Constructor requires a provider.') } // Requires EITHER a network or a registryAddress if (!network && !registryAddress) { throw new Error('The EthJsENS Constructor requires a network or registry address.') } this.provider = provider this.eth = new Eth(this.provider) this.contract = new EthContract(this.eth) this.namehash = namehash // Link to Registry this.Registry = this.contract(registryAbi) if (!registryAddress && network) { registryAddress = networkMap[network] } this.registry = this.Registry.at(registryAddress) // Create Resolver class this.Resolver = this.contract(resolverAbi) } lookup (name = '') { return this.getNamehash(name) .then((node) => { if (node === emptyHash) { return Promise.reject(NotFoundError) } return this.resolveAddressForNode(node) }) } getNamehash (name) { try { return Promise.resolve(namehash(name)) } catch (e) { return Promise.reject(BadCharacterError) } } getOwner (name = '') { return this.getNamehash(name) .then(node => this.getOwnerForNode(node)) } getOwnerForNode (node) { if (node === emptyHash) { return Promise.reject(NotFoundError) } return this.registry.owner(node) .then((result) => { const ownerAddress = result[0] if (ownerAddress === emptyAddr) { throw NotFoundError } return ownerAddress }) } getResolver (name = '') { return this.getNamehash(name) .then(node => this.getResolverForNode(node)) } getResolverAddress (name = '') { return this.getNamehash(name) .then(node => this.getResolverAddressForNode(node)) } getResolverForNode (node) { if (!node.startsWith('0x')) { node = `0x${node}` } return this.getResolverAddressForNode(node) .then((resolverAddress) => { return this.Resolver.at(resolverAddress) }) } getResolverAddressForNode (node) { return this.registry.resolver(node) .then((result) => { const resolverAddress = result[0] if (resolverAddress === emptyAddr) { throw NotFoundError } return resolverAddress }) } resolveAddressForNode (node) { return this.getResolverForNode(node) .then((resolver) => { return resolver.addr(node) }) .then(result => result[0]) } reverse (address) { if (!address) { return Promise.reject(new Error('Must supply an address to reverse lookup.')) } if (address.startsWith('0x')) { address = address.slice(2) } const name = `${address.toLowerCase()}.addr.reverse` const node = namehash(name) return this.getNamehash(name) .then(node => this.getResolverForNode(node)) .then(resolver => resolver.name(node)) .then(results => results[0]) } } module.exports = Ens },{"./abis/registry.json":1,"./abis/resolver.json":2,"@alayanetwork/ethjs-contract":14,"@alayanetwork/ethjs-query":19,"eth-ens-namehash":127,"ethereum-ens-network-map":129}],5:[function(require,module,exports){ module.exports={ "1": { "registry": "314159265dd8dbb310642f98f50c066173c1259b" }, "3": { "registry": "112234455c3a32fd11230c42e7bccd4a84e02010", "resolver": "C68De5B43C3d980B0C110A77a5F78d3c4c4d63B4" } } },{}],6:[function(require,module,exports){ 'use strict'; // Copyright (c) 2017 Pieter Wuille // // 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. var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; module.exports = { decode: decode, encode: encode }; function polymod(values) { var chk = 1; for (var p = 0; p < values.length; ++p) { var top = chk >> 25; chk = (chk & 0x1ffffff) << 5 ^ values[p]; for (var i = 0; i < 5; ++i) { if (top >> i & 1) { chk ^= GENERATOR[i]; } } } return chk; } function hrpExpand(hrp) { var ret = []; var p; for (p = 0; p < hrp.length; ++p) { ret.push(hrp.charCodeAt(p) >> 5); } ret.push(0); for (p = 0; p < hrp.length; ++p) { ret.push(hrp.charCodeAt(p) & 31); } return ret; } function verifyChecksum(hrp, data) { return polymod(hrpExpand(hrp).concat(data)) === 1; } function createChecksum(hrp, data) { var values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]); var mod = polymod(values) ^ 1; var ret = []; for (var p = 0; p < 6; ++p) { ret.push(mod >> 5 * (5 - p) & 31); } return ret; } function encode(hrp, data) { var combined = data.concat(createChecksum(hrp, data)); var ret = hrp + '1'; for (var p = 0; p < combined.length; ++p) { ret += CHARSET.charAt(combined[p]); } return ret; } function decode(bechString) { var p; var hasLower = false; var hasUpper = false; for (p = 0; p < bechString.length; ++p) { if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) { return null; } if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) { hasLower = true; } if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) { hasUpper = true; } } if (hasLower && hasUpper) { return null; } bechString = bechString.toLowerCase(); var pos = bechString.lastIndexOf('1'); if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) { return null; } var hrp = bechString.substring(0, pos); var data = []; for (p = pos + 1; p < bechString.length; ++p) { var d = CHARSET.indexOf(bechString.charAt(p)); if (d === -1) { return null; } data.push(d); } if (!verifyChecksum(hrp, data)) { return null; } return { hrp: hrp, data: data.slice(0, data.length - 6) }; } },{}],7:[function(require,module,exports){ 'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var createKeccakHash = require('keccak'); var secp256k1 = require('secp256k1'); var assert = require('assert'); var rlp = require('rlp'); var BN = require('bn.js'); var segwitAddr = require('./segwit_addr'); var createHash = require('create-hash'); var Buffer = require('safe-buffer').Buffer; Object.assign(exports, require('ethjs-util')); /** * the max integer that this VM can handle (a ```BN```) * @var {BN} MAX_INTEGER */ exports.MAX_INTEGER = new BN('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16); /** * 2^256 (a ```BN```) * @var {BN} TWO_POW256 */ exports.TWO_POW256 = new BN('10000000000000000000000000000000000000000000000000000000000000000', 16); /** * Keccak-256 hash of null (a ```String```) * @var {String} KECCAK256_NULL_S */ exports.KECCAK256_NULL_S = 'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'; exports.SHA3_NULL_S = exports.KECCAK256_NULL_S; /** * Keccak-256 hash of null (a ```Buffer```) * @var {Buffer} KECCAK256_NULL */ exports.KECCAK256_NULL = Buffer.from(exports.KECCAK256_NULL_S, 'hex'); exports.SHA3_NULL = exports.KECCAK256_NULL; /** * Keccak-256 of an RLP of an empty array (a ```String```) * @var {String} KECCAK256_RLP_ARRAY_S */ exports.KECCAK256_RLP_ARRAY_S = '1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347'; exports.SHA3_RLP_ARRAY_S = exports.KECCAK256_RLP_ARRAY_S; /** * Keccak-256 of an RLP of an empty array (a ```Buffer```) * @var {Buffer} KECCAK256_RLP_ARRAY */ exports.KECCAK256_RLP_ARRAY = Buffer.from(exports.KECCAK256_RLP_ARRAY_S, 'hex'); exports.SHA3_RLP_ARRAY = exports.KECCAK256_RLP_ARRAY; /** * Keccak-256 hash of the RLP of null (a ```String```) * @var {String} KECCAK256_RLP_S */ exports.KECCAK256_RLP_S = '56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421'; exports.SHA3_RLP_S = exports.KECCAK256_RLP_S; /** * Keccak-256 hash of the RLP of null (a ```Buffer```) * @var {Buffer} KECCAK256_RLP */ exports.KECCAK256_RLP = Buffer.from(exports.KECCAK256_RLP_S, 'hex'); exports.SHA3_RLP = exports.KECCAK256_RLP; /** * [`BN`](https://github.com/indutny/bn.js) * @var {Function} */ exports.BN = BN; /** * [`rlp`](https://github.com/ethereumjs/rlp) * @var {Function} */ exports.rlp = rlp; /** * [`secp256k1`](https://github.com/cryptocoinjs/secp256k1-node/) * @var {Object} */ exports.secp256k1 = secp256k1; /** * Returns a buffer filled with 0s * @method zeros * @param {Number} bytes the number of bytes the buffer should be * @return {Buffer} */ exports.zeros = function (bytes) { return Buffer.allocUnsafe(bytes).fill(0); }; /** * Returns a zero address * @method zeroAddress * @return {String} */ exports.zeroAddress = function () { var addressLength = 20; var zeroAddress = exports.zeros(addressLength); return exports.bufferToHex(zeroAddress); }; /** * Left Pads an `Array` or `Buffer` with leading zeros till it has `length` bytes. * Or it truncates the beginning if it exceeds. * @method lsetLength * @param {Buffer|Array} msg the value to pad * @param {Number} length the number of bytes the output should be * @param {Boolean} [right=false] whether to start padding form the left or right * @return {Buffer|Array} */ exports.setLengthLeft = exports.setLength = function (msg, length, right) { var buf = exports.zeros(length); msg = exports.toBuffer(msg); if (right) { if (msg.length < length) { msg.copy(buf); return buf; } return msg.slice(0, length); } else { if (msg.length < length) { msg.copy(buf, length - msg.length); return buf; } return msg.slice(-length); } }; /** * Right Pads an `Array` or `Buffer` with leading zeros till it has `length` bytes. * Or it truncates the beginning if it exceeds. * @param {Buffer|Array} msg the value to pad * @param {Number} length the number of bytes the output should be * @return {Buffer|Array} */ exports.setLengthRight = function (msg, length) { return exports.setLength(msg, length, true); }; /** * Trims leading zeros from a `Buffer` or an `Array` * @param {Buffer|Array|String} a * @return {Buffer|Array|String} */ exports.unpad = exports.stripZeros = function (a) { a = exports.stripHexPrefix(a); var first = a[0]; while (a.length > 0 && first.toString() === '0') { a = a.slice(1); first = a[0]; } return a; }; /** * Attempts to turn a value into a `Buffer`. As input it supports `Buffer`, `String`, `Number`, null/undefined, `BN` and other objects with a `toArray()` method. * @param {*} v the value */ exports.toBuffer = function (v) { if (!Buffer.isBuffer(v)) { if (Array.isArray(v)) { v = Buffer.from(v); } else if (typeof v === 'string') { if (exports.isHexString(v)) { v = Buffer.from(exports.padToEven(exports.stripHexPrefix(v)), 'hex'); } else { v = Buffer.from(v); } } else if (typeof v === 'number') { v = exports.intToBuffer(v); } else if (v === null || v === undefined) { v = Buffer.allocUnsafe(0); } else if (BN.isBN(v)) { v = v.toArrayLike(Buffer); } else if (v.toArray) { // converts a BN to a Buffer v = Buffer.from(v.toArray()); } else { throw new Error('invalid type'); } } return v; }; /** * Converts a `Buffer` to a `Number` * @param {Buffer} buf * @return {Number} * @throws If the input number exceeds 53 bits. */ exports.bufferToInt = function (buf) { return new BN(exports.toBuffer(buf)).toNumber(); }; /** * Converts a `Buffer` into a hex `String` * @param {Buffer} buf * @return {String} */ exports.bufferToHex = function (buf) { buf = exports.toBuffer(buf); return '0x' + buf.toString('hex'); }; /** * Interprets a `Buffer` as a signed integer and returns a `BN`. Assumes 256-bit numbers. * @param {Buffer} num * @return {BN} */ exports.fromSigned = function (num) { return new BN(num).fromTwos(256); }; /** * Converts a `BN` to an unsigned integer and returns it as a `Buffer`. Assumes 256-bit numbers. * @param {BN} num * @return {Buffer} */ exports.toUnsigned = function (num) { return Buffer.from(num.toTwos(256).toArray()); }; /** * Creates Keccak hash of the input * @param {Buffer|Array|String|Number} a the input data * @param {Number} [bits=256] the Keccak width * @return {Buffer} */ exports.keccak = function (a, bits) { a = exports.toBuffer(a); if (!bits) bits = 256; return createKeccakHash('keccak' + bits).update(a).digest(); }; /** * Creates Keccak-256 hash of the input, alias for keccak(a, 256) * @param {Buffer|Array|String|Number} a the input data * @return {Buffer} */ exports.keccak256 = function (a) { return exports.keccak(a); }; /** * Creates SHA-3 (Keccak) hash of the input [OBSOLETE] * @param {Buffer|Array|String|Number} a the input data * @param {Number} [bits=256] the SHA-3 width * @return {Buffer} */ exports.sha3 = exports.keccak; /** * Creates SHA256 hash of the input * @param {Buffer|Array|String|Number} a the input data * @return {Buffer} */ exports.sha256 = function (a) { a = exports.toBuffer(a); return createHash('sha256').update(a).digest(); }; /** * Creates RIPEMD160 hash of the input * @param {Buffer|Array|String|Number} a the input data * @param {Boolean} padded whether it should be padded to 256 bits or not * @return {Buffer} */ exports.ripemd160 = function (a, padded) { a = exports.toBuffer(a); var hash = createHash('rmd160').update(a).digest(); if (padded === true) { return exports.setLength(hash, 32); } else { return hash; } }; /** * Creates SHA-3 hash of the RLP encoded version of the input * @param {Buffer|Array|String|Number} a the input data * @return {Buffer} */ exports.rlphash = function (a) { return exports.keccak(rlp.encode(a)); }; /** * Checks if the private key satisfies the rules of the curve secp256k1. * @param {Buffer} privateKey * @return {Boolean} */ exports.isValidPrivate = function (privateKey) { return secp256k1.privateKeyVerify(privateKey); }; /** * Checks if the public key satisfies the rules of the curve secp256k1 * and the requirements of Ethereum. * @param {Buffer} publicKey The two points of an uncompressed key, unless sanitize is enabled * @param {Boolean} [sanitize=false] Accept public keys in other formats * @return {Boolean} */ exports.isValidPublic = function (publicKey, sanitize) { if (publicKey.length === 64) { // Convert to SEC1 for secp256k1 return secp256k1.publicKeyVerify(Buffer.concat([Buffer.from([4]), publicKey])); } if (!sanitize) { return false; } return secp256k1.publicKeyVerify(publicKey); }; /** * Returns the ethereum address of a given public key. * Accepts "Ethereum public keys" and SEC1 encoded keys. * @param {Buffer} pubKey The two points of an uncompressed key, unless sanitize is enabled * @param {Boolean} [sanitize=false] Accept public keys in other formats * @return {Buffer} */ exports.pubToAddress = exports.publicToAddress = function (pubKey, sanitize) { pubKey = exports.toBuffer(pubKey); if (sanitize && pubKey.length !== 64) { pubKey = secp256k1.publicKeyConvert(pubKey, false).slice(1); } assert(pubKey.length === 64); // Only take the lower 160bits of the hash return exports.keccak(pubKey).slice(-20); }; /** * Returns the ethereum public key of a given private key * @param {Buffer} privateKey A private key must be 256 bits wide * @return {Buffer} */ var privateToPublic = exports.privateToPublic = function (privateKey) { privateKey = exports.toBuffer(privateKey); // skip the type flag and use the X, Y points return secp256k1.publicKeyCreate(privateKey, false).slice(1); }; /** * Converts a public key to the Ethereum format. * @param {Buffer} publicKey * @return {Buffer} */ exports.importPublic = function (publicKey) { publicKey = exports.toBuffer(publicKey); if (publicKey.length !== 64) { publicKey = secp256k1.publicKeyConvert(publicKey, false).slice(1); } return publicKey; }; /** * ECDSA sign * @param {Buffer} msgHash * @param {Buffer} privateKey * @return {Object} */ exports.ecsign = function (msgHash, privateKey) { var sig = secp256k1.sign(msgHash, privateKey); var ret = {}; ret.r = sig.signature.slice(0, 32); ret.s = sig.signature.slice(32, 64); ret.v = sig.recovery + 27; return ret; }; /** * Returns the keccak-256 hash of `message`, prefixed with the header used by the `eth_sign` RPC call. * The output of this function can be fed into `ecsign` to produce the same signature as the `eth_sign` * call for a given `message`, or fed to `ecrecover` along with a signature to recover the public key * used to produce the signature. * @param message * @returns {Buffer} hash */ exports.hashPersonalMessage = function (message) { var prefix = exports.toBuffer('\x19Ethereum Signed Message:\n' + message.length.toString()); return exports.keccak(Buffer.concat([prefix, message])); }; /** * ECDSA public key recovery from signature * @param {Buffer} msgHash * @param {Number} v * @param {Buffer} r * @param {Buffer} s * @return {Buffer} publicKey */ exports.ecrecover = function (msgHash, v, r, s) { var signature = Buffer.concat([exports.setLength(r, 32), exports.setLength(s, 32)], 64); var recovery = v - 27; if (recovery !== 0 && recovery !== 1) { throw new Error('Invalid signature v value'); } var senderPubKey = secp256k1.recover(msgHash, signature, recovery); return secp256k1.publicKeyConvert(senderPubKey, false).slice(1); }; /** * Convert signature parameters into the format of `eth_sign` RPC method * @param {Number} v * @param {Buffer} r * @param {Buffer} s * @return {String} sig */ exports.toRpcSig = function (v, r, s) { // NOTE: with potential introduction of chainId this might need to be updated if (v !== 27 && v !== 28) { throw new Error('Invalid recovery id'); } // geth (and the RPC eth_sign method) uses the 65 byte format used by Bitcoin // FIXME: this might change in the future - https://github.com/ethereum/go-ethereum/issues/2053 return exports.bufferToHex(Buffer.concat([exports.setLengthLeft(r, 32), exports.setLengthLeft(s, 32), exports.toBuffer(v - 27)])); }; /** * Convert signature format of the `eth_sign` RPC method to signature parameters * NOTE: all because of a bug in geth: https://github.com/ethereum/go-ethereum/issues/2053 * @param {String} sig * @return {Object} */ exports.fromRpcSig = function (sig) { sig = exports.toBuffer(sig); // NOTE: with potential introduction of chainId this might need to be updated if (sig.length !== 65) { throw new Error('Invalid signature length'); } var v = sig[64]; // support both versions of `eth_sign` responses if (v < 27) { v += 27; } return { v: v, r: sig.slice(0, 32), s: sig.slice(32, 64) }; }; /** * Returns the ethereum address of a given private key * @param {Buffer} privateKey A private key must be 256 bits wide * @return {Buffer} */ exports.privateToAddress = function (privateKey) { return exports.publicToAddress(privateToPublic(privateKey)); }; /** * Checks if the given string is an bech32 address * * @method isBech32Address * @param {String} address the given bech32 adress * @return {Boolean} */ exports.isBech32Address = function (address) { if (address.length !== 42) { return false; } var hrp = address.substr(0, 3); var ret = segwitAddr.decode(hrp, address); if (ret === null) { return false; } return true; }; /** * Transforms given string to bech32 address * * @method toBech32Address * @param {String} hrp * @param {String} address * @return {String} formatted bech32 address */ exports.toBech32Address = function (hrp, address) { if (exports.isValidAddress(address)) { return segwitAddr.EncodeAddress(hrp, address); } return ''; }; /** * Resolve the bech32 address * * @method decodeBech32Address * @param {String} bech32Address * @return {String} formatted address */ exports.decodeBech32Address = function (bech32Address) { if (exports.isBech32Address(bech32Address)) { var hrp = bech32Address.substr(0, 3); var address = segwitAddr.DecodeAddress(hrp, bech32Address); if (address !== null) { return '0x' + address; } } return ''; }; /** * Checks if the address is a valid. Accepts checksummed addresses too * @param {String} address * @return {Boolean} */ exports.isValidAddress = function (address) { return (/^0x[0-9a-fA-F]{40}$/.test(address) ); }; /** * Checks if a given address is a zero address * @method isZeroAddress * @param {String} address * @return {Boolean} */ exports.isZeroAddress = function (address) { var zeroAddress = exports.zeroAddress(); return zeroAddress === exports.addHexPrefix(address); }; /** * Returns a checksummed address * @param {String} address * @return {String} */ exports.toChecksumAddress = function (address) { address = exports.stripHexPrefix(address).toLowerCase(); var hash = exports.keccak(address).toString('hex'); var ret = '0x'; for (var i = 0; i < address.length; i++) { if (parseInt(hash[i], 16) >= 8) { ret += address[i].toUpperCase(); } else { ret += address[i]; } } return ret; }; /** * Checks if the address is a valid checksummed address * @param {Buffer} address * @return {Boolean} */ exports.isValidChecksumAddress = function (address) { return exports.isValidAddress(address) && exports.toChecksumAddress(address) === address; }; /** * Generates an address of a newly created contract * @param {Buffer} from the address which is creating this new address * @param {Buffer} nonce the nonce of the from account * @return {Buffer} */ exports.generateAddress = function (from, nonce) { from = exports.toBuffer(from); nonce = new BN(nonce); if (nonce.isZero()) { // in RLP we want to encode null in the case of zero nonce // read the RLP documentation for an answer if you dare nonce = null; } else { nonce = Buffer.from(nonce.toArray()); } // Only take the lower 160bits of the hash return exports.rlphash([from, nonce]).slice(-20); }; /** * Returns true if the supplied address belongs to a precompiled account (Byzantium) * @param {Buffer|String} address * @return {Boolean} */ exports.isPrecompiled = function (address) { var a = exports.unpad(address); return a.length === 1 && a[0] >= 1 && a[0] <= 8; }; /** * Adds "0x" to a given `String` if it does not already start with "0x" * @param {String} str * @return {String} */ exports.addHexPrefix = function (str) { if (typeof str !== 'string') { return str; } if (str.startsWith('atx') || str.startsWith('atp')) { return str; } return exports.isHexPrefixed(str) ? str : '0x' + str; }; /** * Validate ECDSA signature * @method isValidSignature * @param {Buffer} v * @param {Buffer} r * @param {Buffer} s * @param {Boolean} [homestead=true] * @return {Boolean} */ exports.isValidSignature = function (v, r, s, homestead) { var SECP256K1_N_DIV_2 = new BN('7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0', 16); var SECP256K1_N = new BN('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 16); if (r.length !== 32 || s.length !== 32) { return false; } if (v !== 27 && v !== 28) { return false; } r = new BN(r); s = new BN(s); if (r.isZero() || r.gt(SECP256K1_N) || s.isZero() || s.gt(SECP256K1_N)) { return false; } if (homestead === false && new BN(s).cmp(SECP256K1_N_DIV_2) === 1) { return false; } return true; }; /** * Converts a `Buffer` or `Array` to JSON * @param {Buffer|Array} ba * @return {Array|String|null} */ exports.baToJSON = function (ba) { if (Buffer.isBuffer(ba)) { return '0x' + ba.toString('hex'); } else if (ba instanceof Array) { var array = []; for (var i = 0; i < ba.length; i++) { array.push(exports.baToJSON(ba[i])); } return array; } }; /** * Defines properties on a `Object`. It make the assumption that underlying data is binary. * @param {Object} self the `Object` to define properties on * @param {Array} fields an array fields to define. Fields can contain: * * `name` - the name of the properties * * `length` - the number of bytes the field can have * * `allowLess` - if the field can be less than the length * * `allowEmpty` * @param {*} data data to be validated against the definitions */ exports.defineProperties = function (self, fields, data) { self.raw = []; self._fields = []; // attach the `toJSON` self.toJSON = function (label) { if (label) { var obj = {}; self._fields.forEach(function (field) { obj[field] = '0x' + self[field].toString('hex'); }); return obj; } return exports.baToJSON(this.raw); }; self.serialize = function serialize() { return rlp.encode(self.raw); }; fields.forEach(function (field, i) { self._fields.push(field.name); function getter() { return self.raw[i]; } function setter(v) { v = exports.toBuffer(v); if (v.toString('hex') === '00' && !field.allowZero) { v = Buffer.allocUnsafe(0); } if (field.allowLess && field.length) { v = exports.stripZeros(v); assert(field.length >= v.length, 'The field ' + field.name + ' must not have more ' + field.length + ' bytes'); } else if (!(field.allowZero && v.length === 0) && field.length) { assert(field.length === v.length, 'The field ' + field.name + ' must have byte length of ' + field.length); } self.raw[i] = v; } Object.defineProperty(self, field.name, { enumerable: true, configurable: true, get: getter, set: setter }); if (field.default) { self[field.name] = field.default; } // attach alias if (field.alias) { Object.defineProperty(self, field.alias, { enumerable: false, configurable: true, set: setter, get: getter }); } }); // if the constuctor is passed data if (data) { if (typeof data === 'string') { data = Buffer.from(exports.stripHexPrefix(data), 'hex'); } if (Buffer.isBuffer(data)) { data = rlp.decode(data); } if (Array.isArray(data)) { if (data.length > self._fields.length) { throw new Error('wrong number of fields in data'); } // make sure all the items are buffers data.forEach(function (d, i) { self[self._fields[i]] = exports.toBuffer(d); }); } else if ((typeof data === 'undefined' ? 'undefined' : _typeof(data)) === 'object') { var keys = Object.keys(data); fields.forEach(function (field) { if (keys.indexOf(field.name) !== -1) self[field.name] = data[field.name]; if (keys.indexOf(field.alias) !== -1) self[field.alias] = data[field.alias]; }); } else { throw new Error('invalid data'); } } }; },{"./segwit_addr":8,"assert":205,"bn.js":28,"create-hash":110,"ethjs-util":133,"keccak":154,"rlp":184,"safe-buffer":185,"secp256k1":186}],8:[function(require,module,exports){ 'use strict'; // Copyright (c) 2017 Pieter Wuille // // 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. var bech32 = require('./bech32'); module.exports = { encode: encode, decode: decode, DecodeAddress: DecodeAddress, EncodeAddress: EncodeAddress }; function convertbits(data, frombits, tobits, pad) { var acc = 0; var bits = 0; var ret = []; var maxv = (1 << tobits) - 1; for (var p = 0; p < data.length; ++p) { var value = data[p]; if (value < 0 || value >> frombits !== 0) { return null; } acc = acc << frombits | value; bits += frombits; while (bits >= tobits) { bits -= tobits; ret.push(acc >> bits & maxv); } } if (pad) { if (bits > 0) { ret.push(acc << tobits - bits & maxv); } } else if (bits >= frombits || acc << tobits - bits & maxv) { return null; } return ret; } function decode(hrp, addr) { var dec = bech32.decode(addr); if (dec === null || dec.hrp !== hrp || dec.data.length < 1 /* || dec.data[0] > 16 */) { return null; } var res = convertbits(dec.data.slice(0), 5, 8, false); if (res === null || res.length < 2 || res.length > 40) { return null; } if (dec.data[0] === 0 && res.length !== 20 && res.length !== 32) { return null; } return { hrp: dec.hrp, program: res }; } function encode(hrp, program) { var ret = bech32.encode(hrp, convertbits(program, 8, 5, true)); if (decode(hrp, ret) === null) { return null; } return ret; } // 十六进制字符串转字节数组 function Str2Bytes(str) { var pos = 0; var len = str.length; if (len % 2 !== 0) { return null; } len /= 2; var hexA = []; for (var i = 0; i < len; i++) { var s = str.substr(pos, 2); if (s === '0x' || s === '0X') { pos += 2; continue; } var v = parseInt(s, 16); hexA.push(v); pos += 2; } return hexA; } // 字节数组转十六进制字符串 function Bytes2Str(arr) { var str = ''; for (var i = 0; i < arr.length; i++) { var tmp = arr[i].toString(16); if (tmp.length === 1) { tmp = '0' + tmp; } str += tmp; } return str; } // 解析 function DecodeAddress(hrp, address) { var ret = decode(hrp, address); if (ret === null) { return null; } return Bytes2Str(ret.program); // console.log("decode result ==> " + Bytes2Str(ret.program)); } // function EncodeAddress(hrp, strAddress) { var program = Str2Bytes(strAddress); var ret = encode(hrp, program); // console.log("encode result ==> " + ret); return ret; } },{"./bech32":6}],9:[function(require,module,exports){ (function (Buffer){(function (){ 'use strict'; /* eslint-disable */ /* Primary Attribution Richard Moore <ricmoo@me.com> https://github.com/ethers-io Note, Richard is a god of ether gods. Follow and respect him, and use Ethers.io! */ var utils = require('./utils/index.js'); var uint256Coder = utils.uint256Coder; var ethUtil = require('@alayanetwork/ethereumjs-util'); var coderBoolean = utils.coderBoolean; var coderFixedBytes = utils.coderFixedBytes; var coderAddress = utils.coderAddress; var coderDynamicBytes = utils.coderDynamicBytes; var coderString = utils.coderString; var coderArray = utils.coderArray; var paramTypePart = utils.paramTypePart; var getParamCoder = utils.getParamCoder; function Result() {} function encodeParams(types, values) { if (types.length !== values.length) { throw new Error('[ethjs-abi] while encoding params, types/values mismatch, Your contract requires ' + types.length + ' types (arguments), and you passed in ' + values.length); } var parts = []; types.forEach(function (type, index) { var coder = getParamCoder(type); if (type === 'address') { values[index] = ethUtil.decodeBech32Address(values[index]); } parts.push({ dynamic: coder.dynamic, value: coder.encode(values[index]) }); }); function alignSize(size) { return parseInt(32 * Math.ceil(size / 32)); } var staticSize = 0, dynamicSize = 0; parts.forEach(function (part) { if (part.dynamic) { staticSize += 32; dynamicSize += alignSize(part.value.length); } else { staticSize += alignSize(part.value.length); } }); var offset = 0, dynamicOffset = staticSize; var data = new Buffer(staticSize + dynamicSize); parts.forEach(function (part, index) { if (part.dynamic) { uint256Coder.encode(dynamicOffset).copy(data, offset); offset += 32; part.value.copy(data, dynamicOffset); dynamicOffset += alignSize(part.value.length); } else { part.value.copy(data, offset); offset += alignSize(part.value.length); } }); return '0x' + data.toString('hex'); } // decode bytecode data from output names and types function decodeParams(names, types, data) { var useNumberedParams = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; // Names is optional, so shift over all the parameters if not provided if (arguments.length < 3) { data = types; types = names; names = []; } data = utils.hexOrBuffer(data); var values = new Result(); var offset = 0; types.forEach(function (type, index) { var coder = getParamCoder(type); if (coder.dynamic) { var dynamicOffset = uint256Coder.decode(data, offset); var result = coder.decode(data, dynamicOffset.value.toNumber()); offset += dynamicOffset.consumed; } else { var result = coder.decode(data, offset); offset += result.consumed; } if (useNumberedParams) { values[index] = result.value; } if (names[index]) { values[names[index]] = result.value; } }); return values; } // create an encoded method signature from an ABI object function encodeSignature(method) { var signature = method.name + '(' + utils.getKeys(method.inputs, 'type').join(',') + ')'; var signatureEncoded = '0x' + new Buffer(utils.keccak256(signature), 'hex').slice(0, 4).toString('hex'); return signatureEncoded; } // encode method ABI object with values in an array, output bytecode function encodeMethod(method, values) { var paramsEncoded = encodeParams(utils.getKeys(method.inputs, 'type'), values).substring(2); return '' + encodeSignature(method) + paramsEncoded; } // decode method data bytecode, from method ABI object function decodeMethod(method, data) { var outputNames = utils.getKeys(method.outputs, 'name', true); var outputTypes = utils.getKeys(method.outputs, 'type'); return decodeParams(outputNames, outputTypes, utils.hexOrBuffer(data)); } // decode method data bytecode, from method ABI object function encodeEvent(eventObject, values) { return encodeMethod(eventObject, values); } function eventSignature(eventObject) { var signature = eventObject.name + '(' + utils.getKeys(eventObject.inputs, 'type').join(',') + ')'; return '0x' + utils.keccak256(signature); } // decode method data bytecode, from method ABI object function decodeEvent(eventObject, data, topics) { var useNumberedParams = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; var nonIndexed = eventObject.inputs.filter(function (input) { return !input.indexed; }); var nonIndexedNames = utils.getKeys(nonIndexed, 'name', true); var nonIndexedTypes = utils.getKeys(nonIndexed, 'type'); var event = decodeParams(nonIndexedNames, nonIndexedTypes, utils.hexOrBuffer(data), useNumberedParams); var topicOffset = eventObject.anonymous ? 0 : 1; eventObject.inputs.filter(function (input) { return input.indexed; }).map(function (input, i) { var topic = new Buffer(topics[i + topicOffset].slice(2), 'hex'); var coder = getParamCoder(input.type); event[input.name] = coder.decode(topic, 0).value; }); event._eventName = eventObject.name; return event; } // Decode a specific log item with a specific event abi function decodeLogItem(eventObject, log) { var useNumberedParams = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; if (eventObject && log.topics[0] === eventSignature(eventObject)) { return decodeEvent(eventObject, log.data, log.topics, useNumberedParams); } } // Create a decoder for all events defined in an abi. It returns a function which is called // on an array of log entries such as received from getLogs or getTransactionReceipt and parses // any matching log entries function logDecoder(abi) { var useNumberedParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var eventMap = {}; abi.filter(function (item) { return item.type === 'event'; }).map(function (item) { eventMap[eventSignature(item)] = item; }); return function (logItems) { return logItems.map(function (log) { return decodeLogItem(eventMap[log.topics[0]], log, useNumberedParams); }).filter(function (i) { return i; }); }; } module.exports = { encodeParams: encodeParams, decodeParams: decodeParams, encodeMethod: encodeMethod, decodeMethod: decodeMethod, encodeEvent: encodeEvent, decodeEvent: decodeEvent, decodeLogItem: decodeLogItem, logDecoder: logDecoder, eventSignature: eventSignature, encodeSignature: encodeSignature }; }).call(this)}).call(this,require("buffer").Buffer) },{"./utils/index.js":10,"@alayanetwork/ethereumjs-util":7,"buffer":211}],10:[function(require,module,exports){ (function (Buffer){(function (){ 'use strict'; /* Primary Attribution Richard Moore <ricmoo@me.com> https://github.com/ethers-io Note, Richard is a god of ether gods. Follow and respect him, and use Ethers.io! */ var BN = require('bn.js'); var numberToBN = require('number-to-bn'); var keccak256 = require('js-sha3').keccak_256; // from ethereumjs-util function stripZeros(aInput) { var a = aInput; // eslint-disable-line var first = a[0]; // eslint-disable-line while (a.length > 0 && first.toString() === '0') { a = a.slice(1); first = a[0]; } return a; } function bnToBuffer(bnInput) { var bn = bnInput; // eslint-disable-line var hex = bn.toString(16); // eslint-disable-line if (hex.length % 2) { hex = '0' + hex; } return stripZeros(new Buffer(hex, 'hex')); } function isHexString(value, length) { if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) { return false; } if (length && value.length !== 2 + 2 * length) { return false; } return true; } function hexOrBuffer(valueInput, name) { var value = valueInput; // eslint-disable-line if (!Buffer.isBuffer(value)) { if (!isHexString(value)) { var error = new Error(name ? '[ethjs-abi] invalid ' + name : '[ethjs-abi] invalid hex or buffer, must be a prefixed alphanumeric even length hex string'); error.reason = '[ethjs-abi] invalid hex string, hex must be prefixed and alphanumeric (e.g. 0x023..)'; error.value = value; throw error; } value = value.substring(2); if (value.length % 2) { value = '0' + value; } value = new Buffer(value, 'hex'); } return value; } function hexlify(value) { if (typeof value === 'number') { return '0x' + bnToBuffer(new BN(value)).toString('hex'); } else if (value.mod || value.modulo) { return '0x' + bnToBuffer(value).toString('hex'); } else { // eslint-disable-line return '0x' + hexOrBuffer(value).toString('hex'); } } // getKeys([{a: 1, b: 2}, {a: 3, b: 4}], 'a') => [1, 3] function getKeys(params, key, allowEmpty) { var result = []; // eslint-disable-line if (!Array.isArray(params)) { throw new Error('[ethjs-abi] while getting keys, invalid params value ' + JSON.stringify(params)); } for (var i = 0; i < params.length; i++) { // eslint-disable-line var value = params[i][key]; // eslint-disable-line if (allowEmpty && !value) { value = ''; } else if (typeof value !== 'string') { throw new Error('[ethjs-abi] while getKeys found invalid ABI data structure, type value not string'); } result.push(value); } return result; } function coderNumber(size, signed) { return { encode: function encodeNumber(valueInput) { var value = valueInput; // eslint-disable-line if (typeof value === 'object' && value.toString && (value.toTwos || value.dividedToIntegerBy)) { value = value.toString(10).split('.')[0]; } if (typeof value === 'string' || typeof value === 'number') { value = String(value).split('.')[0]; } value = numberToBN(value); value = value.toTwos(size * 8).maskn(size * 8); if (signed) { value = value.fromTwos(size * 8).toTwos(256); } return value.toArrayLike(Buffer, 'be', 32); }, decode: function decodeNumber(data, offset) { var junkLength = 32 - size; // eslint-disable-line var value = new BN(data.slice(offset + junkLength, offset + 32)); // eslint-disable-line if (signed) { value = value.fromTwos(size * 8); } else { value = value.maskn(size * 8); } return { consumed: 32, value: new BN(value.toString(10)) }; } }; } var uint256Coder = coderNumber(32, false); var coderBoolean = { encode: function encodeBoolean(value) { return uint256Coder.encode(value ? 1 : 0); }, decode: function decodeBoolean(data, offset) { var result = uint256Coder.decode(data, offset); // eslint-disable-line return { consumed: result.consumed, value: !result.value.isZero() }; } }; function coderFixedBytes(length) { return { encode: function encodeFixedBytes(valueInput) { var value = valueInput; // eslint-disable-line value = hexOrBuffer(value); if (value.length === 32) { return value; } var result = new Buffer(32); // eslint-disable-line result.fill(0); value.copy(result); return result; }, decode: function decodeFixedBytes(data, offset) { if (data.length !== 0 && data.length < offset + 32) { throw new Error('[ethjs-abi] while decoding fixed bytes, invalid bytes data length: ' + length); } return { consumed: 32, value: '0x' + data.slice(offset, offset + length).toString('hex') }; } }; } var coderAddress = { encode: function encodeAddress(valueInput) { var value =