Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: sync contract + client and update react example #545

Merged
merged 2 commits into from
Jun 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/ecs/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ initializer_class_hash = "0xbeef"
rpc_url = "http://localhost:5050/"

# Default account for katana with seed = 0
account_address = "0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0"
private_key = "0x0300001800000000300000180000000000030000000000003006001800006600"
account_address = "0x06f62894bfd81d2e396ce266b2ad0f21e0668d604e5bb1077337b6d570a54aea"
private_key = "0x07230b49615d175307d580c33d6fda61fc7b9aec91df0f5c1a5ebe3b8cbfee02"
7 changes: 7 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,12 @@
"typescript": "^5.0.3",
"winston": "^3.8.2",
"zustand": "^4.3.7"
},
"dependencies": {
"@latticexyz/recs": "^1.43.0",
"@latticexyz/utils": "^1.36.1\n",
"mobx": "^6.9.0",
"rxjs": "^7.8.1",
"type-fest": "^3.12.0"
}
}
3 changes: 2 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as Providers from './provider';
import * as Account from './account'
import * as Utils from './utils'
import { SyncWorker } from './network/SyncWorker';
import { Query } from './types';
export { Providers, Account, Utils, Query };
export { Providers, Account, Utils, Query, SyncWorker };
44 changes: 44 additions & 0 deletions packages/core/src/network/SyncWorker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Components } from "@latticexyz/recs";
import { Providers } from "..";
import { setComponentFromEntitiesQuery, setComponentFromEvent } from "../utils";
import { Event } from "starknet";

export class SyncWorker<C extends Components> {
private provider: Providers.RPCProvider;
private components: C;
private event_key: String;


constructor(provider: Providers.RPCProvider, components: C, event_key: String) {
console.log("Creating SyncWorker...");
this.provider = provider;
this.components = components;
this.event_key = event_key;
this.init();
}

private async init() {
for (const key of Object.keys(this.components)) {
const component = this.components[key];
if (component.metadata && component.metadata.name) {
// call provider.entities for each component to get all entities linked to that component
const entities = await this.provider.entities(component.metadata.name as string, "0");
setComponentFromEntitiesQuery(component, entities);
}
}
console.log('SyncWorker initialized');
}

public async sync(txHash: string) {
this.provider.provider.getTransactionReceipt(txHash).then((receipt) => {
receipt.events.filter((event) => {
return event.keys.length === 1 &&
event.keys[0] === this.event_key;
}
).map((event: Event) => {
setComponentFromEvent(this.components, event.data);
});

})
}
}
14 changes: 6 additions & 8 deletions packages/core/src/provider/RPCProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,19 @@ export class RPCProvider extends Provider {

public async execute(account: Account, system: string, call_data: number.BigNumberish[]): Promise<InvokeFunctionResponse> {

let call_data_obj = call_data.reduce((obj: any, item, index) => {
obj[index] = item;
return obj;
}, {});
// DISCUSS: is this needed?
// let call_data_obj = call_data.reduce((obj: any, item, index) => {
// obj[index] = item;
// return obj;
// }, {});

try {
const nonce = await account?.getNonce()
const call = await account?.execute(
{
contractAddress: this.getWorldAddress() || "",
entrypoint: WorldEntryPoints.execute,
calldata: stark.compileCalldata({
name: strTofelt252Felt(system),
...call_data_obj
})
calldata: [strTofelt252Felt(system), call_data.length, ...call_data]
},
undefined,
{
Expand Down
91 changes: 90 additions & 1 deletion packages/core/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { EntityIndex, setComponent, Component, Schema, Components } from "@latticexyz/recs";
import { Event } from "starknet";
import { poseidonHashMany } from 'micro-starknet';

export function strTofelt252Felt(str: string): string {
const encoder = new TextEncoder();
const strB = encoder.encode(str);
Expand All @@ -23,4 +27,89 @@ export function getAllSystemNames(manifest: any): any {

export function getAllSystemNamesAsFelt(manifest: any): any {
return manifest.systems.map((system: any) => strTofelt252Felt(system.name));
}
}

// DISCUSSION: MUD expects Numbers, but entities in Starknet are BigInts (from poseidon hash)
// so I am converting them to Numbers here, but it means that there is a bigger risk of collisions
export function getEntityIdFromKeys(keys: bigint[]): EntityIndex {
if (keys.length === 1) {
return parseInt(keys[0].toString()) as EntityIndex;
}
// calculate the poseidon hash of the keys
let poseidon = poseidonHashMany([BigInt(keys.length), ...keys]);
return parseInt(poseidon.toString()) as EntityIndex;
}

export function setComponentFromEntitiesQuery(component: Component, entities: bigint[]) {
let index = 0;

// Retrieve the number of entityIds
const numEntityIds = Number(entities[index++]);

// Retrieve entityIds
const entityIds = entities.slice(index, index + numEntityIds);
index += numEntityIds;

// Retrieve the number of entities with component values
const numEntities = Number(entities[index++]);

for (let i = 0; i < numEntities; i++) {
// Retrieve the number of component values for the current entity
const numValues = Number(entities[index++]);

// Retrieve entity's component values
const valueArray = entities.slice(index, index + numValues)
const componentValues = Object.keys(component.schema).reduce((acc: Schema, key, index) => {
const value = valueArray[index];
acc[key] = Number(value);
return acc;
}, {});

const entityIndex = parseInt(entityIds[i].toString()) as EntityIndex;
setComponent(component, entityIndex, componentValues)

index += numValues;
}
}

export function setComponentFromEvent(components: Components, eventData: string[]) {
// retrieve the component name
const componentName = hex_to_ascii(eventData[0]);

// retrieve the component from name
const component = components[componentName];

// get keys
const keysNumber = parseInt(eventData[1]);
let index = 2 + keysNumber;

const keys = eventData.slice(2, 2 + keysNumber).map((key) => BigInt(key));

// get entityIndex from keys
const entityIndex = getEntityIdFromKeys(keys);

// get values
let numberOfValues = parseInt(eventData[index++]);

// get values
const values = eventData.slice(index, index + numberOfValues);

// create component object from values with schema
const componentValues = Object.keys(component.schema).reduce((acc: Schema, key, index) => {
const value = values[index];
acc[key] = Number(value);
return acc;
}, {});

// set component
setComponent(component, entityIndex, componentValues);

}

function hex_to_ascii(hex: string) {
var str = '';
for (var n = 2; n < hex.length; n += 2) {
str += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
}
return str;
}
73 changes: 73 additions & 0 deletions packages/core/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,18 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"

"@latticexyz/recs@^1.43.0":
version "1.43.0"
resolved "https://registry.yarnpkg.com/@latticexyz/recs/-/recs-1.43.0.tgz#51d8bb0d164ef3c79b86bb8201870177d2eab91b"
integrity sha512-rWCtFeqeoPYT+hsu1whd47cVSvRtOrBe1tGngqxZdiYnLx1bbj5rW9xXzS1Vg+8PgLeX034yZCoV+RjcaGIRPg==

"@latticexyz/utils@^1.36.1\n":
version "1.43.0"
resolved "https://registry.yarnpkg.com/@latticexyz/utils/-/utils-1.43.0.tgz#d8d4747124be541b9b10bb6cf32bf236c0aafaa1"
integrity sha512-8RmAqdg4ASYbOM+fDzIAZDe/1ZEmw1oRsgV18gX8iBjtvNOPImu6nixXE+iZbiOCL3wUifiPJcCThhfo2uKf1w==
dependencies:
typedoc-plugin-markdown "^3.13.6"

"@noble/curves@~1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.0.0.tgz#e40be8c7daf088aaf291887cbc73f43464a92932"
Expand Down Expand Up @@ -1369,6 +1381,18 @@ graphql@^16.6.0:
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.6.0.tgz#c2dcffa4649db149f6282af726c8c83f1c7c5fdb"
integrity sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==

handlebars@^4.7.7:
version "4.7.7"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
dependencies:
minimist "^1.2.5"
neo-async "^2.6.0"
source-map "^0.6.1"
wordwrap "^1.0.0"
optionalDependencies:
uglify-js "^3.1.4"

has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
Expand Down Expand Up @@ -2062,6 +2086,16 @@ minimatch@^3.0.4, minimatch@^3.1.1:
dependencies:
brace-expansion "^1.1.7"

minimist@^1.2.5:
version "1.2.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==

mobx@^6.9.0:
version "6.9.0"
resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.9.0.tgz#8a894c26417c05bed2cf7499322e589ee9787397"
integrity sha512-HdKewQEREEJgsWnErClfbFoVebze6rGazxFLU/XUyrII8dORfVszN1V0BMRnQSzcgsNNtkX8DHj3nC6cdWE9YQ==

ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
Expand All @@ -2077,6 +2111,11 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==

neo-async@^2.6.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==

node-fetch@^2.6.1, node-fetch@^2.6.11:
version "2.6.11"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25"
Expand Down Expand Up @@ -2297,6 +2336,13 @@ resolve@^1.20.0:
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"

rxjs@^7.8.1:
version "7.8.1"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
dependencies:
tslib "^2.1.0"

safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
Expand Down Expand Up @@ -2539,6 +2585,11 @@ ts-jest@^29.1.0:
semver "7.x"
yargs-parser "^21.0.1"

tslib@^2.1.0:
version "2.5.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913"
integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==

type-detect@4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
Expand All @@ -2549,11 +2600,28 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==

type-fest@^3.12.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.12.0.tgz#4ce26edc1ccc59fc171e495887ef391fe1f5280e"
integrity sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==

typedoc-plugin-markdown@^3.13.6:
version "3.15.3"
resolved "https://registry.yarnpkg.com/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.15.3.tgz#f5419a32b93efbdc0fcba60ca4de37727aeb8ba9"
integrity sha512-idntFYu3vfaY3eaD+w9DeRd0PmNGqGuNLKihPU9poxFGnATJYGn9dPtEhn2QrTdishFMg7jPXAhos+2T6YCWRQ==
dependencies:
handlebars "^4.7.7"

typescript@^5.0.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826"
integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==

uglify-js@^3.1.4:
version "3.17.4"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c"
integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==

update-browserslist-db@^1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940"
Expand Down Expand Up @@ -2658,6 +2726,11 @@ winston@^3.8.2:
triple-beam "^1.3.0"
winston-transport "^4.5.0"

wordwrap@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==

wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
Expand Down
Loading