From 44c598bf175ec92b1afa4bd67e183a86a94809fa Mon Sep 17 00:00:00 2001 From: Tarrence van As Date: Fri, 6 Dec 2024 11:26:05 -0500 Subject: [PATCH 01/17] Use preset policies --- packages/keychain/.storybook/preview.tsx | 43 +- .../src/components/Provider/connection.tsx | 3 +- .../src/components/Provider/theme.tsx | 55 +- .../connect/CreateSession.stories.tsx | 4 +- packages/keychain/src/hooks/connection.ts | 57 +- packages/presets/configs/eternum/config.json | 549 +++++++++++++++++- packages/presets/package.json | 3 +- .../presets/scripts/to-session-policies.ts | 92 +++ .../src/generated/controller-configs.ts | 547 +++++++++++++++++ pnpm-lock.yaml | 3 + 10 files changed, 1271 insertions(+), 85 deletions(-) create mode 100644 packages/presets/scripts/to-session-policies.ts diff --git a/packages/keychain/.storybook/preview.tsx b/packages/keychain/.storybook/preview.tsx index cbed86111..744149013 100644 --- a/packages/keychain/.storybook/preview.tsx +++ b/packages/keychain/.storybook/preview.tsx @@ -14,7 +14,12 @@ import Script from "next/script"; import { ETH_CONTRACT_ADDRESS } from "../src/utils/token"; import { ConnectCtx, ConnectionCtx } from "../src/utils/connection/types"; import { UpgradeInterface } from "../src/hooks/upgrade"; -import { defaultTheme, controllerConfigs } from "@cartridge/presets"; +import { + defaultTheme, + controllerConfigs, + SessionPolicies, + ControllerTheme, +} from "@cartridge/presets"; const inter = Inter({ subsets: ["latin"] }); const ibmPlexMono = IBM_Plex_Mono({ @@ -77,7 +82,13 @@ function Provider({ parameters, }: { parameters: StoryParameters } & PropsWithChildren) { const connection = useMockedConnection(parameters.connection); - const theme = parameters.preset || "cartridge"; + + let theme: ControllerTheme = defaultTheme; + if (parameters.preset) { + const config = controllerConfigs[parameters.preset]; + theme = config.theme!; + connection.policies = config.policies || connection.policies; + } return ( @@ -98,6 +109,7 @@ interface StoryParameters extends Parameters { upgrade?: UpgradeInterface; }; preset?: string; + policies?: SessionPolicies; } export function useMockedConnection({ @@ -170,30 +182,13 @@ export default preview; export function ControllerThemeProvider({ children, - theme, -}: PropsWithChildren<{ theme?: string }>) { - const preset = useMemo(() => { - if (!theme) return defaultTheme; - if (theme in controllerConfigs && controllerConfigs[theme].theme) { - return controllerConfigs[theme].theme; - } - return defaultTheme; - }, [theme]); - - const controllerTheme = useMemo( - () => ({ - name: preset.name, - icon: preset.icon, - cover: preset.cover, - }), - [preset], - ); - - useThemeEffect({ theme: preset, assetUrl: "" }); - const chakraTheme = useChakraTheme(preset); + theme = defaultTheme, +}: PropsWithChildren<{ theme?: ControllerTheme }>) { + useThemeEffect({ theme, assetUrl: "" }); + const chakraTheme = useChakraTheme(theme); return ( - + {children} ); diff --git a/packages/keychain/src/components/Provider/connection.tsx b/packages/keychain/src/components/Provider/connection.tsx index 9f53e0c77..36bb7492f 100644 --- a/packages/keychain/src/components/Provider/connection.tsx +++ b/packages/keychain/src/components/Provider/connection.tsx @@ -3,7 +3,7 @@ import Controller from "utils/controller"; import { ConnectionCtx } from "utils/connection"; import { Prefund } from "@cartridge/controller"; import { UpgradeInterface } from "hooks/upgrade"; -import { SessionPolicies } from "@cartridge/presets"; +import { ControllerTheme, SessionPolicies } from "@cartridge/presets"; export const ConnectionContext = createContext< ConnectionContextValue | undefined @@ -17,6 +17,7 @@ export type ConnectionContextValue = { chainId?: string; chainName?: string; policies: SessionPolicies; + theme: ControllerTheme; prefunds: Prefund[]; hasPrefundRequest: boolean; error?: Error; diff --git a/packages/keychain/src/components/Provider/theme.tsx b/packages/keychain/src/components/Provider/theme.tsx index 79493f542..bb1272ffe 100644 --- a/packages/keychain/src/components/Provider/theme.tsx +++ b/packages/keychain/src/components/Provider/theme.tsx @@ -1,9 +1,4 @@ -import { - defaultTheme, - controllerConfigs, - ColorMode, - ControllerTheme, -} from "@cartridge/presets"; +import { ColorMode } from "@cartridge/presets"; import { useThemeEffect } from "@cartridge/ui-next"; import { ChakraProvider, useColorMode } from "@chakra-ui/react"; import { useConnection } from "hooks/connection"; @@ -12,21 +7,13 @@ import { useRouter } from "next/router"; import { PropsWithChildren, useEffect, useMemo } from "react"; export function ControllerThemeProvider({ children }: PropsWithChildren) { - const preset = useControllerThemePreset(); - const controllerTheme = useMemo( - () => ({ - name: preset.name, - icon: preset.icon, - cover: preset.cover, - }), - [preset], - ); + const { theme } = useConnection(); - useThemeEffect({ theme: preset, assetUrl: "" }); - const chakraTheme = useChakraTheme(preset); + useThemeEffect({ theme, assetUrl: "" }); + const chakraTheme = useChakraTheme(theme); return ( - + {children} @@ -45,36 +32,6 @@ function ChakraTheme({ children }: PropsWithChildren) { useEffect(() => { setColorMode(colorMode); }, [setColorMode, colorMode]); - return children; -} - -export function useControllerThemePreset() { - const router = useRouter(); - const { origin } = useConnection(); - - return useMemo(() => { - const themeParam = router.query.theme; - if (typeof themeParam === "undefined") { - return defaultTheme; - } - const val = decodeURIComponent( - Array.isArray(themeParam) - ? themeParam[themeParam.length - 1] - : themeParam, - ); - if ( - typeof val === "string" && - val in controllerConfigs && - controllerConfigs[val].theme - ) { - return controllerConfigs[val].theme; - } - - try { - return JSON.parse(val) as ControllerTheme; - } catch { - return defaultTheme; - } - }, [router.query.theme, origin]); + return children; } diff --git a/packages/keychain/src/components/connect/CreateSession.stories.tsx b/packages/keychain/src/components/connect/CreateSession.stories.tsx index f5341d698..45b25467b 100644 --- a/packages/keychain/src/components/connect/CreateSession.stories.tsx +++ b/packages/keychain/src/components/connect/CreateSession.stories.tsx @@ -22,9 +22,9 @@ export const Default: Story = { }, }; -export const WithTheme: Story = { +export const WithPreset: Story = { parameters: { - preset: "loot-survivor", + preset: "eternum", }, args: { onConnect: () => {}, diff --git a/packages/keychain/src/hooks/connection.ts b/packages/keychain/src/hooks/connection.ts index 72df762f9..fc9eae9fb 100644 --- a/packages/keychain/src/hooks/connection.ts +++ b/packages/keychain/src/hooks/connection.ts @@ -22,6 +22,12 @@ import { import { UpgradeInterface, useUpgrade } from "./upgrade"; import posthog from "posthog-js"; import { Policies, SessionPolicies } from "@cartridge/presets"; +import { + defaultTheme, + controllerConfigs, + ControllerTheme, +} from "@cartridge/presets"; +import { toArray } from "@cartridge/controller"; const CHAIN_ID_TIMEOUT = 3000; @@ -34,6 +40,7 @@ export function useConnectionValue() { const [rpcUrl, setRpcUrl] = useState(); const [chainId, setChainId] = useState(); const [policies, setPolicies] = useState({}); + const [theme, setTheme] = useState(defaultTheme); const [controller, setControllerRaw] = useState(); const [prefunds, setPrefunds] = useState([]); const [hasPrefundRequest, setHasPrefundRequest] = useState(false); @@ -105,19 +112,54 @@ export function useConnectionValue() { ); } + // Handle prefunds const prefundParam = urlParams.get("prefunds"); const prefunds: Prefund[] = prefundParam ? JSON.parse(decodeURIComponent(prefundParam)) : []; setHasPrefundRequest(!!prefundParam); setPrefunds(mergeDefaultETHPrefund(prefunds)); - setPolicies(() => { - const param = urlParams.get("policies"); - if (!param) return {}; - const policies = JSON.parse(decodeURIComponent(param)) as Policies; - return toSessionPolicies(policies); - }); + // Handle theme and policies + const policiesParam = urlParams.get("policies"); + const themeParam = urlParams.get("theme"); + const presetParam = urlParams.get("preset"); + + // Provides backward compatability for Controler <= v0.5.1 + if (themeParam) { + const decodedPreset = decodeURIComponent(themeParam); + const parsedTheme = JSON.parse(decodedPreset) as ControllerTheme; + setTheme(parsedTheme); + } + + // URL policies take precedence over preset policies + if (policiesParam) { + try { + const parsedPolicies = JSON.parse( + decodeURIComponent(policiesParam), + ) as Policies; + setPolicies(toSessionPolicies(parsedPolicies)); + } catch (e) { + console.error("Failed to parse policies:", e); + setPolicies({}); + } + } + + // Application provided policies take precedence over preset policies. + if ( + presetParam && + presetParam in controllerConfigs && + origin && + (origin.startsWith("http://localhost") || + toArray(controllerConfigs[presetParam].origin).includes(origin)) + ) { + setTheme(controllerConfigs[presetParam].theme || defaultTheme); + + // Set policies from preset if no URL policies + if (!policiesParam && controllerConfigs[presetParam].policies) { + setPolicies(controllerConfigs[presetParam].policies); + } + } const connection = connectToController({ setOrigin, @@ -131,7 +173,7 @@ export function useConnectionValue() { return () => { connection.destroy(); }; - }, [setController]); + }, [setController, origin]); useEffect(() => { if (rpcUrl) { @@ -189,6 +231,7 @@ export function useConnectionValue() { chainId, chainName, policies, + theme, prefunds, hasPrefundRequest, error, diff --git a/packages/presets/configs/eternum/config.json b/packages/presets/configs/eternum/config.json index c1f6d2110..6d4f8af71 100644 --- a/packages/presets/configs/eternum/config.json +++ b/packages/presets/configs/eternum/config.json @@ -1,5 +1,552 @@ { "origin": "", + "policies": { + "contracts": { + "0x037d6041960174159E2588f0ee52b3e732b2d3A48528124c046e30180abB84fA": { + "methods": [ + { + "name": "Create Bank", + "description": "", + "entrypoint": "create_bank" + }, + { + "name": "Change Owner Amm Fee", + "description": "", + "entrypoint": "change_owner_amm_fee" + }, + { + "name": "Change Owner Bridge Fee", + "description": "", + "entrypoint": "change_owner_bridge_fee" + } + ] + }, + "0x047d88C65A627b38d728a783382Af648D79AED80Bf396047F9E839e8501d7F6D": { + "methods": [ + { + "name": "Battle Pillage", + "description": "", + "entrypoint": "battle_pillage" + } + ] + }, + "0x001cE27792b23cE379398F5468b69739e89314b2657Cfa3A9c388BDFD33DcFbf": { + "methods": [ + { + "name": "Battle Start", + "description": "", + "entrypoint": "battle_start" + }, + { + "name": "Battle Force Start", + "description": "", + "entrypoint": "battle_force_start" + }, + { + "name": "Battle Join", + "description": "", + "entrypoint": "battle_join" + }, + { + "name": "Battle Leave", + "description": "", + "entrypoint": "battle_leave" + }, + { + "name": "Battle Claim", + "description": "", + "entrypoint": "battle_claim" + } + ] + }, + "0x03c212B90cC4f236BE2C014e0EE0D870277b2cC313217a73D41387E255e806ED": { + "methods": [ + { + "name": "Leave Battle", + "description": "", + "entrypoint": "leave_battle" + }, + { + "name": "Leave Battle If Ended", + "description": "", + "entrypoint": "leave_battle_if_ended" + } + ] + }, + "0x036b82076142f07fbD8bF7B2CABF2e6B190082c0b242c6eCC5e14B2C96d1763c": { + "methods": [ + { + "name": "Create", + "description": "", + "entrypoint": "create" + }, + { + "name": "Pause Production", + "description": "", + "entrypoint": "pause_production" + }, + { + "name": "Resume Production", + "description": "", + "entrypoint": "resume_production" + }, + { + "name": "Destroy", + "description": "", + "entrypoint": "destroy" + } + ] + }, + "0x06fB53696e3d361e88979b9A48bC9925971cBa735cF13275A9157142B2B4C608": { + "methods": [ + { + "name": "Set World Config", + "description": "", + "entrypoint": "set_world_config" + }, + { + "name": "Set Season Config", + "description": "", + "entrypoint": "set_season_config" + }, + { + "name": "Set Quest Config", + "description": "", + "entrypoint": "set_quest_config" + }, + { + "name": "Set Quest Reward Config", + "description": "", + "entrypoint": "set_quest_reward_config" + }, + { + "name": "Set Map Config", + "description": "", + "entrypoint": "set_map_config" + }, + { + "name": "Set Capacity Config", + "description": "", + "entrypoint": "set_capacity_config" + }, + { + "name": "Set Travel Stamina Cost Config", + "description": "", + "entrypoint": "set_travel_stamina_cost_config" + }, + { + "name": "Set Weight Config", + "description": "", + "entrypoint": "set_weight_config" + }, + { + "name": "Set Battle Config", + "description": "", + "entrypoint": "set_battle_config" + }, + { + "name": "Set Tick Config", + "description": "", + "entrypoint": "set_tick_config" + }, + { + "name": "Set Stamina Config", + "description": "", + "entrypoint": "set_stamina_config" + }, + { + "name": "Set Travel Food Cost Config", + "description": "", + "entrypoint": "set_travel_food_cost_config" + }, + { + "name": "Set Stamina Refill Config", + "description": "", + "entrypoint": "set_stamina_refill_config" + }, + { + "name": "Set Leveling Config", + "description": "", + "entrypoint": "set_leveling_config" + }, + { + "name": "Set Production Config", + "description": "", + "entrypoint": "set_production_config" + }, + { + "name": "Set Speed Config", + "description": "", + "entrypoint": "set_speed_config" + }, + { + "name": "Set Hyperstructure Config", + "description": "", + "entrypoint": "set_hyperstructure_config" + }, + { + "name": "Set Bank Config", + "description": "", + "entrypoint": "set_bank_config" + }, + { + "name": "Set Troop Config", + "description": "", + "entrypoint": "set_troop_config" + }, + { + "name": "Set Building Category Pop Config", + "description": "", + "entrypoint": "set_building_category_pop_config" + }, + { + "name": "Set Population Config", + "description": "", + "entrypoint": "set_population_config" + }, + { + "name": "Set Building General Config", + "description": "", + "entrypoint": "set_building_general_config" + }, + { + "name": "Set Building Config", + "description": "", + "entrypoint": "set_building_config" + }, + { + "name": "Set Mercenaries Config", + "description": "", + "entrypoint": "set_mercenaries_config" + }, + { + "name": "Set Resource Bridge Config", + "description": "", + "entrypoint": "set_resource_bridge_config" + }, + { + "name": "Set Resource Bridge Fee Split Config", + "description": "", + "entrypoint": "set_resource_bridge_fee_split_config" + }, + { + "name": "Set Resource Bridge Whitelist Config", + "description": "", + "entrypoint": "set_resource_bridge_whitelist_config" + }, + { + "name": "Set Realm Max Level Config", + "description": "", + "entrypoint": "set_realm_max_level_config" + }, + { + "name": "Set Realm Level Config", + "description": "", + "entrypoint": "set_realm_level_config" + }, + { + "name": "Set Settlement Config", + "description": "", + "entrypoint": "set_settlement_config" + } + ] + }, + "0x0562d27d0C3dB5f34ee37F758D34A01163E933165aa9b794265e6c10d667AF20": { + "methods": [ + { + "name": "Create Admin Bank", + "description": "", + "entrypoint": "create_admin_bank" + } + ] + }, + "0x005291E7F4c092A2a5975BD29e9b42Cb69cdC831214A27a675d732AD33F4af7c": { + "methods": [ + { + "name": "Create", + "description": "", + "entrypoint": "create" + } + ] + }, + "0x06B768187dd4D1dD3fE45A2533C6e099C596283F7699d786e40d701334b76bD8": { + "methods": [ + { + "name": "Mint", + "description": "", + "entrypoint": "mint" + } + ] + }, + "0x012A0ca4558518d6aF296b8F393a917Bb89b3e78Ba33544814B7D9138cE4816e": { + "methods": [ + { + "name": "Create Guild", + "description": "", + "entrypoint": "create_guild" + }, + { + "name": "Join Guild", + "description": "", + "entrypoint": "join_guild" + }, + { + "name": "Whitelist Player", + "description": "", + "entrypoint": "whitelist_player" + }, + { + "name": "Leave Guild", + "description": "", + "entrypoint": "leave_guild" + }, + { + "name": "Transfer Guild Ownership", + "description": "", + "entrypoint": "transfer_guild_ownership" + }, + { + "name": "Remove Guild Member", + "description": "", + "entrypoint": "remove_guild_member" + }, + { + "name": "Remove Player From Whitelist", + "description": "", + "entrypoint": "remove_player_from_whitelist" + } + ] + }, + "0x03BA22B088a94093F781A968E3f82a88B2Ab5047e9C309C93066f00E37334dE6": { + "methods": [ + { + "name": "Create", + "description": "", + "entrypoint": "create" + }, + { + "name": "Contribute To Construction", + "description": "", + "entrypoint": "contribute_to_construction" + }, + { + "name": "Set Co Owners", + "description": "", + "entrypoint": "set_co_owners" + }, + { + "name": "End Game", + "description": "", + "entrypoint": "end_game" + }, + { + "name": "Set Access", + "description": "", + "entrypoint": "set_access" + } + ] + }, + "0x07a5e4dFaBA7AcEd9ADD65913d44311D74E12F85C55503EBF903103B102847e5": { + "methods": [ + { + "name": "Add", + "description": "", + "entrypoint": "add" + }, + { + "name": "Remove", + "description": "", + "entrypoint": "remove" + } + ] + }, + "0x07e16a342A6ccC2c666805925e584B2B52967Bd1C2391B705d393c744BF239c1": { + "methods": [ + { + "name": "Discover Shards Mine", + "description": "", + "entrypoint": "discover_shards_mine" + }, + { + "name": "Add Mercenaries To Structure", + "description": "", + "entrypoint": "add_mercenaries_to_structure" + } + ] + }, + "0x00CC0C73458864B9e0e884DE532b7EBFbe757E7429fB2c736aBd5E129e5FB81A": { + "methods": [ + { + "name": "Explore", + "description": "", + "entrypoint": "explore" + } + ] + }, + "0x027952F3C1C681790a168E5422C21278d925CD1BDD8DAf1CdE8E63aFDfD19E20": { + "methods": [ + { + "name": "Set Address Name", + "description": "", + "entrypoint": "set_address_name" + }, + { + "name": "Set Entity Name", + "description": "", + "entrypoint": "set_entity_name" + } + ] + }, + "0x01BD8e8Db3EEC84B21f8F55609CaD83CEA80812bF6Ff365DC67D787aF818E63E": { + "methods": [ + { + "name": "Transfer Ownership", + "description": "", + "entrypoint": "transfer_ownership" + } + ] + }, + "0x024A8AFd7523e933d37eA2c91aD629fCCde8Ce23cEFA3c324C6248Ca929e3862": { + "methods": [ + { + "name": "Create", + "description": "", + "entrypoint": "create" + }, + { + "name": "Upgrade Level", + "description": "", + "entrypoint": "upgrade_level" + }, + { + "name": "Quest Claim", + "description": "", + "entrypoint": "quest_claim" + } + ] + }, + "0x0161A4CF2e207359dC7Dbf912b21e9099B7729bedE2544F849F384fCb166a109": { + "methods": [ + { + "name": "Deposit Initial", + "description": "", + "entrypoint": "deposit_initial" + }, + { + "name": "Deposit", + "description": "", + "entrypoint": "deposit" + }, + { + "name": "Start Withdraw", + "description": "", + "entrypoint": "start_withdraw" + }, + { + "name": "Finish Withdraw", + "description": "", + "entrypoint": "finish_withdraw" + } + ] + }, + "0x0763fa425503dB5D4bdfF040f6f7509E6eCd8e3F7E75450B9b28f8fc4cDD2877": { + "methods": [ + { + "name": "Approve", + "description": "", + "entrypoint": "approve" + }, + { + "name": "Send", + "description": "", + "entrypoint": "send" + }, + { + "name": "Pickup", + "description": "", + "entrypoint": "pickup" + } + ] + }, + "0x030a4A6472FF2BcFc68d709802E5A9F31F5AC01D04fa97e37D32CE7568741262": { + "methods": [ + { + "name": "Buy", + "description": "", + "entrypoint": "buy" + }, + { + "name": "Sell", + "description": "", + "entrypoint": "sell" + } + ] + }, + "0x0003A6bBB82F9E670c99647F3B0C4AaF1Be82Be712E1A393336B79B9DAB44cc5": { + "methods": [ + { + "name": "Create Order", + "description": "", + "entrypoint": "create_order" + }, + { + "name": "Accept Order", + "description": "", + "entrypoint": "accept_order" + }, + { + "name": "Accept Partial Order", + "description": "", + "entrypoint": "accept_partial_order" + }, + { + "name": "Cancel Order", + "description": "", + "entrypoint": "cancel_order" + } + ] + }, + "0x0119Bf067E05955c0F17f1d4900977fAcBDc10e046E2319FD4d1320f5cc8Be38": { + "methods": [ + { + "name": "Travel", + "description": "", + "entrypoint": "travel" + }, + { + "name": "Travel Hex", + "description": "", + "entrypoint": "travel_hex" + } + ] + }, + "0x046998418397972011E93D370c2f7ac06184AD7Ed9e0811C5c9f88C1feF9445F": { + "methods": [ + { + "name": "Army Create", + "description": "", + "entrypoint": "army_create" + }, + { + "name": "Army Delete", + "description": "", + "entrypoint": "army_delete" + }, + { + "name": "Army Buy Troops", + "description": "", + "entrypoint": "army_buy_troops" + }, + { + "name": "Army Merge Troops", + "description": "", + "entrypoint": "army_merge_troops" + } + ] + } + }, + "messages": [] + }, "theme": { "name": "Eternum", "icon": "/whitelabel/eternum/icon.svg", @@ -8,4 +555,4 @@ "primary": "#dc8b07" } } -} +} \ No newline at end of file diff --git a/packages/presets/package.json b/packages/presets/package.json index 43e0cc646..dfbb1571b 100644 --- a/packages/presets/package.json +++ b/packages/presets/package.json @@ -37,6 +37,7 @@ "@cartridge/tsconfig": "workspace:*", "@types/node": "^20.11.0", "tsx": "^4.7.0", - "typescript": "^5.4.5" + "typescript": "^5.4.5", + "starknet": "6.11.0" } } diff --git a/packages/presets/scripts/to-session-policies.ts b/packages/presets/scripts/to-session-policies.ts new file mode 100644 index 000000000..8939823b3 --- /dev/null +++ b/packages/presets/scripts/to-session-policies.ts @@ -0,0 +1,92 @@ +import fs from "fs"; +import path from "path"; +import { getChecksumAddress } from "starknet"; +import { Policies, SessionPolicies } from "@cartridge/presets"; + +const inputPath = path.join(process.cwd(), "configs/eternum/Policies (1).tsx"); +const outputPath = path.join( + process.cwd(), + "src/generated/session-policies.ts", +); + +function humanizeString(str: string): string { + return str + .split("_") + .map((s) => s.charAt(0).toUpperCase() + s.slice(1)) + .join(" "); +} + +function toArray(val: T | T[]): T[] { + return Array.isArray(val) ? val : [val]; +} + +async function main() { + try { + // Read and parse input file + const fileContent = fs.readFileSync(inputPath, "utf-8"); + const policiesMatch = fileContent.match( + /export const policies = (\[[\s\S]*?\]);/, + ); + + if (!policiesMatch) { + throw new Error("Could not find policies array in input file"); + } + + const policies: Policies = eval(policiesMatch[1]); + + // Convert to session policies + const sessionPolicies = policies.reduce( + (prev, p) => { + if ("target" in p) { + const target = getChecksumAddress(p.target); + const entrypoint = p.method; + const item = { + name: humanizeString(entrypoint), + entrypoint: entrypoint, + }; + + if (target in prev.contracts) { + const methods = toArray(prev.contracts[target].methods); + prev.contracts[target] = { + methods: [...methods, item], + }; + } else { + prev.contracts[target] = { + methods: [item], + }; + } + } else { + prev.messages.push(p); + } + + return prev; + }, + { contracts: {}, messages: [] }, + ); + + // Ensure output directory exists + const outputDir = path.dirname(outputPath); + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + // Write output file + const output = `// This file is auto-generated. DO NOT EDIT IT MANUALLY. +import { SessionPolicies } from "@cartridge/presets"; + +export const sessionPolicies: SessionPolicies = ${JSON.stringify( + sessionPolicies, + null, + 2, + )}; +`; + + fs.writeFileSync(outputPath, output); + console.log("Successfully generated session policies at:", outputPath); + } catch (error) { + console.log(`Failed to generate session policies: ${error.message}`); + process.exit(1); + } +} + +main(); diff --git a/packages/presets/src/generated/controller-configs.ts b/packages/presets/src/generated/controller-configs.ts index 64df395d3..72777031a 100644 --- a/packages/presets/src/generated/controller-configs.ts +++ b/packages/presets/src/generated/controller-configs.ts @@ -48,6 +48,553 @@ export const configs: ControllerConfigs = { }, eternum: { origin: "", + policies: { + contracts: { + "0x037d6041960174159E2588f0ee52b3e732b2d3A48528124c046e30180abB84fA": { + methods: [ + { + name: "Create Bank", + description: "", + entrypoint: "create_bank", + }, + { + name: "Change Owner Amm Fee", + description: "", + entrypoint: "change_owner_amm_fee", + }, + { + name: "Change Owner Bridge Fee", + description: "", + entrypoint: "change_owner_bridge_fee", + }, + ], + }, + "0x047d88C65A627b38d728a783382Af648D79AED80Bf396047F9E839e8501d7F6D": { + methods: [ + { + name: "Battle Pillage", + description: "", + entrypoint: "battle_pillage", + }, + ], + }, + "0x001cE27792b23cE379398F5468b69739e89314b2657Cfa3A9c388BDFD33DcFbf": { + methods: [ + { + name: "Battle Start", + description: "", + entrypoint: "battle_start", + }, + { + name: "Battle Force Start", + description: "", + entrypoint: "battle_force_start", + }, + { + name: "Battle Join", + description: "", + entrypoint: "battle_join", + }, + { + name: "Battle Leave", + description: "", + entrypoint: "battle_leave", + }, + { + name: "Battle Claim", + description: "", + entrypoint: "battle_claim", + }, + ], + }, + "0x03c212B90cC4f236BE2C014e0EE0D870277b2cC313217a73D41387E255e806ED": { + methods: [ + { + name: "Leave Battle", + description: "", + entrypoint: "leave_battle", + }, + { + name: "Leave Battle If Ended", + description: "", + entrypoint: "leave_battle_if_ended", + }, + ], + }, + "0x036b82076142f07fbD8bF7B2CABF2e6B190082c0b242c6eCC5e14B2C96d1763c": { + methods: [ + { + name: "Create", + description: "", + entrypoint: "create", + }, + { + name: "Pause Production", + description: "", + entrypoint: "pause_production", + }, + { + name: "Resume Production", + description: "", + entrypoint: "resume_production", + }, + { + name: "Destroy", + description: "", + entrypoint: "destroy", + }, + ], + }, + "0x06fB53696e3d361e88979b9A48bC9925971cBa735cF13275A9157142B2B4C608": { + methods: [ + { + name: "Set World Config", + description: "", + entrypoint: "set_world_config", + }, + { + name: "Set Season Config", + description: "", + entrypoint: "set_season_config", + }, + { + name: "Set Quest Config", + description: "", + entrypoint: "set_quest_config", + }, + { + name: "Set Quest Reward Config", + description: "", + entrypoint: "set_quest_reward_config", + }, + { + name: "Set Map Config", + description: "", + entrypoint: "set_map_config", + }, + { + name: "Set Capacity Config", + description: "", + entrypoint: "set_capacity_config", + }, + { + name: "Set Travel Stamina Cost Config", + description: "", + entrypoint: "set_travel_stamina_cost_config", + }, + { + name: "Set Weight Config", + description: "", + entrypoint: "set_weight_config", + }, + { + name: "Set Battle Config", + description: "", + entrypoint: "set_battle_config", + }, + { + name: "Set Tick Config", + description: "", + entrypoint: "set_tick_config", + }, + { + name: "Set Stamina Config", + description: "", + entrypoint: "set_stamina_config", + }, + { + name: "Set Travel Food Cost Config", + description: "", + entrypoint: "set_travel_food_cost_config", + }, + { + name: "Set Stamina Refill Config", + description: "", + entrypoint: "set_stamina_refill_config", + }, + { + name: "Set Leveling Config", + description: "", + entrypoint: "set_leveling_config", + }, + { + name: "Set Production Config", + description: "", + entrypoint: "set_production_config", + }, + { + name: "Set Speed Config", + description: "", + entrypoint: "set_speed_config", + }, + { + name: "Set Hyperstructure Config", + description: "", + entrypoint: "set_hyperstructure_config", + }, + { + name: "Set Bank Config", + description: "", + entrypoint: "set_bank_config", + }, + { + name: "Set Troop Config", + description: "", + entrypoint: "set_troop_config", + }, + { + name: "Set Building Category Pop Config", + description: "", + entrypoint: "set_building_category_pop_config", + }, + { + name: "Set Population Config", + description: "", + entrypoint: "set_population_config", + }, + { + name: "Set Building General Config", + description: "", + entrypoint: "set_building_general_config", + }, + { + name: "Set Building Config", + description: "", + entrypoint: "set_building_config", + }, + { + name: "Set Mercenaries Config", + description: "", + entrypoint: "set_mercenaries_config", + }, + { + name: "Set Resource Bridge Config", + description: "", + entrypoint: "set_resource_bridge_config", + }, + { + name: "Set Resource Bridge Fee Split Config", + description: "", + entrypoint: "set_resource_bridge_fee_split_config", + }, + { + name: "Set Resource Bridge Whitelist Config", + description: "", + entrypoint: "set_resource_bridge_whitelist_config", + }, + { + name: "Set Realm Max Level Config", + description: "", + entrypoint: "set_realm_max_level_config", + }, + { + name: "Set Realm Level Config", + description: "", + entrypoint: "set_realm_level_config", + }, + { + name: "Set Settlement Config", + description: "", + entrypoint: "set_settlement_config", + }, + ], + }, + "0x0562d27d0C3dB5f34ee37F758D34A01163E933165aa9b794265e6c10d667AF20": { + methods: [ + { + name: "Create Admin Bank", + description: "", + entrypoint: "create_admin_bank", + }, + ], + }, + "0x005291E7F4c092A2a5975BD29e9b42Cb69cdC831214A27a675d732AD33F4af7c": { + methods: [ + { + name: "Create", + description: "", + entrypoint: "create", + }, + ], + }, + "0x06B768187dd4D1dD3fE45A2533C6e099C596283F7699d786e40d701334b76bD8": { + methods: [ + { + name: "Mint", + description: "", + entrypoint: "mint", + }, + ], + }, + "0x012A0ca4558518d6aF296b8F393a917Bb89b3e78Ba33544814B7D9138cE4816e": { + methods: [ + { + name: "Create Guild", + description: "", + entrypoint: "create_guild", + }, + { + name: "Join Guild", + description: "", + entrypoint: "join_guild", + }, + { + name: "Whitelist Player", + description: "", + entrypoint: "whitelist_player", + }, + { + name: "Leave Guild", + description: "", + entrypoint: "leave_guild", + }, + { + name: "Transfer Guild Ownership", + description: "", + entrypoint: "transfer_guild_ownership", + }, + { + name: "Remove Guild Member", + description: "", + entrypoint: "remove_guild_member", + }, + { + name: "Remove Player From Whitelist", + description: "", + entrypoint: "remove_player_from_whitelist", + }, + ], + }, + "0x03BA22B088a94093F781A968E3f82a88B2Ab5047e9C309C93066f00E37334dE6": { + methods: [ + { + name: "Create", + description: "", + entrypoint: "create", + }, + { + name: "Contribute To Construction", + description: "", + entrypoint: "contribute_to_construction", + }, + { + name: "Set Co Owners", + description: "", + entrypoint: "set_co_owners", + }, + { + name: "End Game", + description: "", + entrypoint: "end_game", + }, + { + name: "Set Access", + description: "", + entrypoint: "set_access", + }, + ], + }, + "0x07a5e4dFaBA7AcEd9ADD65913d44311D74E12F85C55503EBF903103B102847e5": { + methods: [ + { + name: "Add", + description: "", + entrypoint: "add", + }, + { + name: "Remove", + description: "", + entrypoint: "remove", + }, + ], + }, + "0x07e16a342A6ccC2c666805925e584B2B52967Bd1C2391B705d393c744BF239c1": { + methods: [ + { + name: "Discover Shards Mine", + description: "", + entrypoint: "discover_shards_mine", + }, + { + name: "Add Mercenaries To Structure", + description: "", + entrypoint: "add_mercenaries_to_structure", + }, + ], + }, + "0x00CC0C73458864B9e0e884DE532b7EBFbe757E7429fB2c736aBd5E129e5FB81A": { + methods: [ + { + name: "Explore", + description: "", + entrypoint: "explore", + }, + ], + }, + "0x027952F3C1C681790a168E5422C21278d925CD1BDD8DAf1CdE8E63aFDfD19E20": { + methods: [ + { + name: "Set Address Name", + description: "", + entrypoint: "set_address_name", + }, + { + name: "Set Entity Name", + description: "", + entrypoint: "set_entity_name", + }, + ], + }, + "0x01BD8e8Db3EEC84B21f8F55609CaD83CEA80812bF6Ff365DC67D787aF818E63E": { + methods: [ + { + name: "Transfer Ownership", + description: "", + entrypoint: "transfer_ownership", + }, + ], + }, + "0x024A8AFd7523e933d37eA2c91aD629fCCde8Ce23cEFA3c324C6248Ca929e3862": { + methods: [ + { + name: "Create", + description: "", + entrypoint: "create", + }, + { + name: "Upgrade Level", + description: "", + entrypoint: "upgrade_level", + }, + { + name: "Quest Claim", + description: "", + entrypoint: "quest_claim", + }, + ], + }, + "0x0161A4CF2e207359dC7Dbf912b21e9099B7729bedE2544F849F384fCb166a109": { + methods: [ + { + name: "Deposit Initial", + description: "", + entrypoint: "deposit_initial", + }, + { + name: "Deposit", + description: "", + entrypoint: "deposit", + }, + { + name: "Start Withdraw", + description: "", + entrypoint: "start_withdraw", + }, + { + name: "Finish Withdraw", + description: "", + entrypoint: "finish_withdraw", + }, + ], + }, + "0x0763fa425503dB5D4bdfF040f6f7509E6eCd8e3F7E75450B9b28f8fc4cDD2877": { + methods: [ + { + name: "Approve", + description: "", + entrypoint: "approve", + }, + { + name: "Send", + description: "", + entrypoint: "send", + }, + { + name: "Pickup", + description: "", + entrypoint: "pickup", + }, + ], + }, + "0x030a4A6472FF2BcFc68d709802E5A9F31F5AC01D04fa97e37D32CE7568741262": { + methods: [ + { + name: "Buy", + description: "", + entrypoint: "buy", + }, + { + name: "Sell", + description: "", + entrypoint: "sell", + }, + ], + }, + "0x0003A6bBB82F9E670c99647F3B0C4AaF1Be82Be712E1A393336B79B9DAB44cc5": { + methods: [ + { + name: "Create Order", + description: "", + entrypoint: "create_order", + }, + { + name: "Accept Order", + description: "", + entrypoint: "accept_order", + }, + { + name: "Accept Partial Order", + description: "", + entrypoint: "accept_partial_order", + }, + { + name: "Cancel Order", + description: "", + entrypoint: "cancel_order", + }, + ], + }, + "0x0119Bf067E05955c0F17f1d4900977fAcBDc10e046E2319FD4d1320f5cc8Be38": { + methods: [ + { + name: "Travel", + description: "", + entrypoint: "travel", + }, + { + name: "Travel Hex", + description: "", + entrypoint: "travel_hex", + }, + ], + }, + "0x046998418397972011E93D370c2f7ac06184AD7Ed9e0811C5c9f88C1feF9445F": { + methods: [ + { + name: "Army Create", + description: "", + entrypoint: "army_create", + }, + { + name: "Army Delete", + description: "", + entrypoint: "army_delete", + }, + { + name: "Army Buy Troops", + description: "", + entrypoint: "army_buy_troops", + }, + { + name: "Army Merge Troops", + description: "", + entrypoint: "army_merge_troops", + }, + ], + }, + }, + messages: [], + }, theme: { name: "Eternum", icon: "/whitelabel/eternum/icon.svg", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9bab76ece..5ddfa8e79 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -467,6 +467,9 @@ importers: '@types/node': specifier: ^20.11.0 version: 20.16.11 + starknet: + specifier: 6.11.0 + version: 6.11.0 tsx: specifier: ^4.7.0 version: 4.19.2 From feffcf8df56670138f4292a2d197c70ffaafa01a Mon Sep 17 00:00:00 2001 From: Tarrence van As Date: Fri, 6 Dec 2024 12:23:59 -0500 Subject: [PATCH 02/17] Modularize session summary --- .../src/components/SessionSummary.tsx | 372 ------------------ .../src/components/connect/CreateSession.tsx | 4 +- .../components/connect/RegisterSession.tsx | 4 +- .../src/components/session/CollapsibleRow.tsx | 33 ++ .../src/components/session/ContractCard.tsx | 97 +++++ .../src/components/session/SignMessages.tsx | 123 ++++++ .../session/UntrustedSessionSummary.tsx | 82 ++++ packages/keychain/src/hooks/session.ts | 61 +++ packages/utils/src/hooks/contract.ts | 164 -------- packages/utils/src/hooks/index.ts | 1 - packages/utils/tsconfig.json | 4 +- 11 files changed, 401 insertions(+), 544 deletions(-) delete mode 100644 packages/keychain/src/components/SessionSummary.tsx create mode 100644 packages/keychain/src/components/session/CollapsibleRow.tsx create mode 100644 packages/keychain/src/components/session/ContractCard.tsx create mode 100644 packages/keychain/src/components/session/SignMessages.tsx create mode 100644 packages/keychain/src/components/session/UntrustedSessionSummary.tsx create mode 100644 packages/keychain/src/hooks/session.ts delete mode 100644 packages/utils/src/hooks/contract.ts diff --git a/packages/keychain/src/components/SessionSummary.tsx b/packages/keychain/src/components/SessionSummary.tsx deleted file mode 100644 index c59c88106..000000000 --- a/packages/keychain/src/components/SessionSummary.tsx +++ /dev/null @@ -1,372 +0,0 @@ -import React, { PropsWithChildren, useEffect, useState } from "react"; -import { toArray } from "@cartridge/controller"; -import { - Card, - CardContent, - CardHeader, - CardHeaderRight, - CardTitle, - Accordion, - AccordionContent, - AccordionItem, - AccordionTrigger, - CircleIcon, - InfoIcon, - CardIcon, - PencilIcon, - CheckboxIcon, - ArrowTurnDownIcon, - Badge, - SpaceInvaderIcon, - TooltipProvider, - Tooltip, - TooltipTrigger, - TooltipContent, - ExternalIcon, - cn, - Spinner, - CoinsIcon, - ErrorImage, - ScrollIcon, -} from "@cartridge/ui-next"; -import { - formatAddress, - isSlotChain, - SessionSummary as SessionSummaryType, - StarkscanUrl, -} from "@cartridge/utils"; -import { constants, StarknetEnumType, StarknetMerkleType } from "starknet"; -import Link from "next/link"; -import { useConnection } from "hooks/connection"; -import { useSessionSummary } from "@cartridge/utils"; -import { ContractPolicy, SessionPolicies } from "@cartridge/presets"; - -export function SessionSummary({ - policies, - setError, -}: { - policies: SessionPolicies; - setError?: (error: Error) => void; -}) { - const { controller } = useConnection(); - const { - data: summary, - error, - isLoading, - } = useSessionSummary({ - policies, - provider: controller, - }); - - useEffect(() => { - setError?.(error); - }, [error, setError]); - - if (isLoading) { - return ; - } - - if (error) { - return ( -
-
-
Oops! Something went wrong parsing session summary
-
Please try it again.
-
- -
- ); - } - - return ( -
- {Object.entries(summary.dojo).map(([address, { methods, meta }]) => ( - - ))} - - {Object.entries(summary.default).map(([address, { methods }], i) => ( - - - - } - /> - ))} - - {Object.entries(summary.ERC20).map(([address, { methods, meta }]) => ( - - ) : ( - - - - ) - } - /> - ))} - - {Object.entries(summary.ERC721).map(([address, { methods }]) => ( - - - - } - /> - ))} - - -
- ); -} - -function Contract({ - address, - title, - methods: _methods, - icon = , -}: { - address: string; - title: string; - methods: ContractPolicy["methods"]; - icon?: React.ReactNode; -}) { - const methods = toArray(_methods); - const { chainId } = useConnection(); - const isSlot = !!chainId && isSlotChain(chainId); - - return ( - - - {title} - - - {formatAddress(address, { size: "xs" })} - - - - - - - - - - - Approve{" "} - - {methods.length} {methods.length > 1 ? "methods" : "method"} - - - - - - {methods.map((c) => ( - - -
-
{c.name}
- - {c.description && ( - - - - - - - {c.description} - - - )} -
-
- ))} -
-
-
-
- ); -} - -function SignMessages({ - messages, -}: { - messages: SessionSummaryType["messages"]; -}) { - if (!messages || !messages.length) { - return null; - } - - return ( - - - -
- } - > - Sign Messages - - - - - - - You are agreeing to sign{" "} - - {messages.length} {messages.length > 1 ? "messages" : "message"} - {" "} - in the following format - - - - - {messages.map((m, i) => ( - - {Object.values(m.domain).filter((f) => typeof f !== "undefined") - .length && ( - - {m.domain.name && ( - - )} - {m.domain.version && ( - - )} - {m.domain.chainId && ( - - )} - {m.domain.revision && ( - - )} - - )} - - - - - {Object.entries(m.types).map(([name, types]) => ( - - {types.map((t) => ( - - ))} - - ))} - - - ))} - - - - - ); -} - -function CollapsibleRow({ - title, - children, -}: PropsWithChildren & { title: string }) { - const [value, setValue] = useState(""); - return ( - - - -
- -
{title}
-
-
- - - {children} - -
-
- ); -} - -function ValueRow({ - values, -}: { - values: { name: string; value: string | number }[]; -}) { - return ( -
- -
- {values.map((f) => ( -
- {f.name}: {f.value} -
- ))} -
-
- ); -} diff --git a/packages/keychain/src/components/connect/CreateSession.tsx b/packages/keychain/src/components/connect/CreateSession.tsx index 84be6ae2d..911389d08 100644 --- a/packages/keychain/src/components/connect/CreateSession.tsx +++ b/packages/keychain/src/components/connect/CreateSession.tsx @@ -9,7 +9,7 @@ import { SessionConsent } from "components/connect"; import { SESSION_EXPIRATION } from "const"; import { Upgrade } from "./Upgrade"; import { ErrorCode } from "@cartridge/account-wasm"; -import { SessionSummary } from "components/SessionSummary"; +import { UntrustedSessionSummary } from "components/session/UntrustedSessionSummary"; import { TypedDataPolicy } from "@cartridge/presets"; export function CreateSession({ @@ -90,7 +90,7 @@ export function CreateSession({ > - +