Quick Start
Viewkit is a CLI tool that helps you initialize, manage, and publish Shinzo views. In this quickstart guide we're going to build and install the viewkit executable, create a view, and publish it to the testnet.
Prerequisites
- Git
- Make
- Go 1.25
Setup
-
Make sure you've got all the prerequisites installed properly:
git --version && make --version && go versiongit version 2.43.0 GNU Make 4.3 [...] go version go1.25.12 linux/arm64 -
Clone the repository:
git clone https://github.com/shinzonetwork/shinzo-view-creator.git cd shinzo-view-creator -
Build the Viewkit binary:
make buildYou should see a
builddirectory: -
Run Viewkit:
./build/viewkit --helpViewkit helps you initialize, manage, and publish Shinzo views through a simple CLI interface. Usage: viewkit [command] [...] -
Move the
viewkitexecutable somewhere resonable and (optional):sudo mv ./build/viewkit /usr/local/binNow you can run
viewkitfrom anywhere.
Wasmer runtime
Viewkit can execute WebAssembly lenses locally to validate and preview them.
Under the hood, it uses wasmer-go, which depends on a native dynamic library (libwasmer.dylib). If your local system cannot find that library, any command that touches lenses will fail with an error like:
image not found library not loaded: libwasmer.dylib
-
Move back into the shinzo-view-creator repo if you moved out of it:
cd shinzo-view-creator -
Install the Wasmer Go module
go get github.com/wasmerio/[email protected]go: downloading github.com/wasmerio/wasmer-go v1.0.4 go: added github.com/wasmerio/wasmer-go v1.0.4This ensures
wasmer-goand its packaged native libraries are present in yourGOPATH.
Environment variables
We need to set three new environment variables:
WASMER_ROOT: points to the directory wherelibwasmer.dyliblives.WASMER_LIB_PATH: used bywasmer-goto find the dynamic library.DYLD_LIBRARY_PATH: MacOS-specific dynamic loader search path. We prependWASMER_ROOTso the loader can findlibwasmer.dylibwhenviewkitstarts.
-
Append these lines to your shell's RC file.
MacOS:
echo 'export WASMER_ROOT="$(go env GOPATH)/pkg/mod/github.com/wasmerio/[email protected]/wasmer/packaged/lib/darwin-aarch64"' >> ~/.zshrc echo 'export WASMER_LIB_PATH="$WASMER_ROOT"' >> ~/.zshrc echo 'export DYLD_LIBRARY_PATH="$WASMER_ROOT:$DYLD_LIBRARY_PATH"' >> ~/.zshrcLinux:
echo 'export WASMER_ROOT="$(go env GOPATH)/pkg/mod/github.com/wasmerio/[email protected]/wasmer/packaged/lib/linux-amd64"' >> ~/.zshrc echo 'export WASMER_LIB_PATH="$WASMER_ROOT"' >> ~/.zshrc echo 'export LD_LIBRARY_PATH="$WASMER_ROOT:$LD_LIBRARY_PATH"' >> ~/.zshrc -
Reload your shell configuration:
source ~/.zshrc -
Verify that the variables are set:
echo "$WASMER_ROOT" ls "$WASMER_ROOT"/home/user/go/pkg/mod/github.com/wasmerio/[email protected]/wasmer/packaged/lib/linux-amd64 dummy.go libwasmer.so
[!WARNING] If
libwasmer.dylibis missing, re-run thego getstep and ensurego env GOPATHreturns a valid path.
Create a view
Now that everything is set up, we can start creating and deploying views.
-
Initialize the view bundle:
viewkit view init testdeploy๐ View: testdeploy ๐ Query: <none> ๐ SDL: <none> ๐ง Lenses: - (empty) ๐ Metadata: - Version: 0 - Total: 0 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:34:27 +0000 UTCThis:
- Creates a new view bundle called
testdeployon disk. - Registers internal metadata for queries, SDL, lenses, and versions.
- Creates a new view bundle called
-
Inspect the bundle:
viewkit view inspect testdeploy๐ View: testdeploy ๐ Query: <none> ๐ SDL: <none> ๐ง Lenses: - (empty) ๐ Metadata: - Version: 0 - Total: 0 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:34:27 +0000 UTC -
Next we're going to add a query (raw ingest shape). First, define the raw data shape to ingest, e.g. basic EVM logs:
viewkit view add query \ "Log {address topics data transactionHash blockNumber}" \ --name testdeploy๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: <none> ๐ง Lenses: - (empty) ๐ Metadata: - Version: 1 - Total: 1 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:36:32 +0000 UTCThis tells Viewkit that
testdeploywill ingestLogobjects with the specified fields.
Then, check:
```shell
viewkit view inspect testdeploy
```
```output
๐ View: testdeploy
๐ Query:
Log {address topics data transactionHash blockNumber}
๐ SDL: <none>
๐ง Lenses:
- (empty)
๐ Metadata:
- Version: 1
- Total: 1
- Created At: 2026-07-09 09:34:27 +0000 UTC
- Updated At: 2026-07-09 09:36:32 +0000 UTC
```
-
Add an SDL to describe how the data is modeled/exposed:
viewkit view add sdl \ "type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String}" \ --name testdeploy๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String} ๐ง Lenses: - (empty) ๐ Metadata: - Version: 2 - Total: 2 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:37:24 +0000 UTC[!NOTE]
@materialized(if: false): treat this as a virtual type, not a persisted table.transactionHash: String: minimal example field; real views will define more fields.
-
Inspect the view again:
viewkit view inspect testdeploy # now shows both query and SDL๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String} ๐ง Lenses: - (empty) ๐ Metadata: - Version: 2 - Total: 2 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:37:24 +0000 UTCIt now shows both the query and the SDL.
-
Attach a WebAssembly lens that decodes event logs using an ABI. There are the flags we're using:
--args: JSON passed to the lens (here, an ABI definition for the ERC-20Transferevent).--label "decode": human-readable label for the lens.--url: remote URL of the.wasmbinary.--name testdeploy: attaches this lens to thetestdeployview.
viewkit view add lens \ --args '{"abi":"[{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"type\":\"address\",\"name\":\"from\",\"indexed\":true},{\"type\":\"address\",\"name\":\"to\",\"indexed\":true},{\"type\":\"uint256\",\"name\":\"value\",\"indexed\":false}]}]"}' \ --label "decode" \ --url "https://raw.githubusercontent.com/shinzonetwork/wasm-bucket/main/bucket/decode_log/decode_log.wasm" \ --name testdeploy๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String} ๐ง Lenses: - decode (assets/decode.wasm) Arguments: abi: [{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","indexed":true},{"type":"address","name":"to","indexed":true},{"type":"uint256","name":"value","indexed":false}]}] ๐ Metadata: - Version: 3 - Total: 3 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:39:11 +0000 UTC -
Inspect the view again:
viewkit view inspect testdeploy # you should now see: # - query # - SDL # - lens "decode"You should now see the query, SDL, and, the lens
decode:๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String} ๐ง Lenses: - decode (assets/decode.wasm) Arguments: abi: [{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","indexed":true},{"type":"address","name":"to","indexed":true},{"type":"uint256","name":"value","indexed":false}]}] ๐ Metadata: - Version: 3 - Total: 3 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:39:11 +0000 UTC
![TIP] If you see
libwasmer.dylib/ "image not found" errors, revisit the Wasmer setup.
-
Before deploying, validate that your view builds and compiles successfully:
viewkit view test testdeployThis spins up a temporary local DefraDB instance, applies your schema, runs the lens, and checks that everything compiles. If it passes, your view is ready to deploy.
Create a deployment key
You need a wallet to sign deployments to devnet.
-
Generate a one:
viewkit wallet generateโ Wallet generated Mnemonic: document grass code lawn erosion climb people sunset three blame balcony story script hip soup lesson resemble above quiz acid dust salmon plane Address: 0x2e4150993E841b38f4780BC158A7dA0d62E22ec9 -
Treat this wallet like any other secret or asset:
- Do not commit it to Git.
- Do not paste the mnemonic in public places.
- Store it securely.
Deploy locally
The recommended flow is to deploy locally first, verify the view in a Playground, then deploy to a shared network.
-
Deploy locally:
viewkit view deploy testdeploy --target local๐ DefraDB is running on port 9181 โณ Waiting for DefraDB to boot up... โ DefraDB booted up โณ Applying Schemas ... โ Schema Applied โณ Data Inserting... โ Data Inserted Successfully โ Applying View ... โ View Successfully Applied ๐งช Visit the DefraDB GraphQL Playground at http://127.0.0.1:9181/ ๐ฆ Press Ctrl+C to stop...Here's what's happening:
- A local DefraDB instance is started (port shown in the logs).
- Schemas for your view are applied.
- Any seed data (if configured) is inserted.
- The view is applied.
- A DefraDB GraphQL Playground URL is printed.
Use the DefraDB GraphQL Playground
This section is optional, but it's a good idea to check the View within the built-in GraphQL Playground.
- Open the displayed URL in your browser, usually 127.0.0.1:9181.
- You should see a GraphQL Playground.
- Within thie Playground you can:
- Inspect the schema (e.g. see
FilteredAndDecodedLogs). - Run test queries against your local view.
- Verify that your lens is filtering logs as expected.
- Inspect the schema (e.g. see
For example, you can run a query like:
{
filteredAndDecodedLogs {
transactionHash
}
}
While this process is running, viewkit will keep the local DefraDB instance alive. Press CTRL + c to stop the DefraDB instance.
Deploy to devnet
Once your view behaves correctly locally, you can deploy it to a shared network.
-
Gather an RPC URL.
-
Deploy the view to the network:
viewkit view deploy testdeploy --target devnet --rpc http://testnet.shinzo.network:8545/
Need Help
- For onboarding and technical support, join the Shinzo Discord.
- To report a documentation bug or request a feature, open an issue in the docs repo.
- For a technical issue with the Viewkit client, open an issue in the shinzo-view-creator repo.