Create your first View
Viewkit is a CLI tool that helps you initialize, manage, and publish Shinzo views. In this tutorial you will build the viewkit executable, assemble a View from its parts, test it locally, and deploy it to the public testnet. If you would rather work from a browser UI instead of the CLI, Create and deploy Views in Shinzo Studio covers the same create, deploy, and query flow for Views.
A View is a versioned bundle with three parts: a query (the raw data shape you ingest), an SDL (the GraphQL schema that models the result), and lenses (WebAssembly transforms that filter, decode, or reshape the data). The View you build here decodes fungible token transfer events from raw logs into readable fields.
Prerequisites
- Git.
- Make.
- Go 1.25 or later.
Setup
-
Make sure the prerequisites are 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 on your PATH (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 when you run view test or deploy locally.
Under the hood it uses wasmer-go, which depends on a native dynamic library (libwasmer.dylib on macOS, libwasmer.so on Linux). If your system cannot find that library, any command that touches lenses will fail with an error like "image not found" or "library not loaded".
-
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/wasmer-go@v1.0.4go: downloading github.com/wasmerio/wasmer-go v1.0.4 go: added github.com/wasmerio/wasmer-go v1.0.4This makes
wasmer-goand its packaged native libraries available in yourGOPATH.
Environment variables
You need to set three environment variables:
WASMER_ROOT: points to the directory where the Wasmer dynamic library lives.WASMER_LIB_PATH: used bywasmer-goto find the dynamic library.DYLD_LIBRARY_PATH(macOS) orLD_LIBRARY_PATH(Linux): the dynamic loader search path. PrependWASMER_ROOTso the loader finds the library whenviewkitstarts.
-
Append these lines to your shell's RC file.
macOS:
echo 'export WASMER_ROOT="$(go env GOPATH)/pkg/mod/github.com/wasmerio/wasmer-go@v1.0.4/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/wasmer-go@v1.0.4/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 the variables are set:
echo "$WASMER_ROOT" ls "$WASMER_ROOT"/home/user/go/pkg/mod/github.com/wasmerio/wasmer-go@v1.0.4/wasmer/packaged/lib/linux-amd64 dummy.go libwasmer.so
If libwasmer.dylib or libwasmer.so is missing, re-run the go get step and check that go env GOPATH returns a valid path. The local view test and view deploy --target local commands spawn a DefraDB binary that also needs LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (macOS) to be set, so keep these variables set in any shell where you run Viewkit.
Create a View
-
Initialize the View bundle:
viewkit view init testdeployThis creates a new View bundle called
testdeployon disk and registers internal metadata for queries, SDL, lenses, and versions. -
Add a query defining the raw data shape to ingest. Here it is raw event logs:
viewkit view add query \ "Log {address topics data transactionHash blockNumber}" \ --name testdeployThis tells Viewkit that
testdeploywill ingestLogobjects with the specified fields. -
Add an SDL describing how the data is modeled and exposed:
viewkit view add sdl \ "type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String}" \ --name testdeployNote@materialized(if: false): treat this as a virtual type, computed at query time rather than stored.transactionHash: String: a minimal example field; real Views define more fields.
-
Attach a WebAssembly lens that decodes event logs using an ABI:
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 testdeployThese are the flags in play:
--args: JSON passed to the lens. Here it is an ABI definition for aTransferevent withfrom,to, andvaluefields.--label "decode": a human-readable label for the lens.--url: remote URL of the.wasmbinary.--name testdeploy: attaches this lens to thetestdeployView.
-
Inspect the bundle once everything is attached:
viewkit view inspect 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-09-03 11:35:10 +0000 UTC - Updated At: 2026-09-03 11:35:28 +0000 UTCEvery
view addcommand also prints this same summary, so runninginspectonce after all the parts are attached is enough.
If you see libwasmer.dylib or "image not found" errors, revisit the Wasmer setup.
Test the View
-
Before deploying, validate that the View builds and compiles successfully:
viewkit view test testdeploy๐ Loading view... โ๏ธ Ensuring DefraDB binary... ๐ Creating temporary root directory... ๐ Starting DefraDB... โณ Waiting for DefraDB to boot... โ DefraDB booted ๐ฆ Applying schema... โ Schema applied ๐จ Inserting test data... โณ Data Inserting... โ Data Inserted Successfully โ Data inserted ๐ง Applying view... โ View applied ๐ Extracting collection name... โป๏ธ Refreshing view... โ View refreshed โ Test flow completed successfully. Shutting down... โ DefraDB stopped.This spins up a temporary local DefraDB instance, applies the schema, runs the lens, and checks that everything compiles. If it passes, the View is ready to deploy.
Create a deployment wallet
Deploying to the network registers the View on chain, so you need a wallet to sign that transaction.
-
Generate a wallet:
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:
- Do not commit it to Git.
- Do not paste the mnemonic in public places.
- Store it securely.
Fund the wallet
Registration is an on-chain transaction, so the wallet needs tokens to pay the transaction fee.
- Open the Shinzo faucet in your browser.
- Paste the address from
viewkit wallet generateinto the input. - Click Get 0.001 $SHN.
The faucet shows the transaction hash once the tokens are sent. You only need to do this once per wallet.
Deploy locally
The recommended flow is to deploy locally first, verify the View in the DefraDB Playground, then deploy to the 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 happens:
- A local DefraDB instance starts (the port is in the logs).
- The schema for the View is applied.
- Test data is inserted.
- The View is applied.
- A DefraDB GraphQL Playground URL is printed.
Use the DefraDB GraphQL Playground
This step is optional, but it is a good way to check the View before deploying it anywhere.
-
Open the displayed URL in your browser, usually 127.0.0.1:9181.
-
You should see a GraphQL Playground where you can:
- Inspect the schema (for example, the
FilteredAndDecodedLogstype). - Run test queries against the local View.
- Confirm the lens decodes logs as expected.
For example:
{ FilteredAndDecodedLogs { transactionHash } } - Inspect the schema (for example, the
While this process is running, viewkit keeps the local DefraDB instance alive. Press CTRL + c to stop the DefraDB instance.
Deploy to the public testnet
Once the View behaves correctly locally, deploy it to the public testnet.
-
Check that the wallet has a balance, and fund it from the faucet if needed.
-
Deploy the View to the network:
viewkit view deploy testdeploy --target devnet --rpc http://testnet.shinzo.network:8545/
The --target devnet flag name is historical. In the current Viewkit it is the right target for the public testnet (--rpc http://testnet.shinzo.network:8545/). The CLI's mainnet target is not supported yet, so devnet is the only network target that works.
The deploy command rebuilds and re-tests the View, sends a register(bytes) transaction to the View Registry precompile, and prints the result:
๐ง Building and testing view before deployment...
โณ View built and tested successfully. Deploying...
โ
View deployment successful!
----------------------------------------
๐ View ID: FilteredAndDecodedLogs_0x016c19db7f2cf5aa86d34b5779f58de913f92d12ec9ee3642587124ce712c123
๐ View Key: 0x016c19db7f2cf5aa86d34b5779f58de913f92d12ec9ee3642587124ce712c123
๐ฆ Transaction Hash: 0x7be8a3e99299ed017896ae76fb2811208380a459e36d49a0b4a7ac047747a2df
Wire bytes (tx data):96660
----------------------------------------
Registration completes asynchronously, so give it around 20 seconds before the View shows up on chain.
Query your View
After registration, the View is on chain and any Host that picks it up can serve it.
-
Confirm your View is registered:
curl "http://testnet.shinzo.network:1317/shinzonetwork/view/v1/views?include_data=false" \ | jq -r '.views[] | select(.name | contains("FilteredAndDecodedLogs")) | .name, .address'FilteredAndDecodedLogs 0xa1226B03c54789e9Bf8876ac956aBbD1bDf5B654 -
Query the View against a public Host:
HOST=$(curl -s "http://testnet.shinzo.network:1317/shinzonetwork/host/v1/hosts" \ | jq -r '.hosts[0].endpoint_address') curl -X POST "$HOST" \ -H 'Content-Type: application/json' \ -d '{"query":"{ FilteredAndDecodedLogs(limit: 10) { transactionHash } }"}'
Until a Host picks up your View, a query against it returns a schema error:
{"errors":[{"message":"Cannot query field \"FilteredAndDecodedLogs\" on type \"Query\"."}],"data":null}
Hosts subscribe to a View and serve it once it has a pool; a brand-new tutorial View usually has none yet. Signed querying is covered in Query your first View, and Find Views and Hosts shows how to locate Host endpoints and pools. Browse your View in Shinzo Studio or the Explorer.
More examples
For progressively more complex View examples (decoding multiple event types, transaction-based Views without lenses, materialized versus on-query Views, editing and rolling back Views), see View recipes, which includes both the View definitions and the GraphQL queries you run against them.
For the conceptual overview, see Views for builders. For the full command list, filter operators, VWL wire format, and deploy internals, see the Viewkit reference. For a deeper dive on lenses, available modules, and how to chain them, see the Lens reference. For troubleshooting and common errors, see Operations: Troubleshooting.
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.