Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update docs #200

Merged
merged 1 commit into from
Jan 14, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
```ts
export interface AbiStore<Key = AbiParams, Value = ContractAbiResult> {
readonly strategies: Record<ChainOrDefault, readonly ContractAbiResolverStrategy[]>
readonly set: (key: Key, value: Value) => Effect.Effect<void, never>
readonly get: (arg: Key) => Effect.Effect<Value, never>
readonly getMany?: (arg: Array<Key>) => Effect.Effect<Array<Value>, never>
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
```ts
export interface ContractMetaStore<Key = ContractMetaParams, Value = ContractMetaResult> {
readonly strategies: Record<ChainOrDefault, readonly ContractMetaResolverStrategy[]>
readonly set: (arg: Key, value: Value) => Effect.Effect<void, never>
readonly get: (arg: Key) => Effect.Effect<Value, never>
readonly getMany?: (arg: Array<Key>) => Effect.Effect<Array<Value>, never>
}
```
15 changes: 15 additions & 0 deletions apps/docs/src/content/components/effect-rpc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
```ts title="provider.ts"
import { PublicClient, PublicClientObject, UnknownNetwork } from '@3loop/transaction-decoder'
import { Effect } from 'effect'

const getPublicClient = (chainID: number): Effect.Effect<PublicClientObject, UnknownNetwork> => {
if (chainID === 1) {
return Effect.succeed({
client: createPublicClient({
transport: http('https://rpc.ankr.com/eth'),
}),
})
}
return Effect.fail(new UnknownNetwork(chainID))
}
```
2 changes: 1 addition & 1 deletion apps/docs/src/content/components/rpc-provider.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
```ts title="index.ts"
```ts title="provider.ts"
import { createPublicClient, http } from 'viem'

// Create a public client for the Ethereum Mainnet network
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ Loop Decoder provides a `decodeCalldata` method that decodes a transaction calld

To use `decodeCalldata` method, you need to setup a `TransactionDecoder` instance with the necessary data stores. For setup instructions, refer to:

- Setup with default in-memory data stores (the quickest way): [Getting Started](/welcome/getting-started/)
- Setup with built-in in-memory data stores (the quickest way): [Getting Started](/welcome/getting-started/)
- Setup with customizable data stores: [How To Decode Transaction (detailed)](/guides/decode-transaction/)

### Decoding Calldata
8 changes: 5 additions & 3 deletions apps/docs/src/content/docs/guides/decode-transaction.mdx
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
---
title: Decode an Ethereum Transaction (detailed)
title: Decoding Transaction
description: On this page you will provide a step-by-step guide on how to decode and interpret an Ethereum transaction using Loop Decoder.
sidebar:
order: 1
---

import { Content as MemoryAbiLoader } from '../../components/memory-abi-loader.md'

Check warning on line 8 in apps/docs/src/content/docs/guides/decode-transaction.mdx

GitHub Actions / pr

'MemoryAbiLoader' is defined but never used
import { Content as MemoryContractLoader } from '../../components/memory-contract-loader.md'

Check warning on line 9 in apps/docs/src/content/docs/guides/decode-transaction.mdx

GitHub Actions / pr

'MemoryContractLoader' is defined but never used
import { Content as RpcProvider } from '../../components/rpc-provider.md'

Check warning on line 10 in apps/docs/src/content/docs/guides/decode-transaction.mdx

GitHub Actions / pr

'RpcProvider' is defined but never used
import { Content as AbiStoreInterface } from '../../components/abi-store-interface.md'
import { Content as MetaStoreInterface } from '../../components/meta-store-interface.md'
import { Content as AbiStoreInterface } from '../../components/vanilla-abi-store-interface.md'

Check warning on line 11 in apps/docs/src/content/docs/guides/decode-transaction.mdx

GitHub Actions / pr

'AbiStoreInterface' is defined but never used
import { Content as MetaStoreInterface } from '../../components/vanilla-meta-store-interface.md'

Check warning on line 12 in apps/docs/src/content/docs/guides/decode-transaction.mdx

GitHub Actions / pr

'MetaStoreInterface' is defined but never used

This guide explains how to decode Ethereum transactions using Loop Decoder. We'll cover:

- Setting up data loading strategies for ABIs and contract metadata
- Configuring data stores for Contract ABIs and metadata
- Decoding transactions

[Learn more about Loop Decoder APIs and the differences between them](/reference/exposed-apis/)

## Installation

Generate and initialize a new project:
133 changes: 0 additions & 133 deletions apps/docs/src/content/docs/guides/effect-api.md

This file was deleted.

46 changes: 34 additions & 12 deletions apps/docs/src/content/docs/guides/sql-stores.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
---
title: SQL Data Store
title: Decoding Transaction with SQLite Data Store
description: An implementation of the Data Store interface using a SQL database based on @effect/sql
sidebar:
order: 4
order: 3
---

To use the default SQL stores you can import `SqlAbiStore` and `SqlContractMetaStore ` from the `@3loop/transaction-decoder/sql`.
Loop Decoder provides a built-in SQL Data Stores that can be used out of the box. The key benefits of using the built-in SQL stores are:

Given that the SQL stores are based on `@effect/sql` it inherits its SQL Client abstraction. For example we will use a Sqlite client for bun: `SqliteClient` from `@effect/sql-sqlite-bun` package.
- You don't need to write your own database schema, `get` or `set` methods for the [Data Stores](/reference/data-store).
- You will get enhanced performance for decoding transactions by caching the data in the persistent storage.
- You can use any database supported by [`@effect/sql`](https://github.com/Effect-TS/effect/tree/main/packages/sql).

### Example
To use the built-in SQL stores you can import `SqlAbiStore` and `SqlContractMetaStore` from the `@3loop/transaction-decoder/sql`.

This example implements a CLI that will use Sqlite as a cache for the ABIs and Contract Metadata stores. It will decode any transaction by chain id an transaction hash. The more its is used the more data will be cached in the database, thus making it faster to decode transactions.
## Example

In this example we will use a Sqlite client for bun: `SqliteClient` from `@effect/sql-sqlite-bun` package.

The example implements a CLI that will use `Sqlite` as a cache for the ABIs and Contract Metadata stores. It will decode any transaction by chain ID and transaction hash. The more its is used the more data will be cached in the database, thus making it faster to decode transactions.

### Installation

You can add it directly into your project or create a new one.

```shell
$ mkdir transaction-decoder-cli && cd transaction-decoder-cli && bun init
mkdir transaction-decoder-cli && cd transaction-decoder-cli && bun init
```

We will start by installing the necessary dependencies:
Then install the necessary dependencies:

```shell
$ bun i viem effect @effect/sql @effect/sql-sqlite-bun @3loop/transaction-decoder
bun i viem effect @effect/sql @effect/sql-sqlite-bun @3loop/transaction-decoder
```

Then we will create a `index.ts` file with the following content:
### Setup Loop Decoder

Create a `index.ts` file with the following content:

```typescript
import { SqlAbiStore, SqlContractMetaStore } from '@3loop/transaction-decoder/sql'
import {
decodeTransactionByHash,
ERC20RPCStrategyResolver,
EtherscanV2StrategyResolver,
FourByteStrategyResolver,
NFTRPCStrategyResolver,
PublicClient,
} from '@3loop/transaction-decoder'
import { SqliteClient } from '@effect/sql-sqlite-bun'
@@ -69,7 +81,15 @@ export const RPCProviderLive = Layer.succeed(
}),
)

