"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.makeEthereumWalletSigner = exports.ethToSwarmAddress = exports.fromLittleEndian = exports.toLittleEndian = exports.isHexEthAddress = exports.makeHexEthAddress = exports.makeEthAddress = void 0; // For ESM compatibility const js_sha3_1 = __importDefault(require("js-sha3")); const { keccak256, sha3_256 } = js_sha3_1.default; const hex_1 = require("./hex"); const bytes_1 = require("./bytes"); const ETH_ADDR_BYTES_LENGTH = 20; const ETH_ADDR_HEX_LENGTH = 40; function makeEthAddress(address) { if (typeof address === 'string') { const hexAddr = (0, hex_1.makeHexString)(address, ETH_ADDR_HEX_LENGTH); const ownerBytes = (0, hex_1.hexToBytes)(hexAddr); (0, bytes_1.assertBytes)(ownerBytes, ETH_ADDR_BYTES_LENGTH); return ownerBytes; } else if (address instanceof Uint8Array) { (0, bytes_1.assertBytes)(address, ETH_ADDR_BYTES_LENGTH); return address; } throw new TypeError('Invalid EthAddress'); } exports.makeEthAddress = makeEthAddress; function makeHexEthAddress(address) { try { return (0, hex_1.makeHexString)(address, ETH_ADDR_HEX_LENGTH); } catch (e) { if (e instanceof TypeError) { e.message = `Invalid HexEthAddress: ${e.message}`; } throw e; } } exports.makeHexEthAddress = makeHexEthAddress; /** * Check if this is all caps or small caps eth address (=address without checksum) * * @param address Ethereum address as hex string */ function isEthAddrCaseIns(address) { // Check it's string, all small caps or all all caps hex and 40 chars long without the `0x` prefix return (typeof address === 'string' && (/^(0x|0X)?[0-9a-f]{40}$/.test(address) || /^(0x|0X)?[0-9A-F]{40}$/.test(address))); } /** * Check if this is checksummed ethereum address * * @param address Ethereum address as hex string */ function isValidChecksummedEthAddress(address) { try { // Check for valid case insensitive hex type string, 40 chars const addr = (0, hex_1.makeHexString)(address, ETH_ADDR_HEX_LENGTH); // Check the checksum const addressHash = keccak256(addr.toLowerCase()); for (let i = 0; i < 40; i += 1) { // the nth letter should be uppercase if the nth digit of casemap is 1 if ((parseInt(addressHash[i], 16) > 7 && addr[i].toUpperCase() !== addr[i]) || (parseInt(addressHash[i], 16) <= 7 && addr[i].toLowerCase() !== addr[i])) { return false; } } return true; } catch (e) { if (e instanceof TypeError) { return false; } throw e; } } /** * Check if is valid ethereum address * * Pretty much typed version from web3js * https://github.com/ChainSafe/web3.js/blob/1.x/packages/web3-utils/src/utils.js * * @param address Ethereum address as hex string * * @return True if is valid eth address */ function isHexEthAddress(address) { return isEthAddrCaseIns(address) || isValidChecksummedEthAddress(address); } exports.isHexEthAddress = isHexEthAddress; /** * Convert big-endian hex or number to little-endian. * Note: Before conversion it is automatically padded to even length hexstring * * @param bigEndian Big-endian hex string or number to convert * @param pad Length to which the string should be padded before conversion (defaul: 2) * * @return little-endian encoded hexstring */ function toLittleEndian(bigEndian, pad = 2) { var _a; if (!(Number.isInteger(pad) && pad >= 2 && pad % 2 === 0)) { throw new TypeError('minimal padding for conversion needs to be positive even integer'); } let hexRep; if (typeof bigEndian === 'string') hexRep = (0, hex_1.makeHexString)(bigEndian); else if (typeof bigEndian === 'number') hexRep = (0, hex_1.intToHex)(bigEndian); else throw new TypeError('incorrect input type'); hexRep = hexRep.padStart(pad, '0'); // Extend to an even length hexstring if (hexRep.length % 2 !== 0) hexRep = hexRep.padStart(hexRep.length + 1, '0'); // Match all two pairs in the hexstring, reverse the pairs and join it again const littleEndian = (_a = hexRep.match(/../g)) === null || _a === void 0 ? void 0 : _a.reverse().join(''); if (littleEndian) return littleEndian; throw new Error('failed to convert'); } exports.toLittleEndian = toLittleEndian; /** * Convert little-endian hex or number to big-endian * Note: Before conversion it is automatically padded to even length hexstring * * @param littleEndian Little-endian hex string or number to convert * @param pad Length to which the string should be padded before conversion (defaul: 2) * * @return big-endian encoded hexstring */ function fromLittleEndian(littleEndian, pad = 2) { // It's a reversible function return toLittleEndian(littleEndian, pad); } exports.fromLittleEndian = fromLittleEndian; function assertEthAddress(ethAddress) { if (!isHexEthAddress(ethAddress)) throw new TypeError('invalid ETH address'); } function assertSwarmNetworkId(networkId) { if (Number.isInteger(networkId && networkId > 0 && networkId < Number.MAX_SAFE_INTEGER)) { throw new TypeError('swarm network id must be positive integer'); } } /** * Get swarm overlay address from public ethereum address and swarm network id * * @param ethAddress Public ethereum address * @param networkId Swarm network id * * @return Swarm overlay address */ function ethToSwarmAddress(ethAddress, networkId = 1) { assertEthAddress(ethAddress); assertSwarmNetworkId(networkId); const hex = `${(0, hex_1.makeHexString)(ethAddress)}${toLittleEndian(networkId, 16)}`; (0, hex_1.assertHexString)(hex); const overlayAddress = sha3_256((0, hex_1.hexToBytes)(hex)); return overlayAddress; } exports.ethToSwarmAddress = ethToSwarmAddress; /** * Function that takes Ethereum EIP-1193 compatible provider and create an Signer instance that * uses `personal_sign` method to sign requested data. * * @param provider Injected web3 provider like window.ethereum or other compatible with EIP-1193 * @param ethAddress Optional address of the account which the data should be signed with. If not specified `eth_requestAccounts` request is used to get the account address. */ function makeEthereumWalletSigner(provider, ethAddress) { return __awaiter(this, void 0, void 0, function* () { let executorFnc; if (typeof provider !== 'object' || provider === null) { throw new TypeError('We need JsonRPC provider object!'); } if (provider.request) { executorFnc = provider.request; } else if (provider.sendAsync) { executorFnc = provider.sendAsync; } else { throw new Error('Incompatible interface of given provider!'); } if (!ethAddress) { ethAddress = (yield executorFnc({ method: 'eth_requestAccounts' }))[0]; } const bytesEthAddress = makeEthAddress(ethAddress); const hexEthAddress = makeHexEthAddress(ethAddress); return { address: bytesEthAddress, sign: (data) => __awaiter(this, void 0, void 0, function* () { const result = yield executorFnc({ jsonrpc: '2.0', method: 'personal_sign', params: ['0x' + data.hex(), '0x' + hexEthAddress], }); return result; }), }; }); } exports.makeEthereumWalletSigner = makeEthereumWalletSigner;