micro-eth-signer
Advanced tools
Comparing version 0.4.8 to 0.5.0
@@ -16,2 +16,4 @@ /*! micro-eth-signer - MIT License (c) Paul Miller (paulmillr.com) */ | ||
export declare function strip0x(hex: string): string; | ||
export declare function hexToBytes(hex: string): Uint8Array; | ||
export declare function numberTo0xHex(num: number | bigint): string; | ||
declare type Chain = keyof typeof CHAIN_TYPES; | ||
@@ -81,1 +83,2 @@ declare type Type = keyof typeof TRANSACTION_TYPES; | ||
export {}; | ||
//# sourceMappingURL=index.d.ts.map |
111
index.js
@@ -1,22 +0,31 @@ | ||
"use strict"; | ||
/*! micro-eth-signer - MIT License (c) Paul Miller (paulmillr.com) */ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Transaction = exports.Address = exports.strip0x = exports.add0x = exports.TRANSACTION_TYPES = exports.CHAIN_TYPES = void 0; | ||
const sha3_1 = require("@noble/hashes/sha3"); | ||
const utils_1 = require("@noble/hashes/utils"); | ||
const secp256k1 = require("@noble/secp256k1"); | ||
const rlp_1 = require("rlp"); | ||
exports.CHAIN_TYPES = { mainnet: 1, ropsten: 3, rinkeby: 4, goerli: 5, kovan: 42 }; | ||
exports.TRANSACTION_TYPES = { legacy: 0, eip2930: 1, eip1559: 2 }; | ||
function add0x(hex) { | ||
import { keccak_256 } from '@noble/hashes/sha3'; | ||
import { bytesToHex, hexToBytes as _hexToBytes } from '@noble/hashes/utils'; | ||
import * as secp256k1 from '@noble/secp256k1'; | ||
import RLP from 'rlp'; | ||
export const CHAIN_TYPES = { mainnet: 1, ropsten: 3, rinkeby: 4, goerli: 5, kovan: 42 }; | ||
export const TRANSACTION_TYPES = { legacy: 0, eip2930: 1, eip1559: 2 }; | ||
export function add0x(hex) { | ||
return /^0x/i.test(hex) ? hex : `0x${hex}`; | ||
} | ||
exports.add0x = add0x; | ||
function strip0x(hex) { | ||
export function strip0x(hex) { | ||
return hex.replace(/^0x/i, ''); | ||
} | ||
exports.strip0x = strip0x; | ||
export function hexToBytes(hex) { | ||
return _hexToBytes(strip0x(hex)); | ||
} | ||
export function numberTo0xHex(num) { | ||
const hex = num.toString(16); | ||
const x2 = hex.length & 1 ? `0${hex}` : hex; | ||
return add0x(x2); | ||
} | ||
function hexToNumber(hex) { | ||
if (typeof hex !== 'string') { | ||
throw new TypeError('hexToNumber: expected string, got ' + typeof hex); | ||
} | ||
return hex ? BigInt(add0x(hex)) : 0n; | ||
} | ||
function cloneDeep(obj) { | ||
if (Array.isArray(obj)) { | ||
return obj.map((i) => cloneDeep(i)); | ||
return obj.map(cloneDeep); | ||
} | ||
@@ -35,21 +44,2 @@ else if (typeof obj === 'bigint') { | ||
} | ||
const padHex = (hex) => (hex.length & 1 ? `0${hex}` : hex); | ||
function hexToBytes(hex) { | ||
hex = padHex(strip0x(hex)); | ||
const array = new Uint8Array(hex.length / 2); | ||
for (let i = 0; i < array.length; i++) { | ||
const j = i * 2; | ||
array[i] = Number.parseInt(hex.slice(j, j + 2), 16); | ||
} | ||
return array; | ||
} | ||
function numberToHex(num) { | ||
return padHex(num.toString(16)); | ||
} | ||
function hexToNumber(hex) { | ||
if (typeof hex !== 'string') { | ||
throw new TypeError('hexToNumber: expected string, got ' + typeof hex); | ||
} | ||
return hex ? BigInt(add0x(hex)) : 0n; | ||
} | ||
const FIELDS = ['nonce', 'gasPrice', 'gasLimit', 'to', 'value', 'data', 'v', 'r', 's']; | ||
@@ -77,3 +67,3 @@ const FIELDS2930 = [ | ||
if (value instanceof Uint8Array) | ||
value = add0x((0, utils_1.bytesToHex)(value)); | ||
value = add0x(bytesToHex(value)); | ||
if (field === 'yParity' && typeof value === 'boolean') | ||
@@ -84,3 +74,3 @@ value = value ? '0x1' : '0x0'; | ||
if (typeof value === 'number' || typeof value === 'bigint') | ||
value = add0x(padHex(value.toString(16))); | ||
value = numberTo0xHex(value); | ||
if (field === 'gasLimit' && (!value || BigInt(value) === 0n)) | ||
@@ -98,3 +88,3 @@ value = '0x5208'; | ||
if (value instanceof Uint8Array) | ||
value = (0, utils_1.bytesToHex)(value); | ||
value = bytesToHex(value); | ||
if (typeof value !== 'string') | ||
@@ -151,3 +141,3 @@ throw new TypeError(`Invalid type for field ${field}`); | ||
function possibleTypes(input) { | ||
let types = new Set(Object.keys(exports.TRANSACTION_TYPES)); | ||
let types = new Set(Object.keys(TRANSACTION_TYPES)); | ||
const keys = new Set(Object.keys(input)); | ||
@@ -169,3 +159,3 @@ if (keys.has('maxPriorityFeePerGas') || keys.has('maxFeePerGas')) { | ||
if (chain) | ||
chainId = exports.CHAIN_TYPES[chain]; | ||
chainId = CHAIN_TYPES[chain]; | ||
if (Array.isArray(input)) { | ||
@@ -192,3 +182,3 @@ if (!type) | ||
if (chain) { | ||
const fromChain = normalizeField('chainId', exports.CHAIN_TYPES[chain]); | ||
const fromChain = normalizeField('chainId', CHAIN_TYPES[chain]); | ||
const fromInput = normalizeField('chainId', input.chainId); | ||
@@ -218,10 +208,10 @@ if (fromChain !== fromInput) { | ||
throw new Error(`ChainId=${normalized[0]} incompatible with Chain=${chainId}`); | ||
const tNum = exports.TRANSACTION_TYPES[type]; | ||
return (tNum ? `0x0${tNum}` : '0x') + (0, utils_1.bytesToHex)(rlp_1.default.encode(normalized)); | ||
const tNum = TRANSACTION_TYPES[type]; | ||
return (tNum ? `0x0${tNum}` : '0x') + bytesToHex(RLP.encode(normalized)); | ||
} | ||
exports.Address = { | ||
export const Address = { | ||
fromPrivateKey(key) { | ||
if (typeof key === 'string') | ||
key = hexToBytes(key); | ||
return exports.Address.fromPublicKey(secp256k1.getPublicKey(key)); | ||
return Address.fromPublicKey(secp256k1.getPublicKey(key)); | ||
}, | ||
@@ -235,4 +225,4 @@ fromPublicKey(key) { | ||
const pub = len === 65 ? key : secp256k1.Point.fromHex(key).toRawBytes(false); | ||
const addr = (0, utils_1.bytesToHex)((0, sha3_1.keccak_256)(pub.slice(1, 65))).slice(24); | ||
return exports.Address.checksum(addr); | ||
const addr = bytesToHex(keccak_256(pub.slice(1, 65))).slice(24); | ||
return Address.checksum(addr); | ||
}, | ||
@@ -243,3 +233,3 @@ checksum(nonChecksummedAddress) { | ||
throw new Error('Invalid address, must have 40 chars'); | ||
const hash = strip0x((0, utils_1.bytesToHex)((0, sha3_1.keccak_256)(addr))); | ||
const hash = strip0x(bytesToHex(keccak_256(addr))); | ||
let checksummed = ''; | ||
@@ -261,3 +251,3 @@ for (let i = 0; i < addr.length; i++) { | ||
return true; | ||
const hash = (0, utils_1.bytesToHex)((0, sha3_1.keccak_256)(addr.toLowerCase())); | ||
const hash = bytesToHex(keccak_256(addr.toLowerCase())); | ||
for (let i = 0; i < 40; i++) { | ||
@@ -274,3 +264,3 @@ const nth = Number.parseInt(hash[i], 16); | ||
}; | ||
class Transaction { | ||
export class Transaction { | ||
constructor(data, chain, hardfork = Transaction.DEFAULT_HARDFORK, type) { | ||
@@ -283,3 +273,3 @@ this.hardfork = hardfork; | ||
else if (data instanceof Uint8Array) { | ||
norm = (0, utils_1.bytesToHex)(data); | ||
norm = bytesToHex(data); | ||
} | ||
@@ -306,3 +296,3 @@ else if (Array.isArray(data) || (typeof data === 'object' && data != null)) { | ||
this.type = type; | ||
const ui8a = rlp_1.default.decode(txData); | ||
const ui8a = RLP.decode(txData); | ||
this.raw = ui8a.reduce((res, value, i) => { | ||
@@ -322,3 +312,3 @@ const name = TypeToFields[type][i]; | ||
if (!this.raw.chainId) { | ||
this.raw.chainId = normalizeField('chainId', exports.CHAIN_TYPES[chain || Transaction.DEFAULT_CHAIN]); | ||
this.raw.chainId = normalizeField('chainId', CHAIN_TYPES[chain || Transaction.DEFAULT_CHAIN]); | ||
} | ||
@@ -334,4 +324,4 @@ this.isSigned = !!(this.raw.r && this.raw.r !== '0x'); | ||
get chain() { | ||
for (let k in exports.CHAIN_TYPES) | ||
if (exports.CHAIN_TYPES[k] === Number(this.raw.chainId)) | ||
for (let k in CHAIN_TYPES) | ||
if (CHAIN_TYPES[k] === Number(this.raw.chainId)) | ||
return k; | ||
@@ -343,3 +333,3 @@ } | ||
throw new Error('Invalid signed transaction'); | ||
return exports.Address.fromPublicKey(sender); | ||
return Address.fromPublicKey(sender); | ||
} | ||
@@ -375,3 +365,3 @@ get gasPrice() { | ||
get to() { | ||
return exports.Address.checksum(this.raw.to); | ||
return Address.checksum(this.raw.to); | ||
} | ||
@@ -397,6 +387,6 @@ get nonce() { | ||
} | ||
let encoded = rlp_1.default.encode(values); | ||
let encoded = RLP.encode(values); | ||
if (this.type !== 'legacy') | ||
encoded = new Uint8Array([exports.TRANSACTION_TYPES[this.type], ...Array.from(encoded)]); | ||
return (0, utils_1.bytesToHex)((0, sha3_1.keccak_256)(encoded)); | ||
encoded = new Uint8Array([TRANSACTION_TYPES[this.type], ...Array.from(encoded)]); | ||
return bytesToHex(keccak_256(encoded)); | ||
} | ||
@@ -420,3 +410,3 @@ get hash() { | ||
const vv = this.type === 'legacy' ? (chainId ? recovery + (chainId * 2 + 35) : recovery + 27) : recovery; | ||
const [v, r, s] = [vv, signature.r, signature.s].map((n) => add0x(numberToHex(n))); | ||
const [v, r, s] = [vv, signature.r, signature.s].map(numberTo0xHex); | ||
const signedRaw = this.type === 'legacy' | ||
@@ -430,3 +420,3 @@ ? { ...this.raw, v, r, s } | ||
throw new Error('Expected signed transaction: cannot recover sender of unsigned tx'); | ||
const [r, s] = [this.raw.r, this.raw.s].map((n) => hexToNumber(n)); | ||
const [r, s] = [this.raw.r, this.raw.s].map(hexToNumber); | ||
const sig = new secp256k1.Signature(r, s); | ||
@@ -443,5 +433,4 @@ if (this.hardfork !== 'chainstart' && sig.hasHighS()) { | ||
} | ||
exports.Transaction = Transaction; | ||
Transaction.DEFAULT_HARDFORK = 'london'; | ||
Transaction.DEFAULT_CHAIN = 'mainnet'; | ||
Transaction.DEFAULT_TYPE = 'eip1559'; |
{ | ||
"name": "micro-eth-signer", | ||
"version": "0.4.8", | ||
"version": "0.5.0", | ||
"description": "Create, sign and validate Ethereum transactions & addresses with minimum deps. Supports EIP1559", | ||
"type": "module", | ||
"main": "index.js", | ||
"module": "index.js", | ||
"files": [ | ||
"index.js", | ||
"index.d.ts" | ||
"index.d.ts", | ||
"index.d.ts.map", | ||
"index.ts", | ||
"formatters.js", | ||
"formatters.d.ts", | ||
"formatters.d.ts.map", | ||
"formatters.ts", | ||
"tx-validator.js", | ||
"tx-validator.d.ts", | ||
"tx-validator.d.ts.map", | ||
"tx-validator.ts" | ||
], | ||
"scripts": { | ||
"build": "tsc -d && rollup -c rollup.config.js", | ||
"bench": "node test/benchmark.js", | ||
"lint": "prettier --print-width 100 --single-quote --check index.ts", | ||
"test": "node test/test.js" | ||
"dependencies": { | ||
"@noble/hashes": "~1.1.2", | ||
"@noble/secp256k1": "~1.6.3", | ||
"rlp": "3.0.0" | ||
}, | ||
"devDependencies": { | ||
"@rollup/plugin-commonjs": "22.0.0", | ||
"@rollup/plugin-node-resolve": "13.3.0", | ||
"micro-bmark": "0.1.3", | ||
"micro-should": "0.1.4", | ||
"prettier": "2.6.2", | ||
"rollup": "2.75.5", | ||
"typescript": "4.7.3" | ||
}, | ||
"jest": { | ||
@@ -43,16 +63,8 @@ "testRegex": "/test/.*?\\.ts", | ||
], | ||
"dependencies": { | ||
"@noble/hashes": "~1.1.0", | ||
"@noble/secp256k1": "~1.6.0", | ||
"rlp": "3.0.0" | ||
}, | ||
"devDependencies": { | ||
"@rollup/plugin-commonjs": "22.0.0", | ||
"@rollup/plugin-node-resolve": "13.3.0", | ||
"micro-bmark": "0.1.3", | ||
"micro-should": "0.1.4", | ||
"prettier": "2.6.2", | ||
"rollup": "2.75.5", | ||
"typescript": "4.7.3" | ||
"scripts": { | ||
"build": "tsc && rollup -c rollup.config.js", | ||
"bench": "node test/benchmark.js", | ||
"lint": "prettier --print-width 100 --single-quote --check index.ts", | ||
"test": "node test/test.js" | ||
} | ||
} |
@@ -7,4 +7,11 @@ # micro-eth-signer | ||
Validated with over 3MiB of ethers.js test vectors! | ||
Validated with over 3MiB of ethers.js test vectors. | ||
Check out all web3 utility libraries: | ||
- [micro-eth-signer](https://github.com/paulmillr/micro-eth-signer) | ||
- [micro-sol-signer](https://github.com/paulmillr/micro-sol-signer) | ||
- [micro-web3](https://github.com/paulmillr/micro-web3) | ||
- [tx-tor-broadcaster](https://github.com/paulmillr/tx-tor-broadcaster) | ||
## Usage | ||
@@ -151,2 +158,19 @@ | ||
### Additional modules | ||
Those are optional: | ||
```ts | ||
import * as formatters from 'micro-eth-signer/formatters'; | ||
import { validateField, validateFields } from 'micro-eth-signer/tx-validator' | ||
// formatters: | ||
export function parseDecimal(s: string, precision: number): bigint; | ||
export function formatDecimal(n: bigint, precision: number): string; | ||
export function perCentDecimal(precision: number, price: number): bigint; | ||
export function roundDecimal(n: bigint, roundPrecision: number, precision?: number, price?: number): bigint; | ||
export function fromWei(wei: string | number | bigint): string; | ||
export function formatUSD(amount: number): string; | ||
``` | ||
## Performance | ||
@@ -153,0 +177,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
77268
15
1649
187
Yes
1
Updated@noble/hashes@~1.1.2
Updated@noble/secp256k1@~1.6.3