const MetaStoreLive = SqlContractMetaStore.make()
const MetaStoreLive = Layer.unwrapEffect(
Effect.gen(function* () {
const service = yield* PublicClient

return SqlContractMetaStore.make({
default: [ERC20RPCStrategyResolver(service), NFTRPCStrategyResolver(service)],
})
}),
)
const DataLayer = Layer.mergeAll(RPCProviderLive, SqlLive)
const LoadersLayer = Layer.mergeAll(AbiStoreLive, MetaStoreLive)
const MainLayer = Layer.provideMerge(LoadersLayer, DataLayer)
@@ -90,8 +110,10 @@ function main() {
main()
```

### Run the script

Now you can run this script with bun:

```
$ ETHERSCAN_API_KEY='YOUR_API_KEY' RPC_1=https://rpc.ankr.com/eth bun run index.ts 1 0xc0bd04d7e94542e58709f51879f64946ff4a744e1c37f5f920cea3d478e115d7
ETHERSCAN_API_KEY='YOUR_API_KEY' RPC_1=https://rpc.ankr.com/eth bun run index.ts 1 0xc0bd04d7e94542e58709f51879f64946ff4a744e1c37f5f920cea3d478e115d7
```
35 changes: 0 additions & 35 deletions apps/docs/src/content/docs/reference/data-loaders.md

This file was deleted.

101 changes: 101 additions & 0 deletions apps/docs/src/content/docs/reference/data-loaders.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: Data Loaders
description: Data Loaders used to fetch ABI and Contract Metadata required for decoding transactions
sidebar:
order: 3
---

import { Tabs, TabItem } from '@astrojs/starlight/components'

Data Loaders are mechanisms for retrieving the necessary ABI and Contract Metadata for transaction decoding. They are responsible for:

- Resolving ABIs and Contract Metadata using specified strategies and third-party APIs
- Automatically batching requests when processing logs and traces in parallel
- Caching request results in the [Data Store](/reference/data-store)

Loop Decoder implements optimizations to minimize API requests to third-party services. For example, when a contract’s ABI is resolved via Etherscan, it is cached in the store. If the ABI is requested again, the store provides the cached version, avoiding redundant API calls.

## ABI Strategies

ABI strategies will receive the contract address, and event or function signature as input and would return the ABI as a stringified JSON. Loop Decoder provides some strategies out of the box:

- `EtherscanStrategyResolver` - resolves the ABI from Etherscan, requires an API key to work properly
- `EtherscanV2StrategyResolver` - resolves the ABI from Etherscan v2, requires an API key to work properly
- `SourcifyStrategyResolver` - resolves the ABI from Sourcify
- `FourByteStrategyResolver` - resolves the ABI from 4byte.directory
- `OpenchainStrategyResolver` - resolves the ABI from Openchain
- `BlockscoutStrategyResolver` - resolves the ABI from Blockscout

You can create your strategy by implementing the `GetContractABIStrategy` Effect RequestResolver.

## Contract Metadata Strategies

Contract metadata is a collection of information about a contract, such as the contract's name, symbol, and decimals.

Loop Decoder provides some strategies out of the box:

- `ERC20RPCStrategyResolver` - resolves the contract metadata of an ERC20 token from the RPC
- `NFTRPCStrategyResolver` - resolves the contract metadata of an NFT token (ERC721, ERC1155) from the RPC
- `ProxyRPCStrategyResolver` - resolves the contract metadata of a Gnosis Safe proxy contract from the RPC

## Code Examples

### Initializing ABI Strategies

<Tabs>
<TabItem label="Effect API">
```typescript
const AbiStoreLive = SqlAbiStore.make({
default: [
EtherscanV2StrategyResolver({
apikey: process.env.ETHERSCAN_API_KEY,
}),
FourByteStrategyResolver(),
],
//...
})
```
</TabItem>
<TabItem label="Vanilla JS API">
```typescript
const abiStore: VanillaAbiStore = {
strategies: [
EtherscanStrategyResolver({
apikey: process.env.ETHERSCAN_API_KEY || '',
}),
FourByteStrategyResolver(),
],
//...
}
```
</TabItem>
</Tabs>

### Initializing Contract Metadata Strategies

<Tabs>
<TabItem label="Effect API">
```typescript
const MetaStoreLive = Layer.unwrapEffect(
Effect.gen(function* () {
const service = yield* PublicClient

return SqlContractMetaStore.make({
default: [ERC20RPCStrategyResolver(service), NFTRPCStrategyResolver(service)],
})

}),
)

````
</TabItem>
<TabItem label="Vanilla JS API">
```typescript
const contractMetaStore: VanillaContractMetaStore = {
strategies: [ERC20RPCStrategyResolver, NFTRPCStrategyResolver],
//...
}
````
</TabItem>
</Tabs>
167 changes: 0 additions & 167 deletions apps/docs/src/content/docs/reference/data-store.md

This file was deleted.

217 changes: 217 additions & 0 deletions apps/docs/src/content/docs/reference/data-store.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
---
title: Data Store
description: Data Storages are simple APIs that implement a key-value store for persistent cache.
sidebar:
order: 2
---

import { Content as VanillaABI } from '../../components/vanilla-abi-store-interface.md'
import { Content as VanillaMeta } from '../../components/vanilla-meta-store-interface.md'
import { Content as EffectABI } from '../../components/effect-abi-store-interface.md'
import { Content as EffectMeta } from '../../components/effect-meta-store-interface.md'
import { Content as MemoryAbiLoader } from '../../components/memory-abi-loader.md'
import { Content as MemoryContractLoader } from '../../components/memory-contract-loader.md'

Loop Decoder relies on two Data Stores - `AbiStore` and `ContractMetadataStore`. These stores are used for:

- Retrieving and caching data
- Fetching data from external sources using [Data Loaders](../data-loaders) (when not available in the cache)

The Data Store can be customized to suit different needs. Here are some common use cases and implementations:

- In-memory store: The simplest option, ideal for testing and development, available in Built-in Stores.
- Persistent store: Ideal for production environment and when you work with a large number of contracts that you do not know in advance. The store can get and set data to any external database. `SQL` is available in Built-in Stores.
- Static mapping: For applications that work with a fixed set of contracts, the store can get data from a hardcoded set of ABIs and metadata.
- REST API client: For browser-based applications, enabling ABI and contract metadata retrieval from a server

A store also requires a set of strategies that we cover separately in the [Data Loaders](../data-loaders) section.

### Built-in Stores

Loop Decoder provides two stores that can be used out of the box:

#### 1. In-memory stores (Vanilla JS API)

Located at `@3loop/transaction-decoder/in-memory`, ideal for testing and development purposes.

- `InMemoryAbiStore` - caches the resolved ABI in memory
- `InMemoryContractMetaStore` - caches the resolved contract metadata in memory

[See the Getting Started guide for a detailed example](/welcome/getting-started/).

#### 2. SQL stores (Effect API)

Located at `@3loop/transaction-decoder/sql`, a persistent store that can be used in production for enhancing the performance of the decoder. While using this store, you do not need to write your own database schema, and `get` or `set` methods.

- `SqlAbiStore` - caches the resolved ABI in any SQL database supported by `@effect/sql`
- `SqlContractMetaStore` - caches the resolved contract metadata in any SQL database supported by `@effect/sql`

[See the Decoding Transaction with SQLite Data Store guide](/guides/sql-stores).

## Code examples

1. Built-in In-memory stores (Vanilla JS API) - [Quick start demo code](https://github.com/3loop/loop-decoder/blob/88bc99b4d64a9db66dc75f44d1dfb04a0dc32e37/sandbox/quick-start/src/decoder.ts)
2. Built-in SQL stores (Effect API) - [Loop Decoder Web playground](https://github.com/3loop/loop-decoder/blob/88bc99b4d64a9db66dc75f44d1dfb04a0dc32e37/apps/web/src/lib/decode.ts#L32-L58)
3. Custom In-memory stores (Vanilla JS API) - [Farcaster on-chain alerts bot](https://github.com/3loop/farcaster-onchain-alerts-bot/blob/f1b90c9de7550abcd4ad1097fba5c2eb5dc259df/src/decoder/decoder.ts)
4. Custom SQL stores (Effect API) - [Decoder API, ABI Store](https://github.com/3loop/decoder-api/blob/87bec4e70b9df36b62e8d2cf78721a7304e84ed6/src/decoder/abi-loader.ts) and [Contract Metadata Store](https://github.com/3loop/decoder-api/blob/87bec4e70b9df36b62e8d2cf78721a7304e84ed6/src/decoder/meta-loader.ts)

## Custom Data Stores (Effect API)

### Implementation example

Custom SQL stores with Effect API - Decoder API, [ABI Store](https://github.com/3loop/decoder-api/blob/87bec4e70b9df36b62e8d2cf78721a7304e84ed6/src/decoder/abi-loader.ts) and [Contract Metadata Store](https://github.com/3loop/decoder-api/blob/87bec4e70b9df36b62e8d2cf78721a7304e84ed6/src/decoder/meta-loader.ts)

### AbiStore

The full interface of ABI store is:

<EffectABI />

ABI Store Interface requires 2 methods: `set` and `get` to store and retrieve the ABI of a contract. Optionally, you can provide a batch get method `getMany` for further optimization. Because our API supports ABI fragments, the get method will receive both the contract address and the fragment signature.

```typescript
interface AbiParams {
chainID: number
address: string
event?: string | undefined // event signature
signature?: string | undefined // function signature
}
```

The `set` method will receive a key of the type `AbiParams` and and `ContractAbiResult`. You can choose to store the data in the best format that fits your database.

```typescript
interface FunctionFragmentABI {
type: 'func'
abi: string
address: string
chainID: number
signature: string
}

interface EventFragmentABI {
type: 'event'
abi: string
address: string
chainID: number
event: string
}

interface AddressABI {
type: 'address'
abi: string
address: string
chainID: number
}

export type ContractABI = FunctionFragmentABI | EventFragmentABI | AddressABI

export interface ContractAbiSuccess {
status: 'success'
result: ContractABI
}

export interface ContractAbiNotFound {
status: 'not-found'
result: null
}

export interface ContractAbiEmpty {
status: 'empty'
result: null
}

export type ContractAbiResult = ContractAbiSuccess | ContractAbiNotFound | ContractAbiEmpty
```
### ContractMetadataStore
The full interface of Contract Metadata Store is:
<EffectMeta />
Similar to the ABI Store, the Contract Metadata Store Interface requires 2 methods `set`, `get`, and optionally `getMany` to store and retrieve the contract metadata.
The `get` method will receive the contract address and the chain ID as input.
```typescript
interface ContractMetaParams {
address: string
chainID: number
}
```

And, the `set` method will be called with 2 pramaters, the key in the same format as the `get` method, and the metadata in a format of `ContractMetaResult`.

```typescript
interface ContractMetaSuccess {
status: 'success'
result: ContractData
}

interface ContractMetaNotFound {
status: 'not-found'
result: null
}

interface ContractMetaEmpty {
status: 'empty'
result: null
}

export type ContractMetaResult = ContractMetaSuccess | ContractMetaNotFound | ContractMetaEmpty
```
Contract metadata is a map of the following interface:
```typescript
export interface ContractData {
address: string
contractName: string
contractAddress: string
tokenSymbol: string
decimals?: number
type: ContractType
chainID: number
}
```

### Stored Statuses

You can notice that the `AbiStore` and `ContractMetadataStore` interfaces are very similar, and both have a status for the set and get methods. Both stores can return three states:

1. `success` - The requested data is found in the store.
2. `not-found` - The requested data is found in the store, but is missing a value. This means that we have tried to resolve it from a third party, but it was missing there.
3. `empty` - The requested data is not found in the store, which means that it has never been requested before.

We have two states that can return an empty result - `not-found` and `empty`. We want to be able to skip the Data Loader strategy in cases where we know it's not available (`not-found` state), as this can significantly reduce the number of requests and improve performance.

It is possible that a `not-found` item will become available later in the future. Therefore, we encourage storing a `timestamp` and removing the `not-found` items to be able to check them again.

## Custom Data Stores (Vanilla JS API)

### Differences from Effect API

The Vanilla JS API for defining custom data stores differs from the Effect API in the following ways:

- The `get` method is a JS async function (vs Effect TS generator function)
- The `set` method is a JS async function (vs Effect TS generator function)
- The `getMany` method is not supported

Everything else, including received and returned types, is the same as in the Effect API.

### Implementation example

Custom In-memory stores with Vanilla JS API - [Farcaster on-chain alerts bot](https://github.com/3loop/farcaster-onchain-alerts-bot/blob/f1b90c9de7550abcd4ad1097fba5c2eb5dc259df/src/decoder/decoder.ts).

### AbiStore

The full interface of ABI store is:

<VanillaABI />

### ContractMetadataStore

The full interface of Contract Metadata Store is:

<VanillaMeta />
43 changes: 43 additions & 0 deletions apps/docs/src/content/docs/reference/exposed-apis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: Effect VS Vanilla JS APIs
description: Effect VS Vanilla JS APIs
sidebar:
order: 1
---

Loop Decoder provides two APIs for the Data Store: Effect and Vanilla JS.

## Effect API

The Effect API is the most flexible and powerful one, and it utilizes the [Effect TS framework](https://effect.website/docs). This API uses:

- Effect's Layers for dependency injection
- Effect's Generator functions instead of standard async/await functions

## Vanilla JS API

The Vanilla JS API is a simpler alternative to the Effect API, but it still covers the main use cases related to data store. This API is ideal for:

- Projects that don't need advanced features and want to use some of the Built-in Stores
- Simpler implementations with Promise-based async/await
- Easier integration with existing JavaScript codebases

:::note
We recommend using the Effect API for most projects.
:::

## Project Examples

Effect API:

- [Web Playground](https://github.com/3loop/loop-decoder/blob/main/apps/web/src/lib/decode.ts) - always uses the latest version of Loop Decoder
- [Decoder API](https://github.com/3loop/decoder-api) - template for building your own Decoder API server with Loop Decoder

- [Custom SQL Abi Store](https://github.com/3loop/decoder-api/blob/87bec4e70b9df36b62e8d2cf78721a7304e84ed6/src/decoder/abi-loader.ts)
- [Custom SQL Contract Meta Store](https://github.com/3loop/decoder-api/blob/87bec4e70b9df36b62e8d2cf78721a7304e84ed6/src/decoder/meta-loader.ts)
- [RPC Provider](https://github.com/3loop/decoder-api/blob/87bec4e70b9df36b62e8d2cf78721a7304e84ed6/src/decoder/provider.ts)
- [Initializing the Decoder](https://github.com/3loop/decoder-api/blob/87bec4e70b9df36b62e8d2cf78721a7304e84ed6/src/main.ts#L22-L34)

Vanilla JS API:

- [Farcaster on-chain alerts bot](https://github.com/3loop/farcaster-onchain-alerts-bot/blob/f1b90c9de7550abcd4ad1097fba5c2eb5dc259df/src/decoder/decoder.ts) - template of the Farcaster bot, uses Vanilla JS API and custom in-memory stores
2 changes: 0 additions & 2 deletions apps/docs/src/content/docs/reference/proxy-resolution.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
---
title: Proxy Resolution
description: Proxy resolution is the process of resolving the address of a proxy contract to the address of the implementation contract.
sidebar:
order: 3
---

Proxy contracts are smart contracts that forward their calls to another contract - known as the implementation or logic contract. This pattern enables contract upgrades without changing the proxy's address, ensuring users can continue interacting with the same address.
18 changes: 16 additions & 2 deletions apps/docs/src/content/docs/reference/rpc-provider.mdx
Original file line number Diff line number Diff line change
@@ -2,14 +2,28 @@
title: RPC Provider
description: Configuration options for the RPC Provider
sidebar:
order: 4
order: 5
---

import { Content as RpcProvider } from '../../components/rpc-provider.md'
import { Content as EffectRpc } from '../../components/effect-rpc.md'
import { Tabs, TabItem } from '@astrojs/starlight/components'

Loop Decoder requires an RPC provider to fetch transaction data. To configure RPC providers, implement a `getPublicClient` function that returns a `PublicClientObject` based on the chain ID.

<RpcProvider />
<Tabs>
<TabItem label="Effect API">
<EffectRpc />
</TabItem>
<TabItem label="Vanilla JS API">
<RpcProvider />
</TabItem>
</Tabs>

### Code Examples

1. RPC Provider (Effect API) - [Decoder API](https://github.com/3loop/decoder-api/blob/87bec4e70b9df36b62e8d2cf78721a7304e84ed6/src/decoder/provider.ts)
2. RPC Provider (Vanilla JS API) - [Farcaster on-chain alerts bot](https://github.com/3loop/farcaster-onchain-alerts-bot/blob/f1b90c9de7550abcd4ad1097fba5c2eb5dc259df/src/decoder/decoder.ts#L90-L105)

## PublicClientObject Structure


Unchanged files with check annotations Beta

await fs.writeFile(OUTPUT_FILE_NAME, content)
}
async function processInterpreter(file: string, _isDev?: boolean) {

Check warning on line 126 in packages/transaction-interpreter/scripts/build.ts

GitHub Actions / pr

'_isDev' is defined but never used
let contracts: string[] = []
let events: string[] = []
let type: string | null = null
icon: external
---
import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components'

Check warning on line 19 in apps/docs/src/content/docs/index.mdx

GitHub Actions / pr

'Card' is defined but never used

Check warning on line 19 in apps/docs/src/content/docs/index.mdx

GitHub Actions / pr

'CardGrid' is defined but never used

Check warning on line 19 in apps/docs/src/content/docs/index.mdx

GitHub Actions / pr

'LinkCard' is defined but never used
<CardGrid stagger>
<Card title="TypeScript" icon="seti:typescript">
description: The simple way to Create a Farcaster Bot for human-readable alerts
---
import { Content as MemoryAbiLoader } from '../../components/memory-abi-loader.md'

Check warning on line 6 in apps/docs/src/content/docs/recipes/fc-bot.mdx

GitHub Actions / pr

'MemoryAbiLoader' is defined but never used
import { Content as MemoryContractLoader } from '../../components/memory-contract-loader.md'
import { Steps } from '@astrojs/starlight/components'