Skip to content

Commit 9f992c6

Browse files
authored
Add documentation guide on how to use sql store with bun (#150)
* Add documentation guide on how to use sql store with bun * Add info about default stores in reference * Documentation updates
1 parent b994dbc commit 9f992c6

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
---
2+
title: SQL Data Store
3+
description: An implementation of the Data Store interface using a SQL database based on @effect/sql
4+
sidebar:
5+
order: 4
6+
---
7+
8+
To use the default SQL stores you can import `SqlAbiStore` and `SqlContractMetaStore ` from the `@3loop/transaction-decoder/sql`.
9+
10+
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.
11+
12+
### Example
13+
14+
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.
15+
16+
You can add it directly into your project or create a new one.
17+
18+
```shell
19+
$ mkdir transaction-decoder-cli && cd transaction-decoder-cli && bun init
20+
```
21+
22+
We will start by installing the necessary dependencies:
23+
24+
```shell
25+
$ bun i viem effect @effect/sql @effect/sql-sqlite-bun @3loop/transaction-decoder
26+
```
27+
28+
Then we will create a `index.ts` file with the following content:
29+
30+
```typescript
31+
import { SqlAbiStore, SqlContractMetaStore } from '@3loop/transaction-decoder/sql'
32+
import {
33+
decodeTransactionByHash,
34+
EtherscanV2StrategyResolver,
35+
FourByteStrategyResolver,
36+
PublicClient,
37+
} from '@3loop/transaction-decoder'
38+
import { SqliteClient } from '@effect/sql-sqlite-bun'
39+
import { Effect, Layer } from 'effect'
40+
import { createPublicClient, http, type Hex } from 'viem'
41+
42+
const AbiStoreLive = SqlAbiStore.make({
43+
default: [
44+
EtherscanV2StrategyResolver({
45+
apikey: process.env.ETHERSCAN_API_KEY,
46+
}),
47+
FourByteStrategyResolver(),
48+
],
49+
})
50+
51+
const SqlLive = SqliteClient.layer({
52+
filename: 'db.sqlite',
53+
})
54+
55+
export const RPCProviderLive = Layer.succeed(
56+
PublicClient,
57+
PublicClient.of({
58+
_tag: 'PublicClient',
59+
getPublicClient: (chainID: number) => {
60+
return Effect.succeed({
61+
client: createPublicClient({
62+
transport: http(process.env[`RPC_${chainID}`]),
63+
}),
64+
config: {
65+
traceAPI: 'none',
66+
},
67+
})
68+
},
69+
}),
70+
)
71+
72+
const MetaStoreLive = SqlContractMetaStore.make()
73+
const DataLayer = Layer.mergeAll(RPCProviderLive, SqlLive)
74+
const LoadersLayer = Layer.mergeAll(AbiStoreLive, MetaStoreLive)
75+
const MainLayer = Layer.provideMerge(LoadersLayer, DataLayer)
76+
77+
function main() {
78+
const [, , chainID, hash] = Bun.argv
79+
80+
const runnable = Effect.provide(decodeTransactionByHash(hash as Hex, Number(chainID)), MainLayer)
81+
82+
Effect.runPromise(runnable)
83+
.then(console.log)
84+
.catch((error: unknown) => {
85+
console.error('Decode error', JSON.stringify(error, null, 2))
86+
return undefined
87+
})
88+
}
89+
90+
main()
91+
```
92+
93+
Now you can run this script with bun:
94+
95+
```
96+
$ ETHERSCAN_API_KEY='YOUR_API_KEY' RPC_1=https://rpc.ankr.com/eth bun run index.ts 1 0xc0bd04d7e94542e58709f51879f64946ff4a744e1c37f5f920cea3d478e115d7
97+
```

apps/docs/src/content/docs/reference/data-store.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,19 @@ You can notice that the `AbiStore` and `ContractMetadataStore` interfaces are ve
149149
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.
150150

151151
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.
152+
153+
## Default Stores
154+
155+
By defulat loop decoder provides two stores that can be used out of the box:
156+
157+
1. In-memory store - located at `@3loop/transaction-decoder/in-memory`
158+
159+
- `InMemoryAbiStore` - caches the resolved abi in-memory
160+
- `InMemoryContractMetaStore` - caches the resolved contract metadata in-memory
161+
162+
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.
163+
164+
1. Sqlite store - located at `@3loop/transaction-decoder/sql`
165+
166+
- `SqlAbiStore` - caches the resolved abi in any sql database supported by `@effect/sql`
167+
- `SqlContractMetaStore` - caches the resolved contract metadata in any sql database supported by `@effect/sql`

0 commit comments

Comments
 (0)