Socket
Socket
Sign inDemoInstall

micro-eth-signer

Package Overview
Dependencies
5
Maintainers
1
Versions
36
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.6.5 to 0.7.0

lib/_type_test.d.ts

38

package.json
{
"name": "micro-eth-signer",
"version": "0.6.5",
"description": "Create, sign and validate Ethereum transactions & addresses with minimum deps",
"type": "module",
"main": "index.js",
"module": "index.js",
"types": "index.d.ts",
"version": "0.7.0",
"description": "Small tool for Ethereum transactions, addresses and smart contracts",
"files": [
"index.js",
"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"
"lib",
"src"
],
"main": "lib/index.js",
"module": "lib/esm/index.js",
"types": "lib/index.d.ts",
"dependencies": {
"@ethereumjs/rlp": "5.0.0",
"@noble/curves": "~1.3.0",
"@noble/hashes": "~1.3.3"
"@noble/hashes": "~1.3.3",
"micro-packed": "~0.5.0"
},
"devDependencies": {
"micro-bmark": "0.3.0",
"micro-bmark": "0.3.1",
"micro-should": "0.4.0",

@@ -56,9 +46,9 @@ "prettier": "3.1.1",

"scripts": {
"build": "tsc",
"build": "tsc && tsc -p tsconfig.esm.json",
"build:release": "cd build; npm run build:release",
"bench": "node test/benchmark.js",
"lint": "prettier --print-width 100 --single-quote --check index.ts formatters.ts",
"format": "prettier --print-width 100 --single-quote --write index.ts formatters.ts",
"test": "node test/test.js"
"lint": "prettier --print-width 100 --single-quote --check src",
"format": "prettier --print-width 100 --single-quote --write src",
"test": "node test/test.js && node test/web3.test.js"
}
}
# micro-eth-signer
Create, sign and validate Ethereum transactions & addresses with minimum deps.
Small tool for Ethereum transactions, addresses and smart contracts.
- Tiny: 500 lines of code, 3KB gzipped, 13KB bundled
- 3 dependencies: noble-hashes for sha3, noble-curves for secp256k1, rlp
- No network code in main package: allows simpler audits and offline usage
- Validated against 3MB of [ethers](https://github.com/ethers-io/ethers.js/) test vectors
- Using audited [noble](https://paulmillr.com/noble/) cryptography under the hood
- 🔓 Secure: minimum deps, audited [noble](https://paulmillr.com/noble/) cryptography
- ðŸ”ŧ Tree-shaking-friendly: use only what's necessary, other code won't be included
- 🌍 No network code for simplified auditing and offline usage
- 🔍 Tested against 3MB of [ethers](https://github.com/ethers-io/ethers.js/) vectors
- ✍ïļ Create and sign transactions, generate and checksum addresses
- 📖 Decode transactions and events into human-readable form
- 🆎 Call smart contracts: Chainlink and Uniswap APIs are included
- ðŸĶš Decode smart contract ABIs into type-safe TypeScript structures
- ðŸŠķ Small: 500 lines of code for main module, 2.7K lines for everything
*Check out all web3 utility libraries:* [ETH](https://github.com/paulmillr/micro-eth-signer), [BTC](https://github.com/paulmillr/scure-btc-signer), [SOL](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)
_Check out all web3 utility libraries:_ [ETH](https://github.com/paulmillr/micro-eth-signer), [BTC](https://github.com/paulmillr/scure-btc-signer), [SOL](https://github.com/paulmillr/micro-sol-signer), [tx-tor-broadcaster](https://github.com/paulmillr/tx-tor-broadcaster)

@@ -22,5 +26,18 @@ ## Usage

- [Transaction creation and signing](#transaction-creation-and-signing)
- [Address generation and checksumming](#address-generation-and-checksumming)
- [Transaction decoding](#transaction-decoding)
- [Event decoding](#event-decoding)
- [Call smart contracts](#call-smart-contracts)
- [Fetch Chainlink oracle prices](#fetch-chainlink-oracle-prices)
- [Uniswap](#uniswap)
- [Type inference](#type-inference)
- [Human-friendly field validation](#human-friendly-field-validation)
- [Formatters](#formatters)
- [Low-level transaction API](#low-level-transaction-api)
### Transaction creation and signing
```js
import { Address, Transaction } from 'micro-eth-signer';
import { Transaction } from 'micro-eth-signer';
const tx = new Transaction({

@@ -32,5 +49,4 @@ to: '0xdf90dea0e0bf5ca6d2a7f0cb86874ba6714f463e',

maxPriorityFeePerGas: 0,
chainId: 1
chainId: 1,
});
// keys, messages & other inputs can be Uint8Arrays or hex strings

@@ -40,71 +56,153 @@ // Uint8Array.from([0xde, 0xad, 0xbe, 0xef]) === 'deadbeef'

const signedTx = tx.sign(privateKey);
const { hash, hex } = signedTx;
console.log(signedTx.hash, signedTx.hex);
console.log('Need wei', tx.upfrontCost); // also, tx.fee, tx.amount, tx.sender, etc
```
// Strings can be used also
// tx = new Transaction({"nonce": "0x01"})
// Same goes to serialized representation
// tx = new Transaction('0xeb018502540be40082520894df90dea0e0bf5ca6d2a7f0cb86874ba6714f463e872386f26fc1000080808080');
### Address generation and checksumming
// Various tx properties
console.log('Need wei', tx.upfrontCost); // also, tx.fee, tx.amount, tx.sender, etc
```ts
const addr = '0x0089d53f703f7e0843953d48133f74ce247184c2';
const addrc = Address.checksum(addr); // 0x0089d53F703f7E0843953D48133f74cE247184c2
Address.verifyChecksum(addrc); // true
Address.verifyChecksum(addr); // true also (non-checksummed)
Address.fromPrivateKey('0687640ee33ef844baba3329db9e16130bd1735cbae3657bd64aed25e9a5c377');
// 0xD4fE407789e11a27b7888A324eC597435353dC35
Address.fromPublicKey('030fba7ba5cfbf8b00dd6f3024153fc44ddda93727da58c99326eb0edd08195cdb');
// 0xD4fE407789e11a27b7888A324eC597435353dC35
```
// Address manipulation
const addr = Address.fromPrivateKey(privateKey);
const pubKey = signedTx.recoverSenderPublicKey();
console.log('Verified', Address.verifyChecksum(addr));
console.log('addr is correct', signedTx.sender, signedTx.sender == addr);
console.log(signedTx);
### Transaction decoding
// London style txs, EIP 1559
const legacyTx = new Transaction({
to: '0xdf90dea0e0bf5ca6d2a7f0cb86874ba6714f463e',
gasPrice: 100n * 10n ** 9n, // 100 gwei in wei
value: 10n ** 18n, // 1 eth in wei
nonce: 1
}, undefined, undefined, 'legacy');
```ts
import web3 from 'micro-eth-signer/web3.js';
import contracts from 'micro-eth-signer/web3.js/contracts';
import web3net from 'micro-web3-net';
const DEF_CONTRACTS = contracts.DEFAULT_CONTRACTS;
```
const berlinTx = new Transaction({
to: '0xdf90dea0e0bf5ca6d2a7f0cb86874ba6714f463e',
maxFeePerGas: 100n * 10n ** 9n, // 100 gwei in wei
maxPriorityFeePerGas: 1n * 10n ** 9n, // 1 gwei in wei
value: 10n ** 18n, // 1 eth in wei
nonce: 1,
// the field can also be used in eip1559 txs
accessList: [{
"address": "0x123456789a123456789a123456789a123456789a",
"storageKeys": [
"0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
]
}]
}, undefined, undefined, 'eip2930');
The transaction sent ERC-20 USDT token between addresses:
```ts
import { hex } from '@scure/base';
const tx =
'a9059cbb000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000542598700';
const decoder = new web3.Decoder();
const USDT = contracts.tokenFromSymbol('USDT').contract;
decoder.add(USDT, contracts.ERC20);
const info = decoder.decode(USDT, hex.decode(tx), { contractInfo: DEF_CONTRACTS[USDT] });
console.log(info);
// { name: 'transfer', signature: 'transfer(address,uint256)',
// value: { to: '0xdac17f958d2ee523a2206206994597c13d831ec7', value: 22588000000n },
// hint: 'Transfer 22588 USDT to 0xdac17f958d2ee523a2206206994597c13d831ec7' }
```
## API
### Event decoding
### Address
```ts
const BAT = '0x0d8775f648430679a709e98d2b0cb6250d2887ef';
const decoder = new web3.Decoder();
decoder.add(BAT, contracts.ERC20);
const info = decoder.decodeEvent(
BAT,
[
'0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925',
'0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045',
'0x000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564',
],
'0x00000000000000000000000000000000000000000000003635c9adc5dea00000',
{ contract: BAT, contracts: { ...DEF_CONTRACTS }, contractInfo: DEF_CONTRACTS[BAT] }
);
console.log(info.hint);
// Allow 0xe592427a0aece92de3edee1f18e0157c05861564 spending up to 1000 BAT from 0xd8da6bf26964af9d7eed9e03e53415d37aa96045
```
Represents ETH address and has following methods:
### Call smart contracts
- `Address.fromPrivateKey(privateKey: string | Uint8Array): string` - create address from private key
- `Address.fromPublicKey(publicKey: string | Uint8Array): string` - creates address from public key
- `Address.checksum(nonChecksummedAddress: string): string` - creates checksummed address from non-checksummed address
- `Address.verifyChecksum(address: string): boolean` - verifies checksummed & non-checksummed address
#### Fetch Chainlink oracle prices
Usage:
```ts
import chainlink from 'micro-eth-signer/web3/api/chainlink';
const provider = new web3net.Web3({
url: 'https://nodes.mewapi.io/rpc/eth',
headers: { Origin: 'https://www.myetherwallet.com' },
});
const btc = await chainlink.coinPrice(provider, 'BTC');
const bat = await chainlink.tokenPrice(provider, 'BAT');
console.log({ btc, bat }); // BTC 19188.68870991, BAT 0.39728989 in USD
```
#### Uniswap
Swap 12.12 USDT to BAT with uniswap V3 defaults of 0.5% slippage, 30 min expiration.
```ts
import univ2 from 'micro-eth-signer/web3/api/uniswap-v2';
import univ3 from 'micro-eth-signer/web3/api/uniswap-v3';
const provider = new web3net.Web3({
url: 'https://nodes.mewapi.io/rpc/eth',
headers: { Origin: 'https://www.myetherwallet.com' },
});
const USDT = contracts.tokenFromSymbol('USDT');
const BAT = contracts.tokenFromSymbol('BAT');
const u3 = new univ3.UniswapV3(provider); // or new univ2.UniswapV2(provider)
const fromAddress = '0xd8da6bf26964af9d7eed9e03e53415d37aa96045';
const toAddress = '0xd8da6bf26964af9d7eed9e03e53415d37aa96045';
const swap = await u3.swap(USDT, BAT, '12.12', { slippagePercent: 0.5, ttl: 30 * 60 });
const swapData = await swap.tx(fromAddress, toAddress);
console.log(swapData.amount, swapData.expectedAmount, swapData.allowance);
```
### Type inference
The ABI is type-safe with following limitations:
- Fixed size arrays can have 999 elements at max: string[], string[1], ..., string[999]
- Fixed size 2d arrays can have 39 elements at max: string[][], string[][1], ..., string[39][39]
- Which is enough for almost all cases
- ABI must be described as constant value: `[...] as const`
- We're not able to handle contracts with method overload (same function names with different args) — the code will still work, but not types
We're parsing values as:
```js
const addr = "0x0089d53f703f7e0843953d48133f74ce247184c2";
const addrc = Address.checksum(addr) // 0x0089d53F703f7E0843953D48133f74cE247184c2
Address.verifyChecksum(addrc) // true
Address.verifyChecksum(addr) // true also (non-checksummed)
Address.fromPrivateKey("0687640ee33ef844baba3329db9e16130bd1735cbae3657bd64aed25e9a5c377")
// 0xD4fE407789e11a27b7888A324eC597435353dC35
Address.fromPublicKey("030fba7ba5cfbf8b00dd6f3024153fc44ddda93727da58c99326eb0edd08195cdb")
// 0xD4fE407789e11a27b7888A324eC597435353dC35
// no inputs
{} -> encodeInput();
// single input
{inputs: [{type: 'uint'}]} -> encodeInput(bigint);
// all inputs named
{inputs: [{type: 'uint', name: 'lol}, {type: 'address', name: 'wut'}]} -> encodeInput({lol: bigint, wut: string})
// at least one input is unnamed
{inputs: [{type: 'uint', name: 'lol}, {type: 'address'}]} -> encodeInput([bigint, string])
// Same applies for output!
```
### Transaction
Check out [`src/api/ens.ts`](./src/api/ens.ts) for type-safe contract execution example.
Represents unsigned & signed ETH transactions. They are serialized & deserialized using RLP. Here's an example of the same transaction in raw state, and serialized state:
### Human-friendly field validation
```ts
import { validateField, validateFields } from 'micro-eth-signer/tx-validator';
```
### Formatters
```ts
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;
```
### Low-level transaction API
Transaction represents unsigned & signed ETH transactions. They are serialized & deserialized using RLP. Here's an example of the same transaction in raw state, and serialized state:
```js

@@ -124,20 +222,20 @@ // raw

- `new Transaction(serialized[, chain, hardfork, type])` - creates transaction from Raw TX string.
- `chain`: optional argument (default is `mainnet`; `ropsten`, `rinkeby`, `goerli`, `kovan` etc)
- `hardfork`: optional argument (default is `london`). The only place we're checking for `hardfork`
is the replay protection code. There are very old transactions that don't support replay protection,
you'll probably won't need them
- `type`: optional argument (default is `eip1559`). Can be either `legacy`, `eip2930`, or `eip1559`
(Berlin and London style transactions with access lists and `maxFeePerGas`/`maxPriorityFeePerGas`)
- `chain`: optional argument (default is `mainnet`; `ropsten`, `rinkeby`, `goerli`, `kovan` etc)
- `hardfork`: optional argument (default is `london`). The only place we're checking for `hardfork`
is the replay protection code. There are very old transactions that don't support replay protection,
you'll probably won't need them
- `type`: optional argument (default is `eip1559`). Can be either `legacy`, `eip2930`, or `eip1559`
(Berlin and London style transactions with access lists and `maxFeePerGas`/`maxPriorityFeePerGas`)
- `new Transaction(rawTx[, chain, hardfork, type])` - creates transaction from Raw TX data.
- `rawTx` must have fields `to`, `value`, `nonce`, `gasLimit`
- `rawTx` must have `maxFeePerGas` (eip1559 txs) or `gasPrice` (berlin & legacy txs)
- `to` is recipient's address
- `value` is amount to send in wei
- `nonce` is sender's nonce in number
- `gasLimit` is transaction's Gas Limit in wei (minimum is `21000`)
- `maxFeePerGas` is eip1559 transaction's max acceptable gas price in wei (100 gwei is `100 * 10 ** 9`). Not applicable to legacy transactions
- `maxPriorityFeePerGas` is eip1559 transaction's max acceptable tip in wei. Not applicable to legacy transactions
- `gasPrice` is legacy transaction's Gas Price in wei. Not applicable to eip1559 transactions
- `data` is transaction's data if it's calling some smart contracts
- `accessList` is transaction's Access List, a list of addresses that its smart contract call touches. Basically an array of strings: `["0x123...", "0x456..."]`. Not applicable to legacy transactions
- `rawTx` must have fields `to`, `value`, `nonce`, `gasLimit`
- `rawTx` must have `maxFeePerGas` (eip1559 txs) or `gasPrice` (berlin & legacy txs)
- `to` is recipient's address
- `value` is amount to send in wei
- `nonce` is sender's nonce in number
- `gasLimit` is transaction's Gas Limit in wei (minimum is `21000`)
- `maxFeePerGas` is eip1559 transaction's max acceptable gas price in wei (100 gwei is `100 * 10 ** 9`). Not applicable to legacy transactions
- `maxPriorityFeePerGas` is eip1559 transaction's max acceptable tip in wei. Not applicable to legacy transactions
- `gasPrice` is legacy transaction's Gas Price in wei. Not applicable to eip1559 transactions
- `data` is transaction's data if it's calling some smart contracts
- `accessList` is transaction's Access List, a list of addresses that its smart contract call touches. Basically an array of strings: `["0x123...", "0x456..."]`. Not applicable to legacy transactions
- `Transaction#sign(privateKey: string | Uint8Array): Transaction` —

@@ -147,3 +245,3 @@ creates new transaction with same data, but signed by following private key

##### Transaction Properties
Transaction properties:

@@ -154,3 +252,3 @@ - `isSigned: boolean` - whether tx is signed with private key

- `amount: bigint` - amount (aka `value`) in wei
- `fee: bigint` - fee in wei (`maxFeePerGas` * `gasLimit` or `gasPrice` * `gasLimit`)
- `fee: bigint` - fee in wei (`maxFeePerGas` _ `gasLimit` or `gasPrice` _ `gasLimit`)
- `upfrontCost: bigint` - amount + fee in wei, combined

@@ -163,17 +261,16 @@ - `to: string` - address that receives the tx

### Additional modules
As an example, here's how to create legacy pre-eip1559 transaction:
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;
const legacyTx = new Transaction(
{
to: '0xdf90dea0e0bf5ca6d2a7f0cb86874ba6714f463e',
gasPrice: 100n * 10n ** 9n, // 100 gwei in wei
value: 10n ** 18n, // 1 eth in wei
nonce: 1,
},
undefined,
undefined,
'legacy'
);
```

@@ -180,0 +277,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡ïļ by Socket Inc