Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Chaingrep's JS library for parsing and simulating Ethereum transaction data
Chaingrep is making blockchain transactions and data human-readable through our API. The Chaingrep JS library exposes this API in a JS-native library interface. More detailed documentation on the API and the library can be found in the Chaingrep Docs.
To start using the Chaingrep JS library, you need to request an API key. Once you've obtained your API key, you can install chaingrep
using Yarn or NPM and start using it inside your JavaScript or TypeScript applications.
yarn add chaingrep
npm install chaingrep
const { Chaingrep } = require('chaingrep');
const chaingrep = new Chaingrep('YOUR_API_KEY_HERE');
Types are shown in the definitions and examples below, for their full definition, see the actual type definitions in the code.
chaingrep.transaction(transactionHash: string).get(): Promise<RawTransactionResult>
chaingrep.transaction(transactionHash: string).parse(): Promise<ParsedTransactionResult>
interface RawTransactionResult {
transactionHash: string;
blockNumber: number;
from: string;
to?: string;
deployedContract?: string;
value: BigNumber;
data: string;
eventLogs: EventLog[];
status: 'SUCCESS' | 'FAILED';
timestamp: number;
gasUsed: number;
gasPrice: BigNumber;
}
interface EventLog {
address: string;
data: string;
topics: string[];
}
interface ParsedTransactionResult {
transactionHash: string;
transactionType: TransactionType;
transactionMetadata: ParsedTransactionAction; // See type definitions for details
standardEvents: DecodedEventData[];
protocol: {
contractAddress: string;
protocol: string;
}
value: Erc20TokenAmount;
sender: string;
action: string;
transactionCost: {
gasPrice: {
price: number;
unit: 'gwei';
};
gasUsed: number;
paid: Erc20TokenAmount;
}
time: {
formatted: string;
timeago: string;
unixTimestamp: number;
}
status: string;
chain: {
chainId: 1;
name: string;
}
}
type TransactionType =
'ETH_TRANSFER'
| 'ERC20_TRANSFER'
| 'ERC20_APPROVAL'
| 'ERC721_TRANSFER'
| 'ERC721_APPROVAL'
| 'ERC721_APPROVAL_FOR_ALL'
| 'DEX_SWAP'
| 'DEX_PROVIDE_LIQUIDITY'
| 'DEX_REMOVE_LIQUIDITY'
| 'NFT_SALE'
| 'WRAP_ETHER'
| 'UNWRAP_ETHER'
| 'ZKSYNC_DEPOSIT'
| 'ENS_NAME_REGISTRATION';
interface DecodedEventData {
type: string;
address: string;
data: any;
}
interface Erc20TokenAmount {
raw: BigNumber;
formatted: string;
}
A transaction can be retrieved and/or parsed by using the transaction
functionality in the Chaingrep library.
const parsedTransaction = await chaingrep.transaction('0xdef0cf4872c73dd23d284c4b61c39954f5bba0869d5a4b1cfe1e65f35d9b78a3').parse();
{
"transactionHash": "0xdef0cf4872c73dd23d284c4b61c39954f5bba0869d5a4b1cfe1e65f35d9b78a3",
"transactionType": "DEX_SWAP",
"transactionMetadata": {
"account": "0xe126b3E5d052f1F575828f61fEBA4f4f2603652a",
"swappedFrom": {
"asset": {
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"name": "Ether",
"symbol": "ETH",
"decimals": 18,
"logoURI": "https://assets.coingecko.com/coins/images/279/small/ethereum.png?1595348880"
},
"amount": {
"raw": "1000000000000000000",
"formatted": "1.0"
}
},
"swappedTo": {
"asset": {
"address": "0xf4d2888d29d722226fafa5d9b24f9164c092421e",
"name": "LooksRare",
"symbol": "LOOKS",
"decimals": 18,
"logoURI": "https://assets.coingecko.com/coins/images/22173/small/circle-black-256.png?1641173160"
},
"amount": {
"raw": "3806742856923420981865",
"formatted": "3806.742856923420981865"
}
}
},
"standardEvents": [
{
"type": "ERC20_TRANSFER",
"address": "0xf4d2888d29d722226fafa5d9b24f9164c092421e",
"data": {
"from": "0x4b5Ab61593A2401B1075b90c04cBCDD3F87CE011",
"to": "0xe126b3E5d052f1F575828f61fEBA4f4f2603652a",
"value": "3806742856923420981865"
}
},
{
"type": "ERC20_TRANSFER",
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"data": {
"from": "0xDef1C0ded9bec7F1a1670819833240f027b25EfF",
"to": "0x4b5Ab61593A2401B1075b90c04cBCDD3F87CE011",
"value": "1000000000000000000"
}
}
],
"protocol": {
"contractAddress": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
"protocol": "Zeroex"
},
"value": {
"raw": "1000000000000000000",
"formatted": "1"
},
"sender": "0xe126b3e5d052f1f575828f61feba4f4f2603652a",
"action": "Swapped 1.00000 ETH for 3806.74286 LOOKS on Zeroex",
"transactionCost": {
"gasPrice": {
"price": 12,
"unit": "gwei"
},
"gasUsed": 118955,
"paid": {
"raw": "1498267380513635",
"formatted": "0.001498267380513635"
}
},
"time": {
"formatted": "05/22/2022, 11:11:26 AM",
"timeago": "5 days ago",
"unixTimestamp": 1653217886
},
"status": "SUCCESS",
"chain": {
"chainId": 1,
"name": "Ethereum"
}
}
chaingrep.account(address: string).getTransactions(start?: number, amount?: number): Promise<RawTransactionResult[]>
chaingrep.account(address: string).parseTransactions(start?: number, amount?: number): Promise<ParsedTransactionResult[]>
Transactions can be retrieved and/or parsed for a specific account. This includes transactions where the account was the sender or the receiver of the transaction, as well as any transactions where the account received tokens. For more fine-grained transaction selections, see the section on transaction querying. Transactions are sorted by timestamp in descending order. It is possible to add a start
and amount
parameter to paginate these transactions. By default the most recent 10 transactions are returned.
const accountTransactions = await chaingrep.account('0xe126b3e5d052f1f575828f61feba4f4f2603652a').parseTransactions();
chaingrep.account(address: string).subscribe(webhookUrl: string): Promise<string>
chaingrep.account(address: string).unsubscribe(webhookId: string): Promise<string>
chaingrep.user().getAllActiveSubscriptions(): Promise<Subscription[]>
Subscriptions can be created by calling the subscribe
function on an account, with a corresponding webhook URL as its parameter. This returns a webhook ID that can be used to unsubscribe from these updates at any point. A list of all your active subscriptions (for all addresses) can be retrieved at any point by calling chaingrep.user().getAllActiveSubscriptions()
.
After registering your webhook with chaingrep, we will send a POST request to the webhook URL whenever the passed account sends or receives transactions, or when they are involved in any contract events (such as token transfers). The interface can be found below
interface WebhookPayload {
uid: string;
transactions: ParsedTransactionResult[];
}
chaingrep.query(): Query
interface Query {
filter(filter: QueryFilter): this
sort(field: 'timestamp' | 'value' | 'gasPrice' | 'gasUsed', order: 'ascending' | 'descending'): this
timeframe(from: number | Date, to: number | Date): this
execute(start?: number, amount?: number): Promise<ParsedTransactionResult[]>
executeRaw(start?: number, amount?: number): Promise<RawTransactionResult[]>
count(): Promise<number>
}
Transactions can be queried using some more fine-grained filtering. Filters can be defined for the following transaction properties:
interface QueryFilter {
account?: string;
contract?: string;
value?: string;
successful?: boolean;
gasUsed?: string;
gasPrice?: string;
}
Simple comparison operators may be passed, such as { value: '>0', gasUsed: '<=1000000' }
. The account
property matches any transactions sent from/to the passed address, as well as any transactions where the passed address received any tokens. The contract
property matches any transactions sent to the passed address, as well as any transactions where the passed address emitted any events.
Besides filtering on these properties, a query can be limited by its timestamp with .timeframe(from, to)
and you can provide a sort using .sort(field, order)
. By default, the results are sorted by timestamp in a descending order. It is possible to add a start
and amount
parameter to paginate these transactions. By default the most recent 10 transactions are returned.
const queriedTransactions = await chaingrep.query()
.filter({ account: '0xe126b3e5d052f1f575828f61feba4f4f2603652a', value: '>0' })
.timeframe(new Date('2022-05-22T00:00:00'), new Date('2022-05-25T00:00:00'))
.execute();
chaingrep.rawTransaction(transactionRequest: RawTransactionRequest).simulate(): Promise<ParsedTransaction>
interface RawTransactionRequest {
to?: string;
from?: string;
nonce?: BigNumberish;
gasLimit?: BigNumberish;
gasPrice?: BigNumberish;
data?: string;
value?: BigNumberish;
chainId?: number;
type?: number;
maxFeePerGas?: BigNumberish;
maxPriorityFeePerGas?: BigNumberish;
}
Sometimes, you'd like to see what a transaction will do before submitting it to the network. For this, we developed our simulation API. This simulates what will happen if the passed transaction would be submitted to the network right now. You can manually create a "transaction request", but this functionality is also fully compatible with Ethers.js' Contract objects as can be seen in the example below.
const voidSigner = new VoidSigner('0xe126b3e5d052f1f575828f61feba4f4f2603652a');
const looksTokenContract = new Contract('0xf4d2888d29D722226FafA5d9B24F9164c092421E', erc20TokenAbi, voidSigner);
const transactionRequest = await looksTokenContract.populateTransaction.approve('0x881D40237659C251811CEC9c364ef91dC08D300C', '0');
const simulatedTransaction = await chaingrep.rawTransaction(transactionRequest).simulate();
{
"transactionHash": "0x74f7808c20c8c4f961af9fc2ed67b5aad492737868b0b732f52e5ab9d40e0ecc",
"transactionType": "ERC20_APPROVAL",
"transactionMetadata": {
"from": "0xe126b3E5d052f1F575828f61fEBA4f4f2603652a",
"to": "0x881D40237659C251811CEC9c364ef91dC08D300C",
"asset": {
"address": "0xf4d2888d29d722226fafa5d9b24f9164c092421e",
"name": "LooksRare",
"symbol": "LOOKS",
"decimals": 18,
"logoURI": "https://assets.coingecko.com/coins/images/22173/small/circle-black-256.png?1641173160"
},
"amount": {
"raw": "0",
"formatted": "0.0"
}
},
"standardEvents": [
{
"type": "ERC20_APPROVAL",
"address": "0xf4d2888d29D722226FafA5d9B24F9164c092421E",
"data": {
"owner": "0xe126b3E5d052f1F575828f61fEBA4f4f2603652a",
"spender": "0x881D40237659C251811CEC9c364ef91dC08D300C",
"value": "0"
}
}
],
"protocol": {
"contractAddress": "0xf4d2888d29d722226fafa5d9b24f9164c092421e",
"protocol": "UNKNOWN"
},
"value": {
"raw": "0",
"formatted": "0"
},
"sender": "0xe126b3E5d052f1F575828f61fEBA4f4f2603652a",
"action": "Revoked a contract's allowance to spend LOOKS",
"transactionCost": {
"gasPrice": {
"price": 8,
"unit": "gwei"
},
"gasUsed": 26255,
"paid": {
"raw": "213097433502380",
"formatted": "0.00021309743350238"
}
},
"time": {
"formatted": "05/29/2022, 09:28:25 AM",
"timeago": "just now",
"unixTimestamp": 1653816505
},
"status": 1,
"chain": {
"chainId": 1,
"name": "Ethereum"
}
}
A "kitchen sink" example is available here that can be executed with ts-node after cloning the chaingrep-js
repository.
yarn ts-node examples/kitchen-sink.ts
git clone git@github.com:chaingrep/chaingrep-js.git
cd chaingrep-js
yarn
The tests are currently written against the production API for simplicity of implementation. This does mean that it cannot be tested independently. To run all tests you'll need to request an API key and add it to a .env
file in this repo.
To create a new release you have to be a maintainer of this repo and of the NPM package. The steps to create a new release are the following. We follow semantic versioning, so because we are still on a 0.x.x
release, this means that we bump the minor version for breaking changes, and the patch version for non-breaking changes.
npm version [minor | patch]
npm publish
git push
Then, on GitHub, go to the releases tab and draft a new release with tag and title being v{new version}
and write down a short changelog. Refer to the additional releases for examples.
FAQs
Chaingrep's JS library for parsing and simulating Ethereum transaction data
The npm package chaingrep receives a total of 5 weekly downloads. As such, chaingrep popularity was classified as not popular.
We found that chaingrep demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.