From 257d02a52a46dd8dce87ba0bd7cfdce0489fbacc Mon Sep 17 00:00:00 2001 From: Valentin Dosimont Date: Mon, 27 Jan 2025 12:11:57 +0100 Subject: [PATCH] fix: historical events ordering --- .changeset/neat-moose-press.md | 16 + .../src/historical-events.tsx | 6 +- .../__tests__/parseHistoricalEvents.test.ts | 793 ++++++++++++++++++ packages/sdk/src/experimental/index.ts | 8 +- packages/sdk/src/parseHistoricalEvents.ts | 64 +- 5 files changed, 865 insertions(+), 22 deletions(-) create mode 100644 .changeset/neat-moose-press.md create mode 100644 packages/sdk/src/__tests__/parseHistoricalEvents.test.ts diff --git a/.changeset/neat-moose-press.md b/.changeset/neat-moose-press.md new file mode 100644 index 00000000..30e063b7 --- /dev/null +++ b/.changeset/neat-moose-press.md @@ -0,0 +1,16 @@ +--- +"@dojoengine/sdk": patch +"template-vite-ts": patch +"@dojoengine/core": patch +"@dojoengine/create-burner": patch +"@dojoengine/create-dojo": patch +"@dojoengine/predeployed-connector": patch +"@dojoengine/react": patch +"@dojoengine/state": patch +"@dojoengine/torii-client": patch +"@dojoengine/torii-wasm": patch +"@dojoengine/utils": patch +"@dojoengine/utils-wasm": patch +--- + +Fix historical events ordering diff --git a/examples/example-vite-react-sdk/src/historical-events.tsx b/examples/example-vite-react-sdk/src/historical-events.tsx index bb6adb3c..26efa753 100644 --- a/examples/example-vite-react-sdk/src/historical-events.tsx +++ b/examples/example-vite-react-sdk/src/historical-events.tsx @@ -9,7 +9,7 @@ import { useDojoSDK } from "@dojoengine/sdk/react"; export function HistoricalEvents() { const { account } = useAccount(); const { sdk } = useDojoSDK(); - const [events, setEvents] = useState[][]>([]); + const [events, setEvents] = useState[]>([]); const [subscription, setSubscription] = useState(null); useEffect(() => { @@ -82,8 +82,8 @@ export function HistoricalEvents() { return (

Player Events :

- {events.map((e: ParsedEntity[], key) => { - return ; + {events.map((e: ParsedEntity, key) => { + return ; })}
); diff --git a/packages/sdk/src/__tests__/parseHistoricalEvents.test.ts b/packages/sdk/src/__tests__/parseHistoricalEvents.test.ts new file mode 100644 index 00000000..ee182c86 --- /dev/null +++ b/packages/sdk/src/__tests__/parseHistoricalEvents.test.ts @@ -0,0 +1,793 @@ +import * as torii from "@dojoengine/torii-client"; +import { describe, expect, it } from "vitest"; + +import { parseHistoricalEvents, orderKeys } from "../parseHistoricalEvents"; + +describe("parseHistoricalEvents", () => { + it("should preserve order", () => { + const res1 = parseHistoricalEvents( + toriiResultUnsorted as torii.Entities, + { logging: false } + ); + const res2 = parseHistoricalEvents( + toriiResultSorted as torii.Entities, + { logging: false } + ); + + expect(res1).toEqual(res2); + }); + it("should order keys", () => { + const key1Unsorted = Object.keys( + toriiResultUnsorted[ + "0x681d68850e9c98f4383832aa206f00de22040754d6094f7b9a5a6802c25d2a3" + ] + ); + const key2Sorted = Object.keys( + toriiResultSorted[ + "0x681d68850e9c98f4383832aa206f00de22040754d6094f7b9a5a6802c25d2a3" + ] + ); + expect(key1Unsorted).not.toEqual(key2Sorted); + + expect(orderKeys(key1Unsorted)).toEqual(orderKeys(key2Sorted)); + expect(orderKeys(key1Unsorted)).toEqual(orderKeys(key1Unsorted)); + expect(orderKeys(key2Sorted)).toEqual(orderKeys(key2Sorted)); + }); +}); + +const toriiResultUnsorted = { + "0x681d68850e9c98f4383832aa206f00de22040754d6094f7b9a5a6802c25d2a3": { + "dojo_starter-Moved-5": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-14": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-3": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Up", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-11": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-8": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-13": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-6": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-2": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Up", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-12": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-9": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-15": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-16": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Up", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-7": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-10": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-4": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-1": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Up", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + }, +}; +const toriiResultSorted = { + "0x681d68850e9c98f4383832aa206f00de22040754d6094f7b9a5a6802c25d2a3": { + "dojo_starter-Moved": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Up", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-1": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Up", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-2": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Up", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-3": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Up", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-4": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-5": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-6": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-7": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-8": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-9": { + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Down", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + }, + "dojo_starter-Moved-10": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-11": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-12": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-13": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-14": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-15": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + "dojo_starter-Moved-16": { + direction: { + type: "enum", + type_name: "Direction", + value: { + option: "Right", + value: { + type: "tuple", + type_name: "()", + value: [], + key: false, + }, + }, + key: false, + }, + player: { + type: "primitive", + type_name: "ContractAddress", + value: "0x013d9ee239f33fea4f8785b9e3870ade909e20a9599ae7cd62c1c292b73af1b7", + key: true, + }, + }, + }, +}; diff --git a/packages/sdk/src/experimental/index.ts b/packages/sdk/src/experimental/index.ts index 08e56393..68bf253f 100644 --- a/packages/sdk/src/experimental/index.ts +++ b/packages/sdk/src/experimental/index.ts @@ -68,7 +68,13 @@ export async function init(options: SDKConfig) { "For subscription, you need to include entity ids" ); } - const events = parseEntities(await client.getEntities(query)); + const events = historical + ? parseHistoricalEvents( + await client.getEventMessages(query, historical) + ) + : parseEntities( + await client.getEventMessages(query, historical) + ); return [ events, client.onEventMessageUpdated( diff --git a/packages/sdk/src/parseHistoricalEvents.ts b/packages/sdk/src/parseHistoricalEvents.ts index 7bf5ede7..eae48d84 100644 --- a/packages/sdk/src/parseHistoricalEvents.ts +++ b/packages/sdk/src/parseHistoricalEvents.ts @@ -1,6 +1,6 @@ import * as torii from "@dojoengine/torii-client"; -import { ParsedEntity, SchemaType, StandardizedQueryResult } from "./types"; +import { SchemaType, StandardizedQueryResult } from "./types"; import { parseEntities } from "./parseEntities"; /** @@ -18,25 +18,19 @@ import { parseEntities } from "./parseEntities"; export function parseHistoricalEvents( entities: torii.Entities, options?: { logging?: boolean } -): StandardizedQueryResult[] { +): StandardizedQueryResult { + if (options?.logging) { + console.log("Raw historical events", entities); + } + console.log(entities); // Events come from torii flagged as "dojo_starter-Moved-idx" - let events: torii.Entities[] = []; + let events: StandardizedQueryResult = []; for (const entityId in entities) { const entityData = entities[entityId]; - const keys = Object.keys(entityData); - - //sort keys to preserve order given by torii - const sortedKeys = keys.sort((a, b) => { - // Extract the last number from each string using regex - const getLastNumber = (str: string) => { - const match = str.match(/-(\d+)$/); - return match ? parseInt(match[1]) : 0; - }; - - return getLastNumber(a) - getLastNumber(b); - }); + const keys = orderKeys(Object.keys(entityData)); - for (const model of sortedKeys) { + for (const model of keys) { + console.log(model); const modelData = entityData[model]; const modelNameSplit = model.split("-"); modelNameSplit.pop(); @@ -44,9 +38,43 @@ export function parseHistoricalEvents( const modelName = modelNameSplit.length > 1 ? modelNameSplit.join("-") : model; - events = [...events, { [entityId]: { [modelName]: modelData } }]; + events.push( + ...parseEntities( + { [entityId]: { [modelName]: modelData } }, + options + ) + ); } } + if (options?.logging) { + console.log("Parsed historical events", events); + } + + return events; +} + +/** + * Torii entities comes in format: + * { + * "entityId": { + * "ns-Model-idx": { + * ...toriiData + * } + * } + * } + * + * Object.keys returns keys but is not respecting defined keys order. + * Therefore, we need do sort keys before building up final parsedEntities array. + */ +export function orderKeys(keys: string[]) { + keys.sort((a, b) => { + // Extract the last number from each string using regex + const getLastNumber = (str: string) => { + const match = str.match(/-(\d+)$/); + return match ? parseInt(match[1]) : 0; + }; - return events.map((e) => parseEntities(e, options)); + return getLastNumber(a) - getLastNumber(b); + }); + return keys; }