Skip to content

Commit

Permalink
feat: set up blob decoder package and add starknet decoding logic
Browse files Browse the repository at this point in the history
  • Loading branch information
PJColombo committed May 12, 2024
1 parent 2943d90 commit 9d865cd
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-plants-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/blob-decoder": minor
---

Added starknet blob decoder
1 change: 1 addition & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"dependencies": {
"@blobscan/api": "workspace:^0.9.0",
"@blobscan/dayjs": "workspace:^0.0.2",
"@blobscan/blob-decoder": "workspace:^0.0.1",
"@blobscan/open-telemetry": "workspace:^0.0.7",
"@fontsource/inter": "^4.5.15",
"@fontsource/public-sans": "^4.5.12",
Expand Down
34 changes: 34 additions & 0 deletions packages/blob-decoder/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "@blobscan/blob-decoder",
"version": "0.0.1",
"private": true,
"types": "./src/index.ts",
"exports": {
".": {
"import": "./src/index.ts",
"require": "./src/index.ts"
}
},
"license": "MIT",
"scripts": {
"clean": "rm -rf .turbo node_modules",
"lint": "eslint .",
"lint:fix": "pnpm lint --fix",
"type-check": "tsc --noEmit",
"with-env:test": "dotenv -e ../../.env.test --",
"test": "pnpm with-env:test vitest",
"test:ui": "pnpm with-env:test vitest --ui"
},
"dependencies": {
"@blobscan/logger": "^0.0.6",
"@blobscan/majin-blob-wasm": "^0.0.1",
"@blobscan/open-telemetry": "^0.0.6",
"@blobscan/zod": "^0.0.4"
},
"eslintConfig": {
"root": true,
"extends": [
"@blobscan/eslint-config/base"
]
}
}
19 changes: 19 additions & 0 deletions packages/blob-decoder/src/blob-decoder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { StarknetStateDiff, decodeStarknetBlob } from "./starknet";
import { DecodableRollup } from "./types";

export function isDecodableRollup(rollup: string): rollup is DecodableRollup {
return rollup === "STARKNET";
}

export async function decodeBlob(
rollup: "STARKNET",
blobData: string
): Promise<StarknetStateDiff[]>;
export async function decodeBlob(rollup: DecodableRollup, blobData: string) {
switch (rollup) {
case "STARKNET":
return decodeStarknetBlob(blobData);
default:
throw new Error(`Unsupported rollup: ${rollup}`);
}
}
2 changes: 2 additions & 0 deletions packages/blob-decoder/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./blob-decoder";
export * from "./types";
55 changes: 55 additions & 0 deletions packages/blob-decoder/src/starknet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { blob_recover } from "@blobscan/majin-blob-wasm";
import { z } from "@blobscan/zod";

import { BlobDecoderFn } from "./types";
import { bigIntToHex } from "./utils";

export const starknetStateDiffSchema = z
.object({
address: z.string(),
nonce: z.number(),
number_of_storage_updates: z.number(),
new_class_hash: z.string(),
storage_updates: z.array(
z.object({
key: z.string(),
value: z.string(),
})
),
})
.transform((data) => ({
contractAddress: data.address,
nonce: data.nonce,
numberOfStorageUpdates: data.number_of_storage_updates,
newClassHash: data.new_class_hash,
storageUpdates: data.storage_updates,
}));

export type StarknetStateDiff = z.infer<typeof starknetStateDiffSchema>;

function normalizeBlobData(blobData: string) {
return blobData.startsWith("0x") ? blobData.slice(2) : blobData;
}

export const decodeStarknetBlob: BlobDecoderFn<StarknetStateDiff[]> = function (
blobData
) {
const normalizedBlobData = normalizeBlobData(blobData);
const result = blob_recover(normalizedBlobData);
const decodedBlob = JSON.parse(result);

const starknetStateDiffs = starknetStateDiffSchema.array().parse(decodedBlob);

return starknetStateDiffs.map<StarknetStateDiff>((entry) => {
return {
contractAddress: bigIntToHex(entry.contractAddress),
nonce: entry.nonce,
numberOfStorageUpdates: entry.numberOfStorageUpdates,
newClassHash: bigIntToHex(entry.newClassHash),
storageUpdates: entry.storageUpdates.map((storageUpdage) => ({
key: bigIntToHex(storageUpdage.key),
value: bigIntToHex(storageUpdage.value),
})),
};
});
};
3 changes: 3 additions & 0 deletions packages/blob-decoder/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type DecodableRollup = "STARKNET";

export type BlobDecoderFn<R> = (blobData: string) => R;
5 changes: 5 additions & 0 deletions packages/blob-decoder/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function bigIntToHex(value: bigint | string): string {
const value_ = typeof value === "string" ? BigInt(value) : value;

return `0x${value_.toString(16)}`;
}
4 changes: 4 additions & 0 deletions packages/blob-decoder/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "@blobscan/tsconfig/base.production.json",
"include": ["src/**/*.ts", "test/**/*.ts", "vitest.config.ts"]
}
5 changes: 5 additions & 0 deletions packages/blob-decoder/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineProject } from "vitest/config";

import { sharedProjectConfig } from "../../vitest.shared";

export default defineProject(sharedProjectConfig);

0 comments on commit 9d865cd

Please sign in to comment.