212 lines
8.3 KiB
JavaScript
212 lines
8.3 KiB
JavaScript
|
"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;
|