From db58016de7d20ef30c0fb36ab14508ed7028a017 Mon Sep 17 00:00:00 2001 From: Gheorghe Pinzaru Date: Tue, 5 Nov 2024 22:21:13 +0100 Subject: [PATCH 1/3] Add documentation guide on how to use sql store with bun --- .../src/content/docs/guides/sql-stores.md | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 apps/docs/src/content/docs/guides/sql-stores.md diff --git a/apps/docs/src/content/docs/guides/sql-stores.md b/apps/docs/src/content/docs/guides/sql-stores.md new file mode 100644 index 00000000..0f31a045 --- /dev/null +++ b/apps/docs/src/content/docs/guides/sql-stores.md @@ -0,0 +1,97 @@ +--- +title: SQL Data Store +description: An implementation of the Data Store interface using a SQL database based on @effect/sql +sidebar: + order: 4 +--- + +To use the default SQL stores you can import `SqlAbiStore` and `ContractStore ` from the `@3loop/transaction-decoder/sql`. + +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. + +### Example + +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. + +You can add it directly into your project or create a new one. + +```shell +$ mkdir transaction-decoder-cli && cd transaction-decoder-cli && bun init +``` + +We will start by installing the necessary dependencies: + +```shell +$ 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: + +```typescript +import { SqlAbiStore, SqlContractMetaStore } from '@3loop/transaction-decoder/sql' +import { + decodeTransactionByHash, + EtherscanV2StrategyResolver, + FourByteStrategyResolver, + PublicClient, +} from '@3loop/transaction-decoder' +import { SqliteClient } from '@effect/sql-sqlite-bun' +import { Effect, Layer } from 'effect' +import { createPublicClient, http, type Hex } from 'viem' + +const AbiStoreLive = SqlAbiStore.make({ + default: [ + EtherscanV2StrategyResolver({ + apikey: process.env.ETHERSCAN_API_KEY, + }), + FourByteStrategyResolver(), + ], +}) + +const SqlLive = SqliteClient.layer({ + filename: 'db.sqlite', +}) + +export const RPCProviderLive = Layer.succeed( + PublicClient, + PublicClient.of({ + _tag: 'PublicClient', + getPublicClient: (chainID: number) => { + return Effect.succeed({ + client: createPublicClient({ + transport: http(process.env[`RPC_${chainID}`]), + }), + config: { + traceAPI: 'none', + }, + }) + }, + }), +) + +const MetaStoreLive = SqlContractMetaStore.make() +const DataLayer = Layer.mergeAll(RPCProviderLive, SqlLive) +const LoadersLayer = Layer.mergeAll(AbiStoreLive, MetaStoreLive) +const MainLayer = Layer.provideMerge(LoadersLayer, DataLayer) + +function main() { + const [, , chainID, hash] = Bun.argv + + const runnable = Effect.provide(decodeTransactionByHash(hash as Hex, Number(chainID)), MainLayer) + + Effect.runPromise(runnable) + .then(console.log) + .catch((error: unknown) => { + console.error('Decode error', JSON.stringify(error, null, 2)) + return undefined + }) +} + +main() +``` + +Now you can run this script with bun: + +``` +$ bun run index.ts 1 0x123transactionhash +``` From 0e0b9590b56734d6d1bea0cc30bef999cb062305 Mon Sep 17 00:00:00 2001 From: Gheorghe Pinzaru Date: Tue, 5 Nov 2024 22:25:44 +0100 Subject: [PATCH 2/3] Add info about default stores in reference --- apps/docs/src/content/docs/reference/data-store.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/docs/src/content/docs/reference/data-store.md b/apps/docs/src/content/docs/reference/data-store.md index 9c3d290f..0f134426 100644 --- a/apps/docs/src/content/docs/reference/data-store.md +++ b/apps/docs/src/content/docs/reference/data-store.md @@ -149,3 +149,17 @@ You can notice that the `AbiStore` and `ContractMetadataStore` interfaces are ve We have two states that can return an empty result. We want to be able to skip the meta strategy in cases where we know it's not available, as this can significantly reduce the number of requests to the strategies and improve performance. Some strategies may be able to add the data later. Therefore, we encourage storing a timestamp and removing the "not-found" state to be able to check again. + +## Default Stores + +By defulat loop decoder provides two stores that can be used out of the box: + +1. In-memory store - located at `@3loop/transaction-decoder/in-memory` + +- `InMemoryAbiStore` - caches the resolved abi in-memory +- `InMemoryContractMetaStore` - caches the resolved contract metadata in-memory + +2. Sqlite store - located at `@3loop/transaction-decoder/sql` + +- `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` From 737125802447c404f9867532a6b7ed992d41b41b Mon Sep 17 00:00:00 2001 From: Gheorghe Pinzaru Date: Sun, 10 Nov 2024 22:03:15 +0700 Subject: [PATCH 3/3] Documentation updates --- apps/docs/src/content/docs/guides/sql-stores.md | 4 ++-- apps/docs/src/content/docs/reference/data-store.md | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/docs/src/content/docs/guides/sql-stores.md b/apps/docs/src/content/docs/guides/sql-stores.md index 0f31a045..f62db39d 100644 --- a/apps/docs/src/content/docs/guides/sql-stores.md +++ b/apps/docs/src/content/docs/guides/sql-stores.md @@ -5,7 +5,7 @@ sidebar: order: 4 --- -To use the default SQL stores you can import `SqlAbiStore` and `ContractStore ` from the `@3loop/transaction-decoder/sql`. +To use the default SQL stores you can import `SqlAbiStore` and `SqlContractMetaStore ` from the `@3loop/transaction-decoder/sql`. 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. @@ -93,5 +93,5 @@ main() Now you can run this script with bun: ``` -$ bun run index.ts 1 0x123transactionhash +$ ETHERSCAN_API_KEY='YOUR_API_KEY' RPC_1=https://rpc.ankr.com/eth bun run index.ts 1 0xc0bd04d7e94542e58709f51879f64946ff4a744e1c37f5f920cea3d478e115d7 ``` diff --git a/apps/docs/src/content/docs/reference/data-store.md b/apps/docs/src/content/docs/reference/data-store.md index 0f134426..2f87b418 100644 --- a/apps/docs/src/content/docs/reference/data-store.md +++ b/apps/docs/src/content/docs/reference/data-store.md @@ -159,7 +159,9 @@ By defulat loop decoder provides two stores that can be used out of the box: - `InMemoryAbiStore` - caches the resolved abi in-memory - `InMemoryContractMetaStore` - caches the resolved contract metadata in-memory -2. Sqlite store - located at `@3loop/transaction-decoder/sql` +You will most likely use these stores for testing and development purposes. A persistent store will significantly improve the performance of the decoder over time. + +1. Sqlite store - located at `@3loop/transaction-decoder/sql` - `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`