Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tablelandnetwork/dimo-vehicle-defs
Tableland-based DIMO Vehicle Definitions demo
https://github.com/tablelandnetwork/dimo-vehicle-defs
Last synced: 8 days ago
JSON representation
Tableland-based DIMO Vehicle Definitions demo
- Host: GitHub
- URL: https://github.com/tablelandnetwork/dimo-vehicle-defs
- Owner: tablelandnetwork
- License: unlicense
- Created: 2023-08-11T23:31:19.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2023-08-16T04:02:59.000Z (over 1 year ago)
- Last Synced: 2023-08-16T04:28:31.392Z (over 1 year ago)
- Language: TypeScript
- Size: 4.45 MB
- Stars: 2
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# dimo-vehicle-defs
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg)](https://github.com/RichardLitt/standard-readme)
[![Test](https://github.com/tablelandnetwork/dimo-vehicle-defs/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/tablelandnetwork/dimo-vehicle-defs/actions/workflows/test.yml)> Tableland-based DIMO Vehicle Definitions demo
# Table of Contents
- [Background](#background)
- [Development](#development)
- [License](#license)# Background
This is a demo of hosting the DIMO vehicle definitions table from the DIMO `VehicleId` ERC721 contract using Tableland. The table is owned by and written to by the `VehicleId` contract. `VehicleId` tokens represent user vehicles and are associated with a vehicle definition (e.g. 2011 Toyota Tacoma). The crux of the problem is how to ensure that a given vehicle definition exists when a new `VehicleId` is minted from the contract.
We show two potential solutions:
1. [`VehicleId`](./contracts/VehicleId.sol) simply increments a counter whenever a new vehicle definition is added. When minting a `VehicleId`, the user passes in an integer that represents the Tableland row ID (auto-incrementing primary key) of a vehicle definition. Since table rows cannot be deleted, if this integer is greater than the current counter, we know it’s invalid and the transaction is rejected.
2. [`VehicleId2`](./contracts/VehicleId2.sol) leverages a (somewhat experimental) on-chain [dynamic merkle tree](https://ethresear.ch/t/efficient-on-chain-dynamic-merkle-tree/11054) to track a root hash that represents the entire off-chain vehicle definitions table. When minting a `VehicleId`, the user passes in the Tableland row ID (auto-incrementing primary key) of a vehicle definition, a hash of its values (make, model, year, etc.), and a merkle inclusion proof that it actually exists in the off-chain table. The contract only needs to store a single `bytes32` representing the root hash. This approach is more heavy-handed, but ensures a tighter coupling between the `VehicleId` and vehicle definition.Note that the proofs needs to be generated off-chain from the table state. Ideally, validators [`go-tableland`](https://github.com/tablelandnetwork/go-tableland) should have an API endpoint that allows users and apps to fetch inclusion proofs for a given row by internally maintaining a merkle tree for the table. As a user, you wouldn't have to trust what the validator gives you because verification happens on-chain against a root hash that is dynamically updated when rows are added/updated (remember, in this case the table can only be written to by the contract).
## NFT Metadata
We also show how the ERC721 token metadata could be handled dynamically from the vehicle definitions table. The [tokenUri](./contracts/VehicleId.sol#L165) method returns a Tableland query that selects from the table using the internal VehicleId to vehicle definition mapping (see the query [here](./helpers/uris.ts#L19)). The result is that we get token metadata that can change based on its associated vehicle definition. Note, this is only implemented for [`VehicleId`](./contracts/VehicleId.sol).
Here's what the metadata for a `VehicleId` might look like.
```json
{
"name": "VehicleId #1",
"attributes": [
{
"trait_type": "device_type_id",
"value": "vehicle"
},
{
"trait_type": "make",
"value": "Ford"
},
{
"trait_type": "make_token_id",
"value": 41,
"display_type": "number"
},
{
"trait_type": "oem_platform_name",
"value": "FordPass"
},
{
"trait_type": "model",
"value": "F-250 Super Duty"
},
{
"trait_type": "year",
"value": 2018,
"display_type": "number"
},
{
"trait_type": "model_style",
"value": "King Ranch 4dr Crew Cab SB (6.2L 8cyl 6A)"
},
{
"trait_type": "model_sub_style",
"value": "King Ranch"
}
],
"metadata": {
"vehicle_info": {
"base_msrp": "44600",
"fuel_type": "Diesel",
"wheelbase": "164 WB",
"generation": "13",
"driven_wheels": "4x4",
"number_of_doors": "4",
"manufacturer_code": "W2B",
"fuel_tank_capacity_gal": "34"
}
}
}
```There's a lot we could do with the metadata structure. We could `JOIN` from other tables, remove/add attributes, add an image/animation, etc. Note, because [most common metadata format](https://docs.opensea.io/docs/metadata-standards) doesn't support nested object traits in `attributes`, we just add the `metadata` column from the vehicle definitions table as a top level property.
# Development
## Building the client
You can build the Typescript client locally:
```shell
npm install
npm run build
```## Testing
Run the test suite:
```shell
npm test
```## Deploying
Deployments are handled on a per-network basis:
```shell
npx hardhat run scripts/deploy.ts --network polygon
```## Extracting the ABI and Bytecode
You can grab the assets you need by compiling and then using some `jq` magic:
### ABI
```shell
cat artifacts/contracts/VehicleId.sol/VehicleId.json | jq '.abi' > abi.json
```### Bytecode
```shell
cat artifacts/contracts/VehicleId.sol/VehicleId.json | jq -r '.bytecode' > bytecode.bin
```### Generate the Go client!
You can use the above `abi.json` to build the Go client:
```shell
mkdir gobuild
abigen --abi ./abi.json --bin ./bytecode.bin --pkg contracts --out gobuild/VehicleId.go
```## Etherscan verification
To perform Etherscan verification, you first need to deploy a contract to an Ethereum network that's supported by Etherscan, such as Polygon:
```shell
npx hardhat run scripts/deploy.ts --network polygon
```Then, add a `POLYSCAN_API_KEY` to your `.env` file and run the verify script:
```shell
npx hardhat run scripts/verify.ts --network polygon
```## Speedier tests
For faster runs of your tests and scripts, consider skipping ts-node's type checking by setting the environment variable `TS_NODE_TRANSPILE_ONLY` to `1` in hardhat's environment. For more details see [the documentation](https://hardhat.org/guides/typescript.html#performance-optimizations).
# License
[The Unlicense](LICENSE)