From a9aaeefe24a4472e9b1855e1124edc9a6f3ef567 Mon Sep 17 00:00:00 2001 From: ricmoo Date: Tue, 23 Aug 2016 20:12:12 -0400 Subject: [PATCH] Moved address functions to utils (things without need ofr signing do not need all the extra requires). --- index.js | 8 ++-- lib/providers.js | 23 ++++++---- lib/secret-storage.js | 4 +- lib/signing-key.js | 103 +----------------------------------------- lib/utils.js | 102 +++++++++++++++++++++++++++++++++++++++++ lib/wallet.js | 6 +-- 6 files changed, 123 insertions(+), 123 deletions(-) diff --git a/index.js b/index.js index 1b4ec10e..d5f9cdb0 100644 --- a/index.js +++ b/index.js @@ -26,8 +26,8 @@ utils.defineProperty(exportUtils, 'sha256', utils.sha256); // http://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed utils.defineProperty(exportUtils, 'getContractAddress', function(transaction) { - return SigningKey.getAddress('0x' + utils.sha3(rlp.encode([ - utils.hexOrBuffer(SigningKey.getAddress(transaction.from)), + return utils.getAddress('0x' + utils.sha3(rlp.encode([ + utils.hexOrBuffer(utils.getAddress(transaction.from)), utils.hexOrBuffer(utils.hexlify(transaction.nonce, 'nonce')) ])).slice(12).toString('hex')); }); @@ -40,8 +40,8 @@ utils.defineProperty(Wallet, 'etherSymbol', '\uD835\uDF63'); utils.defineProperty(Wallet, 'formatEther', units.formatEther); utils.defineProperty(Wallet, 'parseEther', units.parseEther); -//utils.defineProperty(Wallet, 'getAddress', SigningKey.getAddress); -//utils.defineProperty(Wallet, 'getIcapAddress', SigningKey.getIcapAddress); +utils.defineProperty(Wallet, 'getAddress', utils.getAddress); +utils.defineProperty(Wallet, 'getIcapAddress', utils.getIcapAddress); utils.defineProperty(Wallet, 'isCrowdsaleWallet', secretStorage.isCrowdsaleWallet); utils.defineProperty(Wallet, 'isValidWallet', secretStorage.isValidWallet); diff --git a/lib/providers.js b/lib/providers.js index cdd6a494..62e26998 100644 --- a/lib/providers.js +++ b/lib/providers.js @@ -3,7 +3,6 @@ var inherits = require('inherits'); var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; -var SigningKey = require('./signing-key.js'); var utils = require('./utils.js'); // The required methods a provider must support @@ -120,13 +119,17 @@ function postProcess(client, method, params, makeBN) { } utils.defineProperty(SendAsyncProvider.prototype, 'getBalance', function(address, blockNumber) { - address = SigningKey.getAddress(address); - return postProcess(this.client, 'eth_getBalance', [address, validBlock(blockNumber)], true); + return postProcess(this.client, 'eth_getBalance', [ + utils.getAddress(address), + validBlock(blockNumber) + ], true); }); utils.defineProperty(SendAsyncProvider.prototype, 'getTransactionCount', function(address, blockNumber) { - address = SigningKey.getAddress(address); - return postProcess(this.client, 'eth_getTransactionCount', [address, validBlock(blockNumber)], false); + return postProcess(this.client, 'eth_getTransactionCount', [ + utils.getAddress(address), + validBlock(blockNumber) + ], false); }); utils.defineProperty(SendAsyncProvider.prototype, 'getGasPrice', function() { @@ -260,14 +263,14 @@ function EtherscanProvider(options) { utils.defineProperty(providers, 'EtherscanProvider', EtherscanProvider); utils.defineProperty(EtherscanProvider.prototype, 'getBalance', function(address, blockNumber) { - address = SigningKey.getAddress(address); + address = utils.getAddress(address); blockNumber = validBlock(blockNumber); var query = ('module=account&action=balance&address=' + address + '&tag=' + blockNumber); return this._send(query, base10ToBN); }); utils.defineProperty(EtherscanProvider.prototype, 'getTransactionCount', function(address, blockNumber) { - address = SigningKey.getAddress(address); + address = utils.getAddress(address); blockNumber = validBlock(blockNumber); var query = ('module=proxy&action=eth_getTransactionCount&address=' + address + '&tag=' + blockNumber); return this._send(query, hexToNumber); @@ -285,7 +288,7 @@ utils.defineProperty(EtherscanProvider.prototype, 'sendTransaction', function(si }); utils.defineProperty(EtherscanProvider.prototype, 'call', function(transaction) { - var address = SigningKey.getAddress(transaction.to); + var address = utils.getAddress(transaction.to); var data = transaction.data; if (!utils.isHexString(data)) { throw new Error('invalid data'); } var query = ('module=proxy&action=eth_call&to=' + address + '&data=' + data); @@ -293,7 +296,7 @@ utils.defineProperty(EtherscanProvider.prototype, 'call', function(transaction) }); utils.defineProperty(EtherscanProvider.prototype, 'estimateGas', function(transaction) { - var address = SigningKey.getAddress(transaction.to); + var address = utils.getAddress(transaction.to); var query = 'module=proxy&action=eth_estimateGas&to=' + address; if (transaction.gasPrice) { @@ -303,7 +306,7 @@ utils.defineProperty(EtherscanProvider.prototype, 'estimateGas', function(transa query += '&gas=' + utils.hexlify(transaction.gasLimit); } if (transaction.from) { - query += '&from=' + SigningKey.getAddress(transaction.from); + query += '&from=' + utils.getAddress(transaction.from); } if (transaction.data) { query += '&data=' + ensureHex(transaction.data); diff --git a/lib/secret-storage.js b/lib/secret-storage.js index 0cde8734..0f4237a3 100644 --- a/lib/secret-storage.js +++ b/lib/secret-storage.js @@ -82,7 +82,7 @@ utils.defineProperty(secretStorage, 'decryptCrowdsale', function(json, password) var data = JSON.parse(json); // Ethereum Address - var ethaddr = SigningKey.getAddress(searchPath(data, 'ethaddr')); + var ethaddr = utils.getAddress(searchPath(data, 'ethaddr')); // Encrypted Seed var encseed = new Buffer(searchPath(data, 'encseed'), 'hex'); @@ -203,7 +203,7 @@ utils.defineProperty(secretStorage, 'decrypt', function(json, password, progress } var signingKey = new SigningKey(privateKey); - if (signingKey.address !== SigningKey.getAddress(data.address)) { + if (signingKey.address !== utils.getAddress(data.address)) { reject(new Error('address mismatch')); return; } diff --git a/lib/signing-key.js b/lib/signing-key.js index b76f9c08..209fe25e 100644 --- a/lib/signing-key.js +++ b/lib/signing-key.js @@ -7,98 +7,6 @@ var utils = require('./utils.js'); var secp256k1 = new (elliptic.ec)('secp256k1'); -function getChecksumAddress(address) { - if (typeof(address) !== 'string' || !address.match(/^0x[0-9A-Fa-f]{40}$/)) { - throw new Error('invalid address'); - } - - address = address.substring(2).toLowerCase(); - var hashed = utils.sha3(address); - - address = address.split(''); - for (var i = 0; i < 40; i += 2) { - if ((hashed[i >> 1] >> 4) >= 8) { - address[i] = address[i].toUpperCase(); - } - if ((hashed[i >> 1] & 0x0f) >= 8) { - address[i + 1] = address[i + 1].toUpperCase(); - } - } - - return '0x' + address.join(''); -} - -function getAddress(address) { - var result = null; - - if (typeof(address) !== 'string') { throw new Error('invalid address'); } - - if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) { - - // Missing the 0x prefix - if (address.substring(0, 2) !== '0x') { address = '0x' + address; } - - result = getChecksumAddress(address); - - // It is a checksummed address with a bad checksum - if (address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) && result !== address) { - throw new Error('invalid address checksum'); - } - - // Maybe ICAP? (we only support direct mode) - } else if (address.match(/^XE[0-9]{2}[0-9A-Za-z]{30,31}$/)) { - - // It is an ICAP address with a bad checksum - if (address.substring(2, 4) !== ibanChecksum(address)) { - throw new Error('invalid address icap checksum'); - } - - result = (new utils.BN(address.substring(4), 36)).toString(16); - while (result.length < 40) { result = '0' + result; } - result = getChecksumAddress('0x' + result); - - } else { - throw new Error('invalid address'); - } - - return result; -} - -// See: https://en.wikipedia.org/wiki/International_Bank_Account_Number -var ibanChecksum = (function() { - - // Create lookup table - var ibanLookup = {}; - for (var i = 0; i < 10; i++) { ibanLookup[String(i)] = String(i); } - for (var i = 0; i < 26; i++) { ibanLookup[String.fromCharCode(65 + i)] = String(10 + i); } - - // How many decimal digits can we process? (for 64-bit float, this is 15) - var safeDigits = Math.floor(Math.log10(Number.MAX_SAFE_INTEGER)); - - return function(address) { - address = address.toUpperCase(); - address = address.substring(4) + address.substring(0, 2) + '00'; - - var expanded = address.split(''); - for (var i = 0; i < expanded.length; i++) { - expanded[i] = ibanLookup[expanded[i]]; - } - expanded = expanded.join(''); - - // Javascript can handle integers safely up to 15 (decimal) digits - while (expanded.length >= safeDigits){ - var block = expanded.substring(0, safeDigits); - expanded = parseInt(block, 10) % 97 + expanded.substring(block.length); - } - - var checksum = String(98 - (parseInt(expanded, 10) % 97)); - while (checksum.length < 2) { checksum = '0' + checksum; } - - return checksum; - }; -})(); - - function SigningKey(privateKey) { if (!(this instanceof SigningKey)) { throw new Error('missing new'); } @@ -112,7 +20,7 @@ function SigningKey(privateKey) { var keyPair = secp256k1.keyFromPrivate(privateKey); var publicKey = (new Buffer(keyPair.getPublic(false, 'hex'), 'hex')).slice(1); - var address = getAddress(utils.sha3(publicKey).slice(12).toString('hex')); + var address = utils.getAddress(utils.sha3(publicKey).slice(12).toString('hex')); utils.defineProperty(this, 'address', address) utils.defineProperty(this, 'signDigest', function(digest) { @@ -120,14 +28,5 @@ function SigningKey(privateKey) { }); } -utils.defineProperty(SigningKey, 'getAddress', getAddress); - -utils.defineProperty(SigningKey, 'getIcapAddress', function(address) { - address = getAddress(address).substring(2); - var base36 = (new utils.BN(address, 16)).toString(36).toUpperCase(); - while (base36.length < 30) { base36 = '0' + base36; } - return 'XE' + ibanChecksum('XE00' + base36) + base36; -}); - module.exports = SigningKey; diff --git a/lib/utils.js b/lib/utils.js index d3c4d0dd..7249c0cd 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -213,6 +213,105 @@ function defineProperty(object, name, value) { }); } +function getChecksumAddress(address) { + if (typeof(address) !== 'string' || !address.match(/^0x[0-9A-Fa-f]{40}$/)) { + throw new Error('invalid address'); + } + + address = address.substring(2).toLowerCase(); + var hashed = sha3(address); + + address = address.split(''); + for (var i = 0; i < 40; i += 2) { + if ((hashed[i >> 1] >> 4) >= 8) { + address[i] = address[i].toUpperCase(); + } + if ((hashed[i >> 1] & 0x0f) >= 8) { + address[i + 1] = address[i + 1].toUpperCase(); + } + } + + return '0x' + address.join(''); +} + +function getAddress(address) { + var result = null; + + if (typeof(address) !== 'string') { throw new Error('invalid address'); } + + if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) { + + // Missing the 0x prefix + if (address.substring(0, 2) !== '0x') { address = '0x' + address; } + + result = getChecksumAddress(address); + + // It is a checksummed address with a bad checksum + if (address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) && result !== address) { + throw new Error('invalid address checksum'); + } + + // Maybe ICAP? (we only support direct mode) + } else if (address.match(/^XE[0-9]{2}[0-9A-Za-z]{30,31}$/)) { + + // It is an ICAP address with a bad checksum + if (address.substring(2, 4) !== ibanChecksum(address)) { + throw new Error('invalid address icap checksum'); + } + + result = (new BN(address.substring(4), 36)).toString(16); + while (result.length < 40) { result = '0' + result; } + result = getChecksumAddress('0x' + result); + + } else { + throw new Error('invalid address'); + } + + return result; +} + +// See: https://en.wikipedia.org/wiki/International_Bank_Account_Number +var ibanChecksum = (function() { + + // Create lookup table + var ibanLookup = {}; + for (var i = 0; i < 10; i++) { ibanLookup[String(i)] = String(i); } + for (var i = 0; i < 26; i++) { ibanLookup[String.fromCharCode(65 + i)] = String(10 + i); } + + // How many decimal digits can we process? (for 64-bit float, this is 15) + var safeDigits = Math.floor(Math.log10(Number.MAX_SAFE_INTEGER)); + + return function(address) { + address = address.toUpperCase(); + address = address.substring(4) + address.substring(0, 2) + '00'; + + var expanded = address.split(''); + for (var i = 0; i < expanded.length; i++) { + expanded[i] = ibanLookup[expanded[i]]; + } + expanded = expanded.join(''); + + // Javascript can handle integers safely up to 15 (decimal) digits + while (expanded.length >= safeDigits){ + var block = expanded.substring(0, safeDigits); + expanded = parseInt(block, 10) % 97 + expanded.substring(block.length); + } + + var checksum = String(98 - (parseInt(expanded, 10) % 97)); + while (checksum.length < 2) { checksum = '0' + checksum; } + + return checksum; + }; +})(); + + +function getIcapAddress(address) { + address = getAddress(address).substring(2); + var base36 = (new BN(address, 16)).toString(36).toUpperCase(); + while (base36.length < 30) { base36 = '0' + base36; } + return 'XE' + ibanChecksum('XE00' + base36) + base36; +} + function cloneObject(object) { var clone = {}; for (var key in object) { clone[key] = object[key]; } @@ -275,6 +374,9 @@ module.exports = { defineProperty: defineProperty, + getAddress: getAddress, + getIcapAddress: getIcapAddress, + cloneObject: cloneObject, bnToBuffer: bnToBuffer, diff --git a/lib/wallet.js b/lib/wallet.js index 03729ac9..c4e5681e 100644 --- a/lib/wallet.js +++ b/lib/wallet.js @@ -205,7 +205,7 @@ utils.defineProperty(Wallet.prototype, 'sendTransaction', function(transaction) }); utils.defineProperty(Wallet.prototype, 'send', function(address, amountWei, options) { - address = SigningKey.getAddress(address); + address = utils.getAddress(address); if (utils.BN.isBN(amountWei)) { amountWei = '0x' + utils.bnToBuffer(amountWei).toString('hex'); } @@ -226,10 +226,6 @@ utils.defineProperty(Wallet.prototype, 'getContract', function(address, abi) { return new Contract(this, address, new Contract.Interface(abi)); }); - -utils.defineProperty(Wallet, 'getAddress', SigningKey.getAddress); -utils.defineProperty(Wallet, 'getIcapAddress', SigningKey.getIcapAddress); - utils.defineProperty(Wallet, '_Contract', Contract); module.exports = Wallet;