├── .cargo └── config.toml ├── .github └── workflows │ └── publish_to_npm.yaml ├── .gitignore ├── .npmignore ├── .yarn └── releases │ └── yarn-3.8.1.cjs ├── .yarnrc.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── __test__ └── decoder.test.mjs ├── build.rs ├── docs ├── .nojekyll ├── assets │ ├── highlight.css │ ├── icons.js │ ├── icons.svg │ ├── main.js │ ├── navigation.js │ ├── search.js │ └── style.css ├── classes │ ├── CallDecoder.html │ ├── Decoder.html │ ├── EventStream.html │ ├── HypersyncClient.html │ └── QueryResponseStream.html ├── enums │ ├── BlockField.html │ ├── DataType.html │ ├── HexOutput.html │ ├── JoinMode.html │ ├── LogField.html │ ├── TraceField.html │ └── TransactionField.html ├── functions │ ├── presetQueryBlocksAndTransactionHashes.html │ ├── presetQueryBlocksAndTransactions.html │ ├── presetQueryLogs.html │ └── presetQueryLogsOfEvent.html ├── index.html ├── interfaces │ ├── AccessList.html │ ├── Authorization.html │ ├── AuthorizationSelection.html │ ├── Block.html │ ├── BlockSelection.html │ ├── ClientConfig.html │ ├── ColumnMapping.html │ ├── DecodedEvent.html │ ├── DecodedSolValue.html │ ├── Event.html │ ├── EventResponse.html │ ├── Events.html │ ├── FieldSelection.html │ ├── Log.html │ ├── LogSelection.html │ ├── Query.html │ ├── QueryResponse.html │ ├── QueryResponseData.html │ ├── RollbackGuard.html │ ├── StreamConfig.html │ ├── Trace.html │ ├── TraceSelection.html │ ├── Transaction.html │ ├── TransactionSelection.html │ └── Withdrawal.html └── modules.html ├── examples ├── all-erc20 │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── app.ts │ └── tsconfig.json ├── call_watch │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── app.ts │ └── tsconfig.json ├── parquet-out │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── app.ts │ └── tsconfig.json ├── reverse_wallet │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── app.ts │ └── tsconfig.json ├── simple-blocks-and-transaction-hashes │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── app.ts │ └── tsconfig.json ├── simple-blocks-and-transactions │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── app.ts │ └── tsconfig.json ├── simple-logs-of-event │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── app.ts │ └── tsconfig.json ├── simple-logs │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── app.ts │ └── tsconfig.json ├── wallet │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── app.ts │ └── tsconfig.json └── watch │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ └── app.ts │ └── tsconfig.json ├── index.d.ts ├── index.js ├── npm ├── darwin-arm64 │ ├── README.md │ └── package.json ├── darwin-x64 │ ├── README.md │ └── package.json ├── linux-arm64-gnu │ ├── README.md │ └── package.json ├── linux-x64-gnu │ ├── README.md │ └── package.json ├── linux-x64-musl │ ├── README.md │ └── package.json └── win32-x64-msvc │ ├── README.md │ └── package.json ├── package.json ├── src ├── config.rs ├── decode.rs ├── decode_call.rs ├── lib.rs ├── preset_query.rs ├── query.rs └── types.rs └── yarn.lock /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.aarch64-unknown-linux-musl] 2 | linker = "aarch64-linux-musl-gcc" 3 | rustflags = ["-C", "target-feature=-crt-static"] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | node_modules/ 46 | jspm_packages/ 47 | 48 | # TypeScript v1 declaration files 49 | typings/ 50 | 51 | # TypeScript cache 52 | *.tsbuildinfo 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variables file 76 | .env 77 | .env.test 78 | 79 | # parcel-bundler cache (https://parceljs.org/) 80 | .cache 81 | 82 | # Next.js build output 83 | .next 84 | 85 | # Nuxt.js build / generate output 86 | .nuxt 87 | dist 88 | 89 | # Gatsby files 90 | .cache/ 91 | # Comment in the public line in if your project uses Gatsby and not Next.js 92 | # https://nextjs.org/blog/next-9-1#public-directory-support 93 | # public 94 | 95 | # vuepress build output 96 | .vuepress/dist 97 | 98 | # Serverless directories 99 | .serverless/ 100 | 101 | # FuseBox cache 102 | .fusebox/ 103 | 104 | # DynamoDB Local files 105 | .dynamodb/ 106 | 107 | # TernJS port file 108 | .tern-port 109 | 110 | # Stores VSCode versions used for testing VSCode extensions 111 | .vscode-test 112 | 113 | # End of https://www.toptal.com/developers/gitignore/api/node 114 | 115 | # Created by https://www.toptal.com/developers/gitignore/api/macos 116 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos 117 | 118 | ### macOS ### 119 | # General 120 | .DS_Store 121 | .AppleDouble 122 | .LSOverride 123 | 124 | # Icon must end with two 125 | Icon 126 | 127 | 128 | # Thumbnails 129 | ._* 130 | 131 | # Files that might appear in the root of a volume 132 | .DocumentRevisions-V100 133 | .fseventsd 134 | .Spotlight-V100 135 | .TemporaryItems 136 | .Trashes 137 | .VolumeIcon.icns 138 | .com.apple.timemachine.donotpresent 139 | 140 | # Directories potentially created on remote AFP share 141 | .AppleDB 142 | .AppleDesktop 143 | Network Trash Folder 144 | Temporary Items 145 | .apdisk 146 | 147 | ### macOS Patch ### 148 | # iCloud generated files 149 | *.icloud 150 | 151 | # End of https://www.toptal.com/developers/gitignore/api/macos 152 | 153 | # Created by https://www.toptal.com/developers/gitignore/api/windows 154 | # Edit at https://www.toptal.com/developers/gitignore?templates=windows 155 | 156 | ### Windows ### 157 | # Windows thumbnail cache files 158 | Thumbs.db 159 | Thumbs.db:encryptable 160 | ehthumbs.db 161 | ehthumbs_vista.db 162 | 163 | # Dump file 164 | *.stackdump 165 | 166 | # Folder config file 167 | [Dd]esktop.ini 168 | 169 | # Recycle Bin used on file shares 170 | $RECYCLE.BIN/ 171 | 172 | # Windows Installer files 173 | *.cab 174 | *.msi 175 | *.msix 176 | *.msm 177 | *.msp 178 | 179 | # Windows shortcuts 180 | *.lnk 181 | 182 | # End of https://www.toptal.com/developers/gitignore/api/windows 183 | 184 | #Added by cargo 185 | 186 | /target 187 | Cargo.lock 188 | 189 | .pnp.* 190 | .yarn/* 191 | !.yarn/patches 192 | !.yarn/plugins 193 | !.yarn/releases 194 | !.yarn/sdks 195 | !.yarn/versions 196 | 197 | *.node 198 | 199 | data/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | .cargo 4 | .github 5 | npm 6 | .eslintrc 7 | .prettierignore 8 | rustfmt.toml 9 | yarn.lock 10 | *.node 11 | .yarn 12 | __test__ 13 | renovate.json 14 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-3.8.1.cjs 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "envio_hypersync-client" 4 | version = "0.0.0" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix 11 | napi = { version = "2", default-features = false, features = [ 12 | "napi9", 13 | "async", 14 | "serde-json", 15 | ] } 16 | napi-derive = "2" 17 | serde = { version = "1", features = ["derive"] } 18 | alloy-dyn-abi = "1.1" 19 | tokio = { version = "1", features = ["rt-multi-thread"] } 20 | env_logger = "0.11" 21 | faster-hex = "0.9.0" 22 | anyhow = "1" 23 | serde_json = "1" 24 | ruint = "1" 25 | alloy-primitives = "1.1" 26 | 27 | hypersync-client = "0.19.0" 28 | 29 | [build-dependencies] 30 | napi-build = "2.0.1" 31 | 32 | [profile.release] 33 | lto = true 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node.js HyperSync Client 2 | 3 | HyperSync Client by [Envio](https://envio.dev). 4 | 5 | Read full documentation [here](https://docs.hypersync.xyz/docs/nodejs-client/introduction). 6 | 7 | ## Getting Started 8 | 9 | ```bash 10 | npm i @envio-dev/hypersync-client 11 | ``` 12 | 13 | See [examples](examples) for usage. 14 | -------------------------------------------------------------------------------- /__test__/decoder.test.mjs: -------------------------------------------------------------------------------- 1 | import test from "ava"; 2 | import { Decoder, HypersyncClient } from "../index.js"; 3 | 4 | test("Decodes event from etherscan", async (t) => { 5 | const decoder = Decoder.fromSignatures([ 6 | "event Mint(address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)", 7 | ]); 8 | 9 | const log = { 10 | topics: [ 11 | "0x7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde", 12 | "0x000000000000000000000000827922686190790b37229fd06084350e74485b72", 13 | "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 14 | "0x0000000000000000000000000000000000000000000000000000000000000001", 15 | ], 16 | data: "0x000000000000000000000000827922686190790b37229fd06084350e74485b72000000000000000000000000000000000000000000000000000000000bebae76000000000000000000000000000000000000000000000000000000000000270f000000000000000000000000000000000000000000000000000000000000270f", 17 | }; 18 | const decoded = await decoder.decodeLogs([log]); 19 | t.is(decoded[0].indexed[1].val, -1n); 20 | }); 21 | 22 | //skig the async test against hypersync endpoint 23 | test.skip("Fetches event from base", async (t) => { 24 | const decoder = Decoder.fromSignatures([ 25 | "event Mint(address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)", 26 | ]); 27 | const client = HypersyncClient.new({ url: "https://base.hypersync.xyz" }); 28 | const res = await client.getEvents({ 29 | fromBlock: 13899663, 30 | toBlock: 13899664, 31 | logs: [ 32 | { 33 | address: ["0x98c7A2338336d2d354663246F64676009c7bDa97"], 34 | topics: [ 35 | [ 36 | "0x7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde", 37 | ], 38 | ], 39 | }, 40 | ], 41 | fieldSelection: { 42 | log: [ 43 | "topic0", 44 | "topic1", 45 | "topic2", 46 | "topic3", 47 | "data", 48 | "log_index", 49 | "transaction_hash", 50 | ], 51 | }, 52 | }); 53 | 54 | const decoded = await decoder.decodeEvents(res.data); 55 | t.is(decoded[0].indexed[1].val, -1n); 56 | // console.log(decoded[0].indexed[1].val); 57 | // const decoder = Decoder.fromSignatures([ 58 | // "event Mint(address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)", 59 | // ]); 60 | // 61 | // const log = { 62 | // topics: [ 63 | // "0x7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde", 64 | // "0x000000000000000000000000827922686190790b37229fd06084350e74485b72", 65 | // "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 66 | // "0x0000000000000000000000000000000000000000000000000000000000000001", 67 | // ], 68 | // data: "0x000000000000000000000000827922686190790b37229fd06084350e74485b72000000000000000000000000000000000000000000000000000000000bebae76000000000000000000000000000000000000000000000000000000000000270f000000000000000000000000000000000000000000000000000000000000270f", 69 | // }; 70 | // const decoded = await decoder.decodeLogs([log]); 71 | // t.is(decoded[0].indexed[1].val, -1n); 72 | }); 73 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | extern crate napi_build; 2 | 3 | fn main() { 4 | napi_build::setup(); 5 | } 6 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-code-background: #FFFFFF; 3 | --dark-code-background: #1E1E1E; 4 | } 5 | 6 | @media (prefers-color-scheme: light) { :root { 7 | --code-background: var(--light-code-background); 8 | } } 9 | 10 | @media (prefers-color-scheme: dark) { :root { 11 | --code-background: var(--dark-code-background); 12 | } } 13 | 14 | :root[data-theme='light'] { 15 | --code-background: var(--light-code-background); 16 | } 17 | 18 | :root[data-theme='dark'] { 19 | --code-background: var(--dark-code-background); 20 | } 21 | 22 | pre, code { background: var(--code-background); } 23 | -------------------------------------------------------------------------------- /docs/assets/navigation.js: -------------------------------------------------------------------------------- 1 | window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA52VT28TMRDFv4vPEREVVCi3kkIjtFVFU8EBcTDeSdaKY6/8BxoQ3x3FYbN21h5bvfq995tZjT377Q+x8GzJgrwXiu0+chAtmZGe2o4sCEi3N/NRedXZvSAzsuOyJYt3f2fn9C219OnQw2V2OM8nV/D84Gzv7GX0LOSznxSX96qdVB3O88lGbZPfOpznk0+aMkhmRwVNS0OZ5UrmGJGeJy2pELfAVAt6hDBBjQEzD8SY8PoqmlouX5H98BOkXVsNdD/NByLGWB160OYg2VJwkHbKuTBgrM8O9OERTK+kgVxfCRPGvGEMjGm4CVrj0oLeUAZmPsox5OrtdQhxtlOa/6bHoaY5oaMatQYBrI55tmJw/8yTLK8Uo3g/sQWDnUa9VHLDt0lUaEBBSri9vKd9z2WGFDow1Ok9tP5aJ0mhoQK0VuILFQ4w1uDBcPmGip14w/AU8ojBUUSZPMNgYb/m8LsTWzBYo9KDbhQ63kZt8Q5CAwby+yVJ8Eoxis4jclSjjn/gMu7owpCPSogflO3uHNVtEhc5MNRp7SLvOzRgIP+/TRK8UoziI48tBdjwz86RBr0SU+xsYsTAX7ntWk1/UZHEjTIG6TUYsP7O+FVubmQbNLKipoNgBWyc9OdmXhWMK1+/qS/8kpqV5Rq1LdGPlnrYw+ZiX2eZ/50T9Pd/I5OmsrALAAA=" -------------------------------------------------------------------------------- /docs/classes/EventStream.html: -------------------------------------------------------------------------------- 1 | EventStream | @envio-dev/hypersync-client

Constructors

Methods

close 3 | recv 4 |

Constructors

Methods

-------------------------------------------------------------------------------- /docs/classes/QueryResponseStream.html: -------------------------------------------------------------------------------- 1 | QueryResponseStream | @envio-dev/hypersync-client

Constructors

Methods

close 3 | recv 4 |

Constructors

Methods

-------------------------------------------------------------------------------- /docs/enums/HexOutput.html: -------------------------------------------------------------------------------- 1 | HexOutput | @envio-dev/hypersync-client

Enumeration Members

Enumeration Members

NoEncode: "NoEncode"
NonPrefixed: "NonPrefixed"
Prefixed: "Prefixed"
-------------------------------------------------------------------------------- /docs/enums/JoinMode.html: -------------------------------------------------------------------------------- 1 | JoinMode | @envio-dev/hypersync-client

Enumeration Members

Enumeration Members

Default: 0
JoinAll: 1
JoinNothing: 2
-------------------------------------------------------------------------------- /docs/functions/presetQueryBlocksAndTransactionHashes.html: -------------------------------------------------------------------------------- 1 | presetQueryBlocksAndTransactionHashes | @envio-dev/hypersync-client

Function presetQueryBlocksAndTransactionHashes

  • Returns a query object for all Blocks and hashes of the Transactions within the block range 2 | (from_block, to_block]. Also returns the block_hash and block_number fields on each Transaction 3 | so it can be mapped to a block. If to_block is None then query runs to the head of the chain.

    4 |

    Parameters

    • fromBlock: number
    • Optional toBlock: number

    Returns Query

-------------------------------------------------------------------------------- /docs/functions/presetQueryBlocksAndTransactions.html: -------------------------------------------------------------------------------- 1 | presetQueryBlocksAndTransactions | @envio-dev/hypersync-client

Function presetQueryBlocksAndTransactions

  • Returns a query for all Blocks and Transactions within the block range (from_block, to_block] 2 | If to_block is None then query runs to the head of the chain.

    3 |

    Parameters

    • fromBlock: number
    • Optional toBlock: number

    Returns Query

-------------------------------------------------------------------------------- /docs/functions/presetQueryLogs.html: -------------------------------------------------------------------------------- 1 | presetQueryLogs | @envio-dev/hypersync-client
  • Returns a query object for all Logs within the block range from the given address. 2 | If to_block is None then query runs to the head of the chain.

    3 |

    Parameters

    • contractAddress: string
    • fromBlock: number
    • Optional toBlock: number

    Returns Query

-------------------------------------------------------------------------------- /docs/functions/presetQueryLogsOfEvent.html: -------------------------------------------------------------------------------- 1 | presetQueryLogsOfEvent | @envio-dev/hypersync-client
  • Returns a query for all Logs within the block range from the given address with a 2 | matching topic0 event signature. Topic0 is the keccak256 hash of the event signature. 3 | If to_block is None then query runs to the head of the chain.

    4 |

    Parameters

    • contractAddress: string
    • topic0: string
    • fromBlock: number
    • Optional toBlock: number

    Returns Query

-------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | @envio-dev/hypersync-client

@envio-dev/hypersync-client

-------------------------------------------------------------------------------- /docs/interfaces/AccessList.html: -------------------------------------------------------------------------------- 1 | AccessList | @envio-dev/hypersync-client

Evm access list object

2 |

See ethereum rpc spec for the meaning of fields

3 |
interface AccessList {
    address?: string;
    storageKeys?: string[];
}

Properties

Properties

address?: string
storageKeys?: string[]
-------------------------------------------------------------------------------- /docs/interfaces/AuthorizationSelection.html: -------------------------------------------------------------------------------- 1 | AuthorizationSelection | @envio-dev/hypersync-client
interface AuthorizationSelection {
    address?: string[];
    chainId?: number[];
}

Properties

Properties

address?: string[]

List of addresses to match in the transaction authorizationList

4 |
chainId?: number[]

List of chain ids to match in the transaction authorizationList

5 |
-------------------------------------------------------------------------------- /docs/interfaces/BlockSelection.html: -------------------------------------------------------------------------------- 1 | BlockSelection | @envio-dev/hypersync-client
interface BlockSelection {
    hash?: string[];
    miner?: string[];
}

Properties

hash? 2 | miner? 3 |

Properties

hash?: string[]

Hash of a block, any blocks that have one of these hashes will be returned. 4 | Empty means match all.

5 |
miner?: string[]

Miner address of a block, any blocks that have one of these miners will be returned. 6 | Empty means match all.

7 |
-------------------------------------------------------------------------------- /docs/interfaces/DecodedEvent.html: -------------------------------------------------------------------------------- 1 | DecodedEvent | @envio-dev/hypersync-client

Decoded EVM log

2 |
interface DecodedEvent {
    body: DecodedSolValue[];
    indexed: DecodedSolValue[];
}

Properties

body 3 | indexed 4 |

Properties

indexed: DecodedSolValue[]
-------------------------------------------------------------------------------- /docs/interfaces/DecodedSolValue.html: -------------------------------------------------------------------------------- 1 | DecodedSolValue | @envio-dev/hypersync-client
interface DecodedSolValue {
    val: string | bigint | boolean | DecodedSolValue[];
}

Properties

val 2 |

Properties

val: string | bigint | boolean | DecodedSolValue[]
-------------------------------------------------------------------------------- /docs/interfaces/Event.html: -------------------------------------------------------------------------------- 1 | Event | @envio-dev/hypersync-client

Data relating to a single event (log)

2 |
interface Event {
    block?: Block;
    log: Log;
    transaction?: Transaction;
}

Properties

block? 3 | log 4 | transaction? 5 |

Properties

block?: Block

Block that this event happened in

6 |
log: Log

Evm log data

7 |
transaction?: Transaction

Transaction that triggered this event

8 |
-------------------------------------------------------------------------------- /docs/interfaces/LogSelection.html: -------------------------------------------------------------------------------- 1 | LogSelection | @envio-dev/hypersync-client
interface LogSelection {
    address?: string[];
    topics?: string[][];
}

Properties

address? 2 | topics? 3 |

Properties

address?: string[]

Address of the contract, any logs that has any of these addresses will be returned. 4 | Empty means match all.

5 |
topics?: string[][]

Topics to match, each member of the top level array is another array, if the nth topic matches any 6 | topic specified in topics[n] the log will be returned. Empty means match all.

7 |
-------------------------------------------------------------------------------- /examples/all-erc20/README.md: -------------------------------------------------------------------------------- 1 | # Index all erc20 on the whole of Ethereum 2 | 3 | Example of using hypersync-client to get data for all erc20 transfers. 4 | 5 | The example uses the 'Transfer' event and counts all the amounts in the first batch of events that it recieves. The script doesn't scan the entire Ethereum chain, but rather goes through as many events as it can in the initial returned range. 6 | 7 | ## Prerequisites 8 | 9 | - Node.js (version 18.0.0 or above - rather stick to even/lts releases) 10 | - npm/yarn/pnpm 11 | 12 | ## Run 13 | 14 | ```bash 15 | git clone https://github.com/enviodev/hypersync-client-node.github 16 | cd hypersync-client-node/examples/all-erc20 17 | npm install 18 | npm build 19 | npm start 20 | ``` 21 | 22 | ## Comments 23 | 24 | The code is well commented, so best you go through that directly. Things to note, this is just an example of the API, and not an accurate example. So it doesn't take into account different decimals of ERC20 tokens, it only runs the query once - so it only does the first ~1.3 million blocks, it also includes volume of intra-contract-interaction transfers which might not be considered volume. 25 | 26 | So areas that could be explored further in pursuit of learning how to use Hypersync: 27 | 28 | - Scan the full chain by repeating queries from the end block rage all the way until the head. 29 | - Scan only erc20 contracts you care about by including the contract addresses in the query. 30 | - Get the decimals of the erc20 tokens and convert the amounts to a standard unit (might not be completely feasible if unless you are doing a subset of erc20 tokens). 31 | - Analyze only the resultant change in erc20 balance in a transaction, and exclude for example if multiple intra-contract transfers happen. This could be a fun one to work out. 32 | -------------------------------------------------------------------------------- /examples/all-erc20/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "all-erc20", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "start": "node dist/app.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/node": "^20.10.3", 15 | "typescript": "^5.3.2" 16 | }, 17 | "dependencies": { 18 | "@envio-dev/hypersync-client": "../.." 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/all-erc20/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@envio-dev/hypersync-client': 9 | specifier: ../.. 10 | version: link:../.. 11 | 12 | devDependencies: 13 | '@types/node': 14 | specifier: ^20.10.3 15 | version: 20.10.4 16 | typescript: 17 | specifier: ^5.3.2 18 | version: 5.3.3 19 | 20 | packages: 21 | 22 | /@types/node@20.10.4: 23 | resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} 24 | dependencies: 25 | undici-types: 5.26.5 26 | dev: true 27 | 28 | /typescript@5.3.3: 29 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 30 | engines: {node: '>=14.17'} 31 | hasBin: true 32 | dev: true 33 | 34 | /undici-types@5.26.5: 35 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 36 | dev: true 37 | -------------------------------------------------------------------------------- /examples/all-erc20/src/app.ts: -------------------------------------------------------------------------------- 1 | import { HypersyncClient, Decoder, BlockField, LogField, TransactionField } from "@envio-dev/hypersync-client"; 2 | import fs from "node:fs"; 3 | 4 | async function main() { 5 | // Create hypersync client using the mainnet hypersync endpoint 6 | // Passing null config makes it use default 7 | const client = HypersyncClient.new(null); 8 | 9 | // The query to run 10 | const query = { 11 | // Start from block 0 and go to the end of the chain (we don't specify a toBlock). 12 | // you can add a "toBlock" to limit the query to a certain range. 13 | "fromBlock": 0, 14 | // The logs we want. We will also automatically get transactions and blocks relating to these logs (the query implicitly joins them). 15 | "logs": [ 16 | { 17 | // We want All ERC20 transfers so no address filter and only a filter for the first topic 18 | "topics": [ 19 | ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"], 20 | ] 21 | } 22 | ], 23 | // Select the fields we are interested in, notice topics are selected as topic0,1,2,3 24 | // Most of the fields below are there for demonstration purposes. 25 | // The only field we use in this example is the 'log.data' + 'log.address' + 'log.topic0' so you could create a faster query by removing others. 26 | "fieldSelection": { 27 | "block": [ 28 | BlockField.Number, 29 | BlockField.Timestamp, 30 | BlockField.Hash, 31 | ], 32 | "log": [ 33 | LogField.BlockNumber, 34 | LogField.LogIndex, 35 | LogField.TransactionIndex, 36 | LogField.TransactionHash, 37 | LogField.Data, 38 | LogField.Address, 39 | LogField.Topic0, 40 | LogField.Topic1, 41 | LogField.Topic2, 42 | LogField.Topic3, 43 | ], 44 | "transaction": [ 45 | TransactionField.BlockNumber, 46 | TransactionField.TransactionIndex, 47 | TransactionField.Hash, 48 | TransactionField.From, 49 | TransactionField.To, 50 | TransactionField.Value, 51 | TransactionField.Input, 52 | ] 53 | }, 54 | }; 55 | 56 | console.log("Running the query..."); 57 | 58 | // Run the query once, the query is automatically paginated so it will return when it reaches some limit (time, response size etc.) 59 | // there is a nextBlock field on the response object so we can set the fromBlock of our query to this value and continue our query until 60 | // res.nextBlock is equal to res.archiveHeight or query.toBlock in case we specified an end block. 61 | const res = await client.get(query); 62 | 63 | console.log(`Ran the query once. Next block to query is ${res.nextBlock}`); 64 | 65 | // Create a decoder with our mapping 66 | const decoder = Decoder.fromSignatures([ 67 | "Transfer(address indexed from, address indexed to, uint amount)" 68 | ]); 69 | 70 | // Decode the log on a background thread so we don't block the event loop. 71 | // Can also use decoder.decodeLogsSync rather than using this promise api if it is more convenient. 72 | const decodedLogs = await decoder.decodeLogs(res.data.logs); 73 | 74 | // Let's count total volume, it is meaningless because of currency differences but good as an example. 75 | let total_volume = BigInt(0); 76 | 77 | for (const log of decodedLogs) { 78 | // skip invalid logs 79 | if (log === null) { 80 | continue; 81 | } 82 | // We know it is a bigint because of the signature 83 | total_volume += log.body[0].val as bigint; 84 | } 85 | 86 | const totalBlocks = res.nextBlock - query.fromBlock; 87 | 88 | console.log(`Total volume was ${total_volume} in ${totalBlocks} blocks in ${res.data.logs.length} transfers.`); 89 | } 90 | 91 | main(); 92 | -------------------------------------------------------------------------------- /examples/all-erc20/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es2020", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist" 9 | }, 10 | "lib": ["es2015"] 11 | } 12 | -------------------------------------------------------------------------------- /examples/call_watch/README.md: -------------------------------------------------------------------------------- 1 | # Watch example 2 | 3 | Example of using hypersync-client to watch for new events of a contract. 4 | 5 | Can run `npx tsc && node dist/app.js` to run it. 6 | -------------------------------------------------------------------------------- /examples/call_watch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "watch-example", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/node": "^20.10.3", 14 | "typescript": "^5.3.2" 15 | }, 16 | "dependencies": { 17 | "@envio-dev/hypersync-client": "../.." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/call_watch/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@envio-dev/hypersync-client': 9 | specifier: ../.. 10 | version: link:../.. 11 | 12 | devDependencies: 13 | '@types/node': 14 | specifier: ^20.10.3 15 | version: 20.16.1 16 | typescript: 17 | specifier: ^5.3.2 18 | version: 5.5.4 19 | 20 | packages: 21 | 22 | /@types/node@20.16.1: 23 | resolution: {integrity: sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==} 24 | dependencies: 25 | undici-types: 6.19.8 26 | dev: true 27 | 28 | /typescript@5.5.4: 29 | resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} 30 | engines: {node: '>=14.17'} 31 | hasBin: true 32 | dev: true 33 | 34 | /undici-types@6.19.8: 35 | resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} 36 | dev: true 37 | -------------------------------------------------------------------------------- /examples/call_watch/src/app.ts: -------------------------------------------------------------------------------- 1 | import {HypersyncClient, Decoder, LogField} from "@envio-dev/hypersync-client"; 2 | import fs from "node:fs"; 3 | import {CallDecoder, TransactionField} from "../../../index"; 4 | 5 | const DAI_ADDRESS = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; 6 | 7 | async function main() { 8 | // Create hypersync client using the mainnet hypersync endpoint 9 | const client = HypersyncClient.new({ 10 | url: "https://eth.hypersync.xyz" 11 | }); 12 | 13 | // The query to run 14 | const query = { 15 | // start from tip of the chain 16 | "fromBlock": 20500000, 17 | "transactions": [ 18 | { 19 | "from": [DAI_ADDRESS] 20 | }, 21 | { 22 | "to": [DAI_ADDRESS] 23 | } 24 | ], 25 | // Select the fields we are interested in, notice topics are selected as topic0,1,2,3 26 | "fieldSelection": { 27 | "transaction": [ 28 | TransactionField.Hash, 29 | TransactionField.Input, 30 | ] 31 | }, 32 | }; 33 | 34 | const decoder = CallDecoder.fromSignatures([ 35 | "transfer(address dst, uint256 wad)", 36 | ]); 37 | 38 | 39 | while (true) { 40 | const res = await client.get(query); 41 | if (res.data.transactions.length !== 0) { 42 | // Decode the log on a background thread so we don't block the event loop. 43 | // Can also use decoder.decodeLogsSync if it is more convenient. 44 | const decodedInputs = await decoder.decodeTransactionsInput(res.data.transactions); 45 | for (const input of decodedInputs) { 46 | if (input === null) { 47 | continue; 48 | } 49 | console.log(`Transaction decoded. Addr ${input[0].val}, Wad ${input[1].val}`); 50 | } 51 | } else { 52 | console.log(`no tx`); 53 | } 54 | let height = res.archiveHeight; 55 | while (height < res.nextBlock) { 56 | // wait if we are at the head 57 | console.log(`waiting for chain to advance. Height is ${height}`); 58 | height = await client.getHeight(); 59 | await new Promise(resolve => setTimeout(resolve, 1000)); 60 | } 61 | 62 | // Continue query from nextBlock 63 | query.fromBlock = res.nextBlock; 64 | } 65 | } 66 | 67 | main(); 68 | -------------------------------------------------------------------------------- /examples/call_watch/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es2020", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist" 9 | }, 10 | "lib": ["es2015"] 11 | } 12 | -------------------------------------------------------------------------------- /examples/parquet-out/README.md: -------------------------------------------------------------------------------- 1 | # Parquet output example 2 | 3 | Example of using hypersync-client to get bulk data into parquet files. 4 | 5 | Can run `npx tsc && node dist/app.js` to run it. 6 | -------------------------------------------------------------------------------- /examples/parquet-out/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parquet-out", 3 | "version": "0.1.4", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/node": "^20.10.3", 14 | "typescript": "^5.3.2" 15 | }, 16 | "dependencies": { 17 | "@envio-dev/hypersync-client": "../.." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/parquet-out/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@envio-dev/hypersync-client': 9 | specifier: ../.. 10 | version: link:../.. 11 | 12 | devDependencies: 13 | '@types/node': 14 | specifier: ^20.10.3 15 | version: 20.10.4 16 | typescript: 17 | specifier: ^5.3.2 18 | version: 5.3.3 19 | 20 | packages: 21 | 22 | /@types/node@20.10.4: 23 | resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} 24 | dependencies: 25 | undici-types: 5.26.5 26 | dev: true 27 | 28 | /typescript@5.3.3: 29 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 30 | engines: {node: '>=14.17'} 31 | hasBin: true 32 | dev: true 33 | 34 | /undici-types@5.26.5: 35 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 36 | dev: true 37 | -------------------------------------------------------------------------------- /examples/parquet-out/src/app.ts: -------------------------------------------------------------------------------- 1 | import { DataType, HexOutput, HypersyncClient, LogField } from "@envio-dev/hypersync-client"; 2 | 3 | async function main() { 4 | // Create hypersync client using the mainnet hypersync endpoint 5 | const client = HypersyncClient.new({ 6 | url: "https://eth.hypersync.xyz", 7 | }); 8 | 9 | // The query to run 10 | const query = { 11 | "fromBlock": 18500123, 12 | "toBlock": 18501123, 13 | "logs": [{ 14 | "address": ["0xdAC17F958D2ee523a2206206994597C13D831ec7"], 15 | "topics": [["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]], 16 | }], 17 | // Select the fields we are interested in, notice topics are selected as topic0,1,2,3 18 | "fieldSelection": { 19 | "log": [ 20 | LogField.BlockNumber, 21 | LogField.LogIndex, 22 | LogField.TransactionIndex, 23 | LogField.TransactionHash, 24 | LogField.Data, 25 | LogField.Address, 26 | LogField.Topic0, 27 | LogField.Topic1, 28 | LogField.Topic2, 29 | LogField.Topic3, 30 | ], 31 | }, 32 | }; 33 | 34 | console.log("Downloading data into parquet... This might take some time depending on connection speed"); 35 | 36 | await client.collectParquet("data", query, { 37 | /// Convert binary columns to prefixed hex format like '0x1ab..' 38 | hexOutput: HexOutput.Prefixed, 39 | columnMapping: { 40 | decodedLog: { 41 | "value": DataType.Float64, 42 | }, 43 | }, 44 | eventSignature: "Transfer(address indexed from, address indexed to, uint256 value)", 45 | }); 46 | 47 | console.log("finished writing parquet"); 48 | } 49 | 50 | main(); 51 | -------------------------------------------------------------------------------- /examples/parquet-out/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es2020", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist" 9 | }, 10 | "lib": ["es2015"] 11 | } 12 | -------------------------------------------------------------------------------- /examples/reverse_wallet/README.md: -------------------------------------------------------------------------------- 1 | # Reverse wallet example 2 | 3 | Example of using hypersync-client to get all transactions data for specific of an address in reverse order. 4 | 5 | Can run `npx tsc && node dist/app.js` to run it. 6 | -------------------------------------------------------------------------------- /examples/reverse_wallet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reverse_wallet", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/node": "^20.10.3", 14 | "typescript": "^5.3.2" 15 | }, 16 | "dependencies": { 17 | "@envio-dev/hypersync-client": "../.." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/reverse_wallet/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@envio-dev/hypersync-client': 9 | specifier: ../.. 10 | version: link:../.. 11 | 12 | devDependencies: 13 | '@types/node': 14 | specifier: ^20.10.3 15 | version: 20.10.4 16 | typescript: 17 | specifier: ^5.3.2 18 | version: 5.3.3 19 | 20 | packages: 21 | 22 | /@types/node@20.10.4: 23 | resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} 24 | dependencies: 25 | undici-types: 5.26.5 26 | dev: true 27 | 28 | /typescript@5.3.3: 29 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 30 | engines: {node: '>=14.17'} 31 | hasBin: true 32 | dev: true 33 | 34 | /undici-types@5.26.5: 35 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 36 | dev: true 37 | -------------------------------------------------------------------------------- /examples/reverse_wallet/src/app.ts: -------------------------------------------------------------------------------- 1 | import { HypersyncClient, Decoder, TransactionField } from "@envio-dev/hypersync-client"; 2 | 3 | async function main() { 4 | // Create hypersync client using the mainnet hypersync endpoint 5 | const client = HypersyncClient.new({ 6 | url: "https://eth.hypersync.xyz" 7 | }); 8 | 9 | // The query to run 10 | const query = { 11 | "fromBlock": 0, 12 | "transactions": [ 13 | // get all transactions coming from and going to our address. 14 | { 15 | from: ["0x5a830d7a5149b2f1a2e72d15cd51b84379ee81e5"] 16 | }, 17 | { 18 | to: ["0x5a830d7a5149b2f1a2e72d15cd51b84379ee81e5"] 19 | } 20 | ], 21 | "fieldSelection": { 22 | "transaction": [ 23 | TransactionField.BlockNumber, 24 | TransactionField.Hash, 25 | TransactionField.From, 26 | TransactionField.To, 27 | TransactionField.Value, 28 | ] 29 | } 30 | }; 31 | 32 | // Stream data in reverse order 33 | // 34 | // This will parallelize internal requests so we don't have to worry about pipelining/parallelizing make request -> handle response -> handle data loop 35 | const receiver = await client.stream(query, { reverse: true }); 36 | 37 | while (true) { 38 | let res = await receiver.recv(); 39 | if (res === null) { 40 | break; 41 | } 42 | for (const tx of res.data.transactions) { 43 | console.log(tx); 44 | } 45 | } 46 | } 47 | 48 | main(); 49 | -------------------------------------------------------------------------------- /examples/reverse_wallet/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es2020", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist" 9 | }, 10 | "lib": ["es2015"] 11 | } 12 | -------------------------------------------------------------------------------- /examples/simple-blocks-and-transaction-hashes/README.md: -------------------------------------------------------------------------------- 1 | # Wallet example 2 | 3 | Example of using hypersync-client to get all blocks and transaction hashes (not whole transaction objects) within a block range. 4 | 5 | Can run `npx tsc && node dist/app.js` to run it. 6 | -------------------------------------------------------------------------------- /examples/simple-blocks-and-transaction-hashes/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wallet", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/node": "^20.10.3", 14 | "typescript": "^5.3.2" 15 | }, 16 | "dependencies": { 17 | "@envio-dev/hypersync-client": "../.." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/simple-blocks-and-transaction-hashes/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@envio-dev/hypersync-client': 9 | specifier: ../.. 10 | version: link:../.. 11 | 12 | devDependencies: 13 | '@types/node': 14 | specifier: ^20.10.3 15 | version: 20.10.4 16 | typescript: 17 | specifier: ^5.3.2 18 | version: 5.3.3 19 | 20 | packages: 21 | 22 | /@types/node@20.10.4: 23 | resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} 24 | dependencies: 25 | undici-types: 5.26.5 26 | dev: true 27 | 28 | /typescript@5.3.3: 29 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 30 | engines: {node: '>=14.17'} 31 | hasBin: true 32 | dev: true 33 | 34 | /undici-types@5.26.5: 35 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 36 | dev: true 37 | -------------------------------------------------------------------------------- /examples/simple-blocks-and-transaction-hashes/src/app.ts: -------------------------------------------------------------------------------- 1 | import { HypersyncClient, presetQueryBlocksAndTransactionHashes } from "@envio-dev/hypersync-client"; 2 | 3 | async function main() { 4 | // Create hypersync client using the mainnet hypersync endpoint 5 | const client = HypersyncClient.new({ 6 | url: "https://eth.hypersync.xyz" 7 | }); 8 | 9 | // query is inclusive of from_block, exclusive of to_block so this will return 49 blocks 10 | let query = presetQueryBlocksAndTransactionHashes(17_000_000, 17_000_050); 11 | 12 | console.log("Running the query..."); 13 | 14 | // Run the query once, the query is automatically paginated so it will return when it reaches some limit (time, response size etc.) 15 | // there is a nextBlock field on the response object so we can set the fromBlock of our query to this value and continue our query until 16 | // res.nextBlock is equal to res.archiveHeight or query.toBlock in case we specified an end block. 17 | const res = await client.get(query); 18 | 19 | console.log(`Query returned ${res.data.blocks.length} blocks and ${res.data.transactions.length} transaction hashes`) 20 | } 21 | 22 | main(); 23 | -------------------------------------------------------------------------------- /examples/simple-blocks-and-transaction-hashes/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es2020", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist" 9 | }, 10 | "lib": ["es2015"] 11 | } 12 | -------------------------------------------------------------------------------- /examples/simple-blocks-and-transactions/README.md: -------------------------------------------------------------------------------- 1 | # Wallet example 2 | 3 | Example of using hypersync-client to get all blocks and transactions within a block range. 4 | 5 | Can run `npx tsc && node dist/app.js` to run it. 6 | -------------------------------------------------------------------------------- /examples/simple-blocks-and-transactions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wallet", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/node": "^20.10.3", 14 | "typescript": "^5.3.2" 15 | }, 16 | "dependencies": { 17 | "@envio-dev/hypersync-client": "../.." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/simple-blocks-and-transactions/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@envio-dev/hypersync-client': 9 | specifier: ../.. 10 | version: link:../.. 11 | 12 | devDependencies: 13 | '@types/node': 14 | specifier: ^20.10.3 15 | version: 20.10.4 16 | typescript: 17 | specifier: ^5.3.2 18 | version: 5.3.3 19 | 20 | packages: 21 | 22 | /@types/node@20.10.4: 23 | resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} 24 | dependencies: 25 | undici-types: 5.26.5 26 | dev: true 27 | 28 | /typescript@5.3.3: 29 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 30 | engines: {node: '>=14.17'} 31 | hasBin: true 32 | dev: true 33 | 34 | /undici-types@5.26.5: 35 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 36 | dev: true 37 | -------------------------------------------------------------------------------- /examples/simple-blocks-and-transactions/src/app.ts: -------------------------------------------------------------------------------- 1 | import { HypersyncClient, presetQueryBlocksAndTransactions } from "@envio-dev/hypersync-client"; 2 | 3 | async function main() { 4 | // Create hypersync client using the mainnet hypersync endpoint 5 | const client = HypersyncClient.new({ 6 | url: "https://eth.hypersync.xyz" 7 | }); 8 | 9 | // query is inclusive of from_block, exclusive of to_block so this will return 49 blocks 10 | let query = presetQueryBlocksAndTransactions(17_000_000, 17_000_050); 11 | 12 | console.log("Running the query..."); 13 | 14 | // Run the query once, the query is automatically paginated so it will return when it reaches some limit (time, response size etc.) 15 | // there is a nextBlock field on the response object so we can set the fromBlock of our query to this value and continue our query until 16 | // res.nextBlock is equal to res.archiveHeight or query.toBlock in case we specified an end block. 17 | const res = await client.get(query); 18 | 19 | console.log(`Query returned ${res.data.blocks.length} blocks and ${res.data.transactions.length} transactions`) 20 | } 21 | 22 | main(); 23 | -------------------------------------------------------------------------------- /examples/simple-blocks-and-transactions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es2020", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist" 9 | }, 10 | "lib": ["es2015"] 11 | } 12 | -------------------------------------------------------------------------------- /examples/simple-logs-of-event/README.md: -------------------------------------------------------------------------------- 1 | # Wallet example 2 | 3 | Example of using hypersync-client to get all logs from a contract's event in a block range. 4 | 5 | Can run `npx tsc && node dist/app.js` to run it. 6 | -------------------------------------------------------------------------------- /examples/simple-logs-of-event/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wallet", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/node": "^20.10.3", 14 | "typescript": "^5.3.2" 15 | }, 16 | "dependencies": { 17 | "@envio-dev/hypersync-client": "../.." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/simple-logs-of-event/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@envio-dev/hypersync-client': 9 | specifier: ../.. 10 | version: link:../.. 11 | 12 | devDependencies: 13 | '@types/node': 14 | specifier: ^20.10.3 15 | version: 20.10.4 16 | typescript: 17 | specifier: ^5.3.2 18 | version: 5.3.3 19 | 20 | packages: 21 | 22 | /@types/node@20.10.4: 23 | resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} 24 | dependencies: 25 | undici-types: 5.26.5 26 | dev: true 27 | 28 | /typescript@5.3.3: 29 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 30 | engines: {node: '>=14.17'} 31 | hasBin: true 32 | dev: true 33 | 34 | /undici-types@5.26.5: 35 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 36 | dev: true 37 | -------------------------------------------------------------------------------- /examples/simple-logs-of-event/src/app.ts: -------------------------------------------------------------------------------- 1 | import { HypersyncClient, presetQueryLogsOfEvent } from "@envio-dev/hypersync-client"; 2 | 3 | async function main() { 4 | // Create hypersync client using the mainnet hypersync endpoint 5 | const client = HypersyncClient.new({ 6 | url: "https://eth.hypersync.xyz" 7 | }); 8 | 9 | // address to get logs from 10 | const usdt_contract = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; 11 | 12 | // topic0 of transaction event signature (hash of event signature) 13 | // query will return logs of this event 14 | const event_topic_0 = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; 15 | 16 | // query is inclusive of from_block, exclusive of to_block so this will return 49 blocks 17 | let query = presetQueryLogsOfEvent(usdt_contract, event_topic_0, 17_000_000, 17_000_050); 18 | 19 | console.log("Running the query..."); 20 | 21 | // Run the query once, the query is automatically paginated so it will return when it reaches some limit (time, response size etc.) 22 | // there is a nextBlock field on the response object so we can set the fromBlock of our query to this value and continue our query until 23 | // res.nextBlock is equal to res.archiveHeight or query.toBlock in case we specified an end block. 24 | const res = await client.get(query); 25 | 26 | console.log(`Query returned ${res.data.logs.length} logs of transfer events from contract ${usdt_contract}`) 27 | 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/simple-logs-of-event/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es2020", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist" 9 | }, 10 | "lib": ["es2015"] 11 | } 12 | -------------------------------------------------------------------------------- /examples/simple-logs/README.md: -------------------------------------------------------------------------------- 1 | # Wallet example 2 | 3 | Example of using hypersync-client to get all logs from a contract in a block range. 4 | 5 | Can run `npx tsc && node dist/app.js` to run it. 6 | -------------------------------------------------------------------------------- /examples/simple-logs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wallet", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/node": "^20.10.3", 14 | "typescript": "^5.3.2" 15 | }, 16 | "dependencies": { 17 | "@envio-dev/hypersync-client": "../.." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/simple-logs/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@envio-dev/hypersync-client': 9 | specifier: ../.. 10 | version: link:../.. 11 | 12 | devDependencies: 13 | '@types/node': 14 | specifier: ^20.10.3 15 | version: 20.10.4 16 | typescript: 17 | specifier: ^5.3.2 18 | version: 5.3.3 19 | 20 | packages: 21 | 22 | /@types/node@20.10.4: 23 | resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} 24 | dependencies: 25 | undici-types: 5.26.5 26 | dev: true 27 | 28 | /typescript@5.3.3: 29 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 30 | engines: {node: '>=14.17'} 31 | hasBin: true 32 | dev: true 33 | 34 | /undici-types@5.26.5: 35 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 36 | dev: true 37 | -------------------------------------------------------------------------------- /examples/simple-logs/src/app.ts: -------------------------------------------------------------------------------- 1 | import { HypersyncClient, presetQueryLogs } from "@envio-dev/hypersync-client"; 2 | 3 | async function main() { 4 | // Create hypersync client using the mainnet hypersync endpoint 5 | const client = HypersyncClient.new({ 6 | url: "https://eth.hypersync.xyz" 7 | }); 8 | 9 | // address to get logs from 10 | const usdt_contract = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; 11 | 12 | // query is inclusive of from_block, exclusive of to_block so this will return 49 blocks 13 | let query = presetQueryLogs(usdt_contract, 17_000_000, 17_000_050); 14 | 15 | console.log("Running the query..."); 16 | 17 | // Run the query once, the query is automatically paginated so it will return when it reaches some limit (time, response size etc.) 18 | // there is a nextBlock field on the response object so we can set the fromBlock of our query to this value and continue our query until 19 | // res.nextBlock is equal to res.archiveHeight or query.toBlock in case we specified an end block. 20 | const res = await client.get(query); 21 | 22 | console.log(`Query returned ${res.data.logs.length} logs from contract ${usdt_contract}`) 23 | } 24 | 25 | main(); 26 | -------------------------------------------------------------------------------- /examples/simple-logs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es2020", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist" 9 | }, 10 | "lib": ["es2015"] 11 | } 12 | -------------------------------------------------------------------------------- /examples/wallet/README.md: -------------------------------------------------------------------------------- 1 | # Wallet example 2 | 3 | Example of using hypersync-client to get all transfer (Ether and erc20) data for specific set of addresses. 4 | 5 | Can run `npx tsc && node dist/app.js` to run it. 6 | -------------------------------------------------------------------------------- /examples/wallet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wallet", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/node": "^20.10.3", 14 | "typescript": "^5.3.2" 15 | }, 16 | "dependencies": { 17 | "@envio-dev/hypersync-client": "../.." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/wallet/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@envio-dev/hypersync-client': 9 | specifier: ../.. 10 | version: link:../.. 11 | 12 | devDependencies: 13 | '@types/node': 14 | specifier: ^20.10.3 15 | version: 20.10.4 16 | typescript: 17 | specifier: ^5.3.2 18 | version: 5.3.3 19 | 20 | packages: 21 | 22 | /@types/node@20.10.4: 23 | resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} 24 | dependencies: 25 | undici-types: 5.26.5 26 | dev: true 27 | 28 | /typescript@5.3.3: 29 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 30 | engines: {node: '>=14.17'} 31 | hasBin: true 32 | dev: true 33 | 34 | /undici-types@5.26.5: 35 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 36 | dev: true 37 | -------------------------------------------------------------------------------- /examples/wallet/src/app.ts: -------------------------------------------------------------------------------- 1 | import { HypersyncClient, Decoder, BlockField, LogField, TransactionField } from "@envio-dev/hypersync-client"; 2 | import fs from "node:fs"; 3 | 4 | // The addresses we want to get data for 5 | const addresses = [ 6 | "0xD1a923D70510814EaE7695A76326201cA06d080F".toLowerCase(), 7 | "0xc0A101c4E9Bb4463BD2F5d6833c2276C36914Fb6".toLowerCase(), 8 | "0xa0FBaEdC4C110f5A0c5E96c3eeAC9B5635b74CE7".toLowerCase(), 9 | "0x32448eb389aBe39b20d5782f04a8d71a2b2e7189".toLowerCase(), 10 | ]; 11 | 12 | // Convert address to topic for filtering. Padds the address with zeroes. 13 | function addressToTopic(address: string): string { 14 | return "0x000000000000000000000000" + address.slice(2, address.length); 15 | } 16 | 17 | async function main() { 18 | // Create hypersync client using the mainnet hypersync endpoint 19 | const client = HypersyncClient.new({ 20 | url: "https://eth.hypersync.xyz" 21 | }); 22 | 23 | const addressTopicFilter = addresses.map(addressToTopic); 24 | 25 | // The query to run 26 | const query = { 27 | // start from block 0 and go to the end of the chain (we don't specify a toBlock). 28 | "fromBlock": 0, 29 | // The logs we want. We will also automatically get transactions and blocks relating to these logs (the query implicitly joins them). 30 | "logs": [ 31 | { 32 | // We want All ERC20 transfers coming to any of our addresses 33 | "topics": [ 34 | ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"], 35 | [], 36 | addressTopicFilter, 37 | [], 38 | ] 39 | }, 40 | { 41 | // We want All ERC20 transfers going from any of our addresses 42 | "topics": [ 43 | ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"], 44 | addressTopicFilter, 45 | [], 46 | [], 47 | ] 48 | } 49 | ], 50 | "transactions": [ 51 | // get all transactions coming from and going to any of our addresses. 52 | { 53 | from: addresses 54 | }, 55 | { 56 | to: addresses 57 | } 58 | ], 59 | // Select the fields we are interested in, notice topics are selected as topic0,1,2,3 60 | "fieldSelection": { 61 | "block": [ 62 | BlockField.Number, 63 | BlockField.Timestamp, 64 | BlockField.Hash, 65 | ], 66 | "log": [ 67 | LogField.BlockNumber, 68 | LogField.LogIndex, 69 | LogField.TransactionIndex, 70 | LogField.TransactionHash, 71 | LogField.Data, 72 | LogField.Address, 73 | LogField.Topic0, 74 | LogField.Topic1, 75 | LogField.Topic2, 76 | LogField.Topic3, 77 | ], 78 | "transaction": [ 79 | TransactionField.BlockNumber, 80 | TransactionField.TransactionIndex, 81 | TransactionField.Hash, 82 | TransactionField.From, 83 | TransactionField.To, 84 | TransactionField.Value, 85 | TransactionField.Input, 86 | ] 87 | }, 88 | }; 89 | 90 | console.log("Running the query..."); 91 | 92 | // Run the query once, the query is automatically paginated so it will return when it reaches some limit (time, response size etc.) 93 | // there is a nextBlock field on the response object so we can set the fromBlock of our query to this value and continue our query until 94 | // res.nextBlock is equal to res.archiveHeight or query.toBlock in case we specified an end block. 95 | const res = await client.get(query); 96 | 97 | console.log(`Ran the query once. Next block to query is ${res.nextBlock}`); 98 | 99 | const decoder = Decoder.fromSignatures([ 100 | "Transfer(address indexed from, address indexed to, uint amount)" 101 | ]); 102 | 103 | // Decode the log on a background thread so we don't block the event loop. 104 | // Can also use decoder.decodeLogsSync if it is more convenient. 105 | const decodedLogs = await decoder.decodeLogs(res.data.logs); 106 | 107 | // Let's count total volume for each address, it is meaningless because of currency differences but good as an example. 108 | let total_erc20_volume = {}; 109 | 110 | for (const log of decodedLogs) { 111 | // skip invalid logs 112 | if (log === null) { 113 | continue; 114 | } 115 | 116 | if (!total_erc20_volume[log.indexed[0].val as string]) { 117 | total_erc20_volume[log.indexed[0].val as string] = BigInt(0); 118 | } 119 | if (!total_erc20_volume[log.indexed[1].val as string]) { 120 | total_erc20_volume[log.indexed[1].val as string] = BigInt(0); 121 | } 122 | // We count for both sides but we will filter by our addresses later so we will ignore unnecessary addresses. 123 | total_erc20_volume[log.indexed[0].val as string] += log.body[0].val as bigint; 124 | total_erc20_volume[log.indexed[1].val as string] += log.body[0].val as bigint; 125 | } 126 | 127 | for (const addr of addresses) { 128 | console.log(`Total erc20 transfer volume for address ${addr} is ${total_erc20_volume[addr]}`); 129 | } 130 | 131 | let total_wei_volume = {}; 132 | 133 | for (const tx of res.data.transactions) { 134 | if (!total_wei_volume[tx.from]) { 135 | total_wei_volume[tx.from] = BigInt(0); 136 | } 137 | if (!total_wei_volume[tx.to]) { 138 | total_wei_volume[tx.to] = BigInt(0); 139 | } 140 | 141 | total_wei_volume[tx.from] += BigInt(tx.value); 142 | total_wei_volume[tx.to] += BigInt(tx.value); 143 | } 144 | 145 | for (const addr of addresses) { 146 | console.log(`Total wei transfer wolume for address ${addr} is ${total_wei_volume[addr]}`); 147 | } 148 | } 149 | 150 | main(); 151 | -------------------------------------------------------------------------------- /examples/wallet/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es2020", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist" 9 | }, 10 | "lib": ["es2015"] 11 | } 12 | -------------------------------------------------------------------------------- /examples/watch/README.md: -------------------------------------------------------------------------------- 1 | # Watch example 2 | 3 | Example of using hypersync-client to watch for new events of a contract. 4 | 5 | Can run `npx tsc && node dist/app.js` to run it. 6 | -------------------------------------------------------------------------------- /examples/watch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "watch-example", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/node": "^20.10.3", 14 | "typescript": "^5.3.2" 15 | }, 16 | "dependencies": { 17 | "@envio-dev/hypersync-client": "../.." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/watch/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@envio-dev/hypersync-client': 9 | specifier: ../.. 10 | version: link:../.. 11 | 12 | devDependencies: 13 | '@types/node': 14 | specifier: ^20.10.3 15 | version: 20.10.4 16 | typescript: 17 | specifier: ^5.3.2 18 | version: 5.3.3 19 | 20 | packages: 21 | 22 | /@types/node@20.10.4: 23 | resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} 24 | dependencies: 25 | undici-types: 5.26.5 26 | dev: true 27 | 28 | /typescript@5.3.3: 29 | resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} 30 | engines: {node: '>=14.17'} 31 | hasBin: true 32 | dev: true 33 | 34 | /undici-types@5.26.5: 35 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 36 | dev: true 37 | -------------------------------------------------------------------------------- /examples/watch/src/app.ts: -------------------------------------------------------------------------------- 1 | import {HypersyncClient, Decoder, LogField} from "@envio-dev/hypersync-client"; 2 | import fs from "node:fs"; 3 | 4 | const DAI_ADDRESS = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; 5 | 6 | async function main() { 7 | // Create hypersync client using the mainnet hypersync endpoint 8 | const client = HypersyncClient.new({ 9 | url: "https://eth.hypersync.xyz" 10 | }); 11 | 12 | const height = await client.getHeight(); 13 | 14 | // The query to run 15 | const query = { 16 | // start from tip of the chain 17 | "fromBlock": height, 18 | "logs": [ 19 | { 20 | "address": [DAI_ADDRESS], 21 | // We want the transfers 22 | "topics": [ 23 | ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"], 24 | [], 25 | [], 26 | [], 27 | ] 28 | } 29 | ], 30 | // Select the fields we are interested in, notice topics are selected as topic0,1,2,3 31 | "fieldSelection": { 32 | "log": [ 33 | LogField.Data, 34 | LogField.Address, 35 | LogField.Topic0, 36 | LogField.Topic1, 37 | LogField.Topic2, 38 | LogField.Topic3, 39 | ] 40 | }, 41 | }; 42 | 43 | const decoder = Decoder.fromSignatures([ 44 | "Transfer(address indexed from, address indexed to, uint amount)" 45 | ]); 46 | 47 | let total_dai_volume = BigInt(0); 48 | 49 | while(true) { 50 | const res = await client.get(query); 51 | 52 | if(res.data.logs.length !== 0) { 53 | // Decode the log on a background thread so we don't block the event loop. 54 | // Can also use decoder.decodeLogsSync if it is more convenient. 55 | const decodedLogs = await decoder.decodeLogs(res.data.logs); 56 | 57 | for (const log of decodedLogs) { 58 | if (log === null) { 59 | continue; 60 | } 61 | total_dai_volume += log.body[0].val as bigint; 62 | } 63 | } 64 | 65 | console.log(`scanned up to ${res.nextBlock} and total DAI transfer volume is ${total_dai_volume / BigInt(1e18)} USD`); 66 | 67 | let height = res.archiveHeight; 68 | while (height < res.nextBlock) { 69 | // wait if we are at the head 70 | console.log(`waiting for chain to advance. Height is ${height}`); 71 | height = await client.getHeight(); 72 | await new Promise(resolve => setTimeout(resolve, 1000)); 73 | } 74 | 75 | // Continue query from nextBlock 76 | query.fromBlock = res.nextBlock; 77 | } 78 | } 79 | 80 | main(); 81 | -------------------------------------------------------------------------------- /examples/watch/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "target": "es2020", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "outDir": "dist" 9 | }, 10 | "lib": ["es2015"] 11 | } 12 | -------------------------------------------------------------------------------- /npm/darwin-arm64/README.md: -------------------------------------------------------------------------------- 1 | # `@envio-dev/hypersync-client-darwin-arm64` 2 | 3 | This is the **aarch64-apple-darwin** binary for `@envio-dev/hypersync-client` 4 | -------------------------------------------------------------------------------- /npm/darwin-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@envio-dev/hypersync-client-darwin-arm64", 3 | "version": "0.6.5", 4 | "os": [ 5 | "darwin" 6 | ], 7 | "cpu": [ 8 | "arm64" 9 | ], 10 | "main": "hypersync-client.darwin-arm64.node", 11 | "files": [ 12 | "hypersync-client.darwin-arm64.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /npm/darwin-x64/README.md: -------------------------------------------------------------------------------- 1 | # `@envio-dev/hypersync-client-darwin-x64` 2 | 3 | This is the **x86_64-apple-darwin** binary for `@envio-dev/hypersync-client` 4 | -------------------------------------------------------------------------------- /npm/darwin-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@envio-dev/hypersync-client-darwin-x64", 3 | "version": "0.6.5", 4 | "os": [ 5 | "darwin" 6 | ], 7 | "cpu": [ 8 | "x64" 9 | ], 10 | "main": "hypersync-client.darwin-x64.node", 11 | "files": [ 12 | "hypersync-client.darwin-x64.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /npm/linux-arm64-gnu/README.md: -------------------------------------------------------------------------------- 1 | # `@envio-dev/hypersync-client-linux-arm64-gnu` 2 | 3 | This is the **aarch64-unknown-linux-gnu** binary for `@envio-dev/hypersync-client` 4 | -------------------------------------------------------------------------------- /npm/linux-arm64-gnu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@envio-dev/hypersync-client-linux-arm64-gnu", 3 | "version": "0.6.5", 4 | "os": [ 5 | "linux" 6 | ], 7 | "cpu": [ 8 | "arm64" 9 | ], 10 | "main": "hypersync-client.linux-arm64-gnu.node", 11 | "files": [ 12 | "hypersync-client.linux-arm64-gnu.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | }, 18 | "libc": [ 19 | "glibc" 20 | ] 21 | } -------------------------------------------------------------------------------- /npm/linux-x64-gnu/README.md: -------------------------------------------------------------------------------- 1 | # `@envio-dev/hypersync-client-linux-x64-gnu` 2 | 3 | This is the **x86_64-unknown-linux-gnu** binary for `@envio-dev/hypersync-client` 4 | -------------------------------------------------------------------------------- /npm/linux-x64-gnu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@envio-dev/hypersync-client-linux-x64-gnu", 3 | "version": "0.6.5", 4 | "os": [ 5 | "linux" 6 | ], 7 | "cpu": [ 8 | "x64" 9 | ], 10 | "main": "hypersync-client.linux-x64-gnu.node", 11 | "files": [ 12 | "hypersync-client.linux-x64-gnu.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | }, 18 | "libc": [ 19 | "glibc" 20 | ] 21 | } -------------------------------------------------------------------------------- /npm/linux-x64-musl/README.md: -------------------------------------------------------------------------------- 1 | # `@envio-dev/hypersync-client-linux-x64-musl` 2 | 3 | This is the **x86_64-unknown-linux-musl** binary for `@envio-dev/hypersync-client` 4 | -------------------------------------------------------------------------------- /npm/linux-x64-musl/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@envio-dev/hypersync-client-linux-x64-musl", 3 | "version": "0.6.5", 4 | "os": [ 5 | "linux" 6 | ], 7 | "cpu": [ 8 | "x64" 9 | ], 10 | "main": "hypersync-client.linux-x64-musl.node", 11 | "files": [ 12 | "hypersync-client.linux-x64-musl.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | }, 18 | "libc": [ 19 | "musl" 20 | ] 21 | } -------------------------------------------------------------------------------- /npm/win32-x64-msvc/README.md: -------------------------------------------------------------------------------- 1 | # `@envio-dev/hypersync-client-win32-x64-msvc` 2 | 3 | This is the **x86_64-pc-windows-msvc** binary for `@envio-dev/hypersync-client` 4 | -------------------------------------------------------------------------------- /npm/win32-x64-msvc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@envio-dev/hypersync-client-win32-x64-msvc", 3 | "version": "0.6.5", 4 | "os": [ 5 | "win32" 6 | ], 7 | "cpu": [ 8 | "x64" 9 | ], 10 | "main": "hypersync-client.win32-x64-msvc.node", 11 | "files": [ 12 | "hypersync-client.win32-x64-msvc.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@envio-dev/hypersync-client", 3 | "description": "HyperSync Client by Envio", 4 | "version": "0.6.6", 5 | "main": "index.js", 6 | "types": "index.d.ts", 7 | "napi": { 8 | "name": "hypersync-client", 9 | "triples": { 10 | "additional": [ 11 | "aarch64-apple-darwin", 12 | "aarch64-unknown-linux-gnu", 13 | "x86_64-unknown-linux-musl" 14 | ] 15 | } 16 | }, 17 | "license": "MIT", 18 | "devDependencies": { 19 | "@napi-rs/cli": "^2.16.3", 20 | "ava": "^5.1.1", 21 | "typedoc": "^0.25.4", 22 | "typedoc-plugin-markdown": "^3.17.1", 23 | "typescript": "^5.3.2" 24 | }, 25 | "ava": { 26 | "timeout": "3m" 27 | }, 28 | "engines": { 29 | "node": ">= 10" 30 | }, 31 | "scripts": { 32 | "artifacts": "napi artifacts", 33 | "build": "napi build --platform --release --no-const-enum", 34 | "build:debug": "napi build --platform --no-const-enum", 35 | "prepublishOnly": "napi prepublish -t npm", 36 | "test": "ava", 37 | "universal": "napi universal", 38 | "version": "napi version", 39 | "docs": "yarn build && npx typedoc index.d.ts", 40 | "docs:md": "yarn build && npx typedoc --plugin typedoc-plugin-markdown index.d.ts" 41 | }, 42 | "packageManager": "yarn@3.8.1" 43 | } 44 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use anyhow::{Context, Result}; 4 | use serde::Serialize; 5 | 6 | #[napi(object)] 7 | #[derive(Default, Clone, Serialize)] 8 | pub struct StreamConfig { 9 | #[serde(skip_serializing_if = "Option::is_none")] 10 | pub column_mapping: Option, 11 | #[serde(skip_serializing_if = "Option::is_none")] 12 | pub event_signature: Option, 13 | #[serde(skip_serializing_if = "Option::is_none")] 14 | pub hex_output: Option, 15 | #[serde(skip_serializing_if = "Option::is_none")] 16 | pub batch_size: Option, 17 | #[serde(skip_serializing_if = "Option::is_none")] 18 | pub max_batch_size: Option, 19 | #[serde(skip_serializing_if = "Option::is_none")] 20 | pub min_batch_size: Option, 21 | #[serde(skip_serializing_if = "Option::is_none")] 22 | pub concurrency: Option, 23 | #[serde(skip_serializing_if = "Option::is_none")] 24 | pub max_num_blocks: Option, 25 | #[serde(skip_serializing_if = "Option::is_none")] 26 | pub max_num_transactions: Option, 27 | #[serde(skip_serializing_if = "Option::is_none")] 28 | pub max_num_logs: Option, 29 | #[serde(skip_serializing_if = "Option::is_none")] 30 | pub max_num_traces: Option, 31 | #[serde(skip_serializing_if = "Option::is_none")] 32 | pub response_bytes_ceiling: Option, 33 | #[serde(skip_serializing_if = "Option::is_none")] 34 | pub response_bytes_floor: Option, 35 | #[serde(skip_serializing_if = "Option::is_none")] 36 | pub reverse: Option, 37 | } 38 | 39 | #[napi(string_enum)] 40 | #[derive(Debug, Serialize)] 41 | pub enum HexOutput { 42 | NoEncode, 43 | Prefixed, 44 | NonPrefixed, 45 | } 46 | 47 | #[napi(string_enum)] 48 | #[derive(Debug, Serialize)] 49 | #[serde(rename_all = "lowercase")] 50 | pub enum DataType { 51 | Float64, 52 | Float32, 53 | UInt64, 54 | UInt32, 55 | Int64, 56 | Int32, 57 | } 58 | 59 | impl Default for HexOutput { 60 | fn default() -> Self { 61 | Self::NoEncode 62 | } 63 | } 64 | 65 | #[napi(object)] 66 | #[derive(Default, Clone, Serialize)] 67 | pub struct ColumnMapping { 68 | #[serde(skip_serializing_if = "Option::is_none")] 69 | pub block: Option>, 70 | #[serde(skip_serializing_if = "Option::is_none")] 71 | pub transaction: Option>, 72 | #[serde(skip_serializing_if = "Option::is_none")] 73 | pub log: Option>, 74 | #[serde(skip_serializing_if = "Option::is_none")] 75 | pub trace: Option>, 76 | #[serde(skip_serializing_if = "Option::is_none")] 77 | pub decoded_log: Option>, 78 | } 79 | 80 | impl StreamConfig { 81 | pub fn try_convert(&self) -> Result { 82 | let json = serde_json::to_vec(self).context("serialize to json")?; 83 | serde_json::from_slice(&json).context("parse json") 84 | } 85 | } 86 | 87 | #[napi(object)] 88 | #[derive(Default, Clone, Serialize)] 89 | pub struct ClientConfig { 90 | #[serde(skip_serializing_if = "Option::is_none")] 91 | pub url: Option, 92 | #[serde(skip_serializing_if = "Option::is_none")] 93 | pub bearer_token: Option, 94 | #[serde(skip_serializing_if = "Option::is_none")] 95 | pub http_req_timeout_millis: Option, 96 | #[serde(skip_serializing_if = "Option::is_none")] 97 | pub max_num_retries: Option, 98 | #[serde(skip_serializing_if = "Option::is_none")] 99 | pub retry_backoff_ms: Option, 100 | #[serde(skip_serializing_if = "Option::is_none")] 101 | pub retry_base_ms: Option, 102 | #[serde(skip_serializing_if = "Option::is_none")] 103 | pub retry_ceiling_ms: Option, 104 | #[serde(skip)] 105 | pub enable_checksum_addresses: Option, 106 | } 107 | 108 | impl ClientConfig { 109 | pub fn try_convert(&self) -> Result { 110 | let json = serde_json::to_vec(self).context("serialize to json")?; 111 | serde_json::from_slice(&json).context("parse json") 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/decode.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use anyhow::{Context, Result}; 4 | use hypersync_client::format::{Data, Hex, LogArgument}; 5 | 6 | use crate::{ 7 | map_err, 8 | types::{DecodedEvent, DecodedSolValue, Event, Log}, 9 | }; 10 | 11 | #[napi] 12 | #[derive(Clone)] 13 | pub struct Decoder { 14 | inner: Arc, 15 | checksummed_addresses: bool, 16 | } 17 | 18 | #[napi] 19 | impl Decoder { 20 | #[napi] 21 | pub fn from_signatures(signatures: Vec) -> napi::Result { 22 | let inner = hypersync_client::Decoder::from_signatures(&signatures) 23 | .context("create inner decoder") 24 | .map_err(map_err)?; 25 | Ok(Self { 26 | inner: Arc::new(inner), 27 | checksummed_addresses: false, 28 | }) 29 | } 30 | 31 | #[napi] 32 | pub fn from_signatures_with_checksum( 33 | signatures: Vec, 34 | checksum: bool, 35 | ) -> napi::Result { 36 | let inner = hypersync_client::Decoder::from_signatures(&signatures) 37 | .context("create inner decoder") 38 | .map_err(map_err)?; 39 | Ok(Self { 40 | inner: Arc::new(inner), 41 | checksummed_addresses: checksum, 42 | }) 43 | } 44 | 45 | #[napi] 46 | pub fn enable_checksummed_addresses(&mut self) { 47 | self.checksummed_addresses = true; 48 | } 49 | 50 | #[napi] 51 | pub fn disable_checksummed_addresses(&mut self) { 52 | self.checksummed_addresses = false; 53 | } 54 | 55 | #[napi] 56 | pub async fn decode_logs(&self, logs: Vec) -> Vec> { 57 | let decoder = self.clone(); 58 | tokio::task::spawn_blocking(move || decoder.decode_logs_sync(logs)) 59 | .await 60 | .unwrap() 61 | } 62 | 63 | #[napi] 64 | pub fn decode_logs_sync(&self, logs: Vec) -> Vec> { 65 | logs.iter() 66 | .map(|log| self.decode_impl(log).ok().flatten()) 67 | .collect::>() 68 | } 69 | 70 | #[napi] 71 | pub async fn decode_events(&self, events: Vec) -> Vec> { 72 | let decoder = self.clone(); 73 | tokio::task::spawn_blocking(move || decoder.decode_events_sync(events)) 74 | .await 75 | .unwrap() 76 | } 77 | 78 | #[napi] 79 | pub fn decode_events_sync(&self, events: Vec) -> Vec> { 80 | events 81 | .iter() 82 | .map(|event| self.decode_impl(&event.log).ok().flatten()) 83 | .collect::>() 84 | } 85 | 86 | fn decode_impl(&self, log: &Log) -> Result> { 87 | let topics = log 88 | .topics 89 | .iter() 90 | .map(|v| { 91 | v.as_ref() 92 | .map(|v| LogArgument::decode_hex(v).context("decode topic")) 93 | .transpose() 94 | }) 95 | .collect::>>() 96 | .context("decode topics")?; 97 | 98 | let topic0 = topics 99 | .first() 100 | .context("get topic0")? 101 | .as_ref() 102 | .context("topic0 is null")?; 103 | 104 | let data = log.data.as_ref().context("get log.data")?; 105 | let data = Data::decode_hex(data).context("decode data")?; 106 | 107 | let decoded = match self 108 | .inner 109 | .decode(topic0.as_slice(), &topics, &data) 110 | .context("decode log")? 111 | { 112 | Some(v) => v, 113 | None => return Ok(None), 114 | }; 115 | 116 | Ok(Some(DecodedEvent { 117 | indexed: decoded 118 | .indexed 119 | .into_iter() 120 | .map(|v| DecodedSolValue::new(v, self.checksummed_addresses)) 121 | .collect(), 122 | body: decoded 123 | .body 124 | .into_iter() 125 | .map(|v| DecodedSolValue::new(v, self.checksummed_addresses)) 126 | .collect(), 127 | })) 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/decode_call.rs: -------------------------------------------------------------------------------- 1 | use crate::map_err; 2 | use crate::types::{DecodedSolValue, Trace, Transaction}; 3 | use anyhow::Context; 4 | use hypersync_client::format::{Data, Hex}; 5 | use std::sync::Arc; 6 | 7 | #[napi] 8 | #[derive(Clone)] 9 | pub struct CallDecoder { 10 | inner: Arc, 11 | checksummed_addresses: bool, 12 | } 13 | 14 | #[napi] 15 | impl CallDecoder { 16 | #[napi] 17 | pub fn from_signatures(signatures: Vec) -> napi::Result { 18 | let inner = hypersync_client::CallDecoder::from_signatures(&signatures) 19 | .context("build inner decoder") 20 | .map_err(map_err)?; 21 | 22 | Ok(Self { 23 | inner: Arc::new(inner), 24 | checksummed_addresses: false, 25 | }) 26 | } 27 | 28 | #[napi] 29 | pub fn from_signatures_with_checksum( 30 | signatures: Vec, 31 | checksum: bool, 32 | ) -> napi::Result { 33 | let inner = hypersync_client::CallDecoder::from_signatures(&signatures) 34 | .context("build inner decoder") 35 | .map_err(map_err)?; 36 | 37 | Ok(Self { 38 | inner: Arc::new(inner), 39 | checksummed_addresses: checksum, 40 | }) 41 | } 42 | 43 | pub fn enable_checksummed_addresses(&mut self) { 44 | self.checksummed_addresses = true; 45 | } 46 | 47 | pub fn disable_checksummed_addresses(&mut self) { 48 | self.checksummed_addresses = false; 49 | } 50 | 51 | #[napi] 52 | pub async fn decode_inputs(&self, inputs: Vec) -> Vec>> { 53 | let decoder = self.clone(); 54 | 55 | tokio::task::spawn_blocking(move || decoder.decode_inputs_sync(inputs)) 56 | .await 57 | .unwrap() 58 | } 59 | 60 | #[napi] 61 | 62 | pub async fn decode_transactions_input( 63 | &self, 64 | txs: Vec, 65 | ) -> Vec>> { 66 | let decoder = self.clone(); 67 | 68 | tokio::task::spawn_blocking(move || decoder.decode_transactions_input_sync(txs)) 69 | .await 70 | .unwrap() 71 | } 72 | 73 | #[napi] 74 | pub async fn decode_traces_input( 75 | &self, 76 | traces: Vec, 77 | ) -> Vec>> { 78 | let decoder = self.clone(); 79 | 80 | tokio::task::spawn_blocking(move || decoder.decode_traces_input_sync(traces)) 81 | .await 82 | .unwrap() 83 | } 84 | 85 | #[napi] 86 | pub fn decode_inputs_sync(&self, inputs: Vec) -> Vec>> { 87 | inputs 88 | .into_iter() 89 | .map(|input| self.decode_impl(input)) 90 | .collect() 91 | } 92 | 93 | #[napi] 94 | pub fn decode_transactions_input_sync( 95 | &self, 96 | txs: Vec, 97 | ) -> Vec>> { 98 | txs.into_iter() 99 | .map(|tx| self.decode_impl(tx.input?)) 100 | .collect() 101 | } 102 | 103 | #[napi] 104 | pub fn decode_traces_input_sync( 105 | &self, 106 | traces: Vec, 107 | ) -> Vec>> { 108 | traces 109 | .into_iter() 110 | .map(|trace| self.decode_impl(trace.input?)) 111 | .collect() 112 | } 113 | 114 | #[napi] 115 | pub fn decode_impl(&self, input: String) -> Option> { 116 | let input = Data::decode_hex(input.as_str()) 117 | .context("decode input") 118 | .unwrap(); 119 | let decoded_input = self 120 | .inner 121 | .decode_input(&input) 122 | .context("decode log") 123 | .unwrap(); 124 | decoded_input.map(|decoded_input| { 125 | decoded_input 126 | .into_iter() 127 | .map(|value| DecodedSolValue::new(value, self.checksummed_addresses)) 128 | .collect() 129 | }) 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/preset_query.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context; 2 | use hypersync_client::{ 3 | format::{Address, Hex, LogArgument}, 4 | preset_query, 5 | }; 6 | 7 | use crate::{map_err, query::Query}; 8 | 9 | /// Returns a query for all Blocks and Transactions within the block range (from_block, to_block] 10 | /// If to_block is None then query runs to the head of the chain. 11 | #[napi] 12 | pub fn preset_query_blocks_and_transactions( 13 | from_block: i64, 14 | to_block: Option, 15 | ) -> napi::Result { 16 | let from_block = from_block 17 | .try_into() 18 | .context("convert from_block") 19 | .map_err(map_err)?; 20 | let to_block = to_block 21 | .map(|t| t.try_into().context("convert to_block")) 22 | .transpose() 23 | .map_err(map_err)?; 24 | 25 | let query: Query = preset_query::blocks_and_transactions(from_block, to_block) 26 | .try_into() 27 | .map_err(map_err)?; 28 | 29 | Ok(query) 30 | } 31 | 32 | /// Returns a query object for all Blocks and hashes of the Transactions within the block range 33 | /// (from_block, to_block]. Also returns the block_hash and block_number fields on each Transaction 34 | /// so it can be mapped to a block. If to_block is None then query runs to the head of the chain. 35 | #[napi] 36 | pub fn preset_query_blocks_and_transaction_hashes( 37 | from_block: i64, 38 | to_block: Option, 39 | ) -> napi::Result { 40 | let from_block = from_block 41 | .try_into() 42 | .context("convert from_block") 43 | .map_err(map_err)?; 44 | let to_block = to_block 45 | .map(|t| t.try_into().context("convert to_block")) 46 | .transpose() 47 | .map_err(map_err)?; 48 | 49 | let query: Query = preset_query::blocks_and_transaction_hashes(from_block, to_block) 50 | .try_into() 51 | .map_err(map_err)?; 52 | 53 | Ok(query) 54 | } 55 | 56 | /// Returns a query object for all Logs within the block range from the given address. 57 | /// If to_block is None then query runs to the head of the chain. 58 | #[napi] 59 | pub fn preset_query_logs( 60 | contract_address: String, 61 | from_block: i64, 62 | to_block: Option, 63 | ) -> napi::Result { 64 | let address = Address::decode_hex(&contract_address) 65 | .context("parse address") 66 | .map_err(map_err)?; 67 | 68 | let from_block = from_block 69 | .try_into() 70 | .context("convert from_block") 71 | .map_err(map_err)?; 72 | let to_block = to_block 73 | .map(|t| t.try_into().context("convert to_block")) 74 | .transpose() 75 | .map_err(map_err)?; 76 | 77 | preset_query::logs(from_block, to_block, address) 78 | .try_into() 79 | .map_err(map_err) 80 | } 81 | 82 | /// Returns a query for all Logs within the block range from the given address with a 83 | /// matching topic0 event signature. Topic0 is the keccak256 hash of the event signature. 84 | /// If to_block is None then query runs to the head of the chain. 85 | #[napi] 86 | pub fn preset_query_logs_of_event( 87 | contract_address: String, 88 | topic0: String, 89 | from_block: i64, 90 | to_block: Option, 91 | ) -> napi::Result { 92 | let address = Address::decode_hex(&contract_address) 93 | .context("parse address") 94 | .map_err(map_err)?; 95 | let topic0 = LogArgument::decode_hex(&topic0) 96 | .context("parse topic0") 97 | .map_err(map_err)?; 98 | 99 | let from_block = from_block 100 | .try_into() 101 | .context("convert from_block") 102 | .map_err(map_err)?; 103 | let to_block = to_block 104 | .map(|t| t.try_into().context("convert to_block")) 105 | .transpose() 106 | .map_err(map_err)?; 107 | 108 | let query = preset_query::logs_of_event(from_block, to_block, topic0, address) 109 | .try_into() 110 | .map_err(map_err)?; 111 | Ok(query) 112 | } 113 | --------------------------------------------------------------------------------