create-dubhe 1.2.0-pre.98 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/package.json +16 -16
- package/templates/101/sui-template/docker-compose.testnet.yml +73 -0
- package/templates/101/sui-template/packages/client/src/app/page.tsx +545 -41
- package/templates/101/sui-template/packages/client/src/app/providers.tsx +12 -4
- package/templates/101/sui-template/packages/contracts/Pub.localnet.toml +4 -4
- package/templates/101/sui-template/packages/contracts/counter.lock.json +20 -0
- package/templates/101/sui-template/packages/contracts/deployment.ts +8 -3
- package/templates/101/sui-template/packages/contracts/dubhe.config.json +59 -13
- package/templates/101/sui-template/packages/contracts/dubhe.config.ts +1 -4
- package/templates/101/sui-template/packages/contracts/metadata.json +1015 -68
- package/templates/101/sui-template/packages/contracts/package.json +7 -4
- package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/dapp_key.move +45 -31
- package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/error.move +8 -0
- package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/genesis.move +30 -13
- package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/init_test.move +19 -14
- package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/resources/counter2.move +198 -0
- package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/resources/counter2withkey.move +90 -0
- package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/resources/value.move +30 -20
- package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/user_storage_init.move +26 -0
- package/templates/101/sui-template/packages/contracts/src/counter/sources/scripts/deploy_hook.move +6 -11
- package/templates/101/sui-template/packages/contracts/src/counter/sources/systems/counter.move +23 -11
- package/templates/101/sui-template/packages/contracts/src/counter/sources/tests/counter.move +15 -14
- package/templates/101/sui-template/packages/contracts/src/dubhe/Move.lock +33 -30
- package/templates/101/sui-template/packages/contracts/src/dubhe/Move.toml +8 -3
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/dapp_key.move +45 -31
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/error.move +170 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/genesis.move +16 -13
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/init_test.move +8 -14
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/account_key.move +1 -3
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/dapp_service.move +1776 -137
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/data_key.move +1 -20
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/events.move +864 -25
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/scripts/deploy_hook.move +15 -16
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/scripts/migrate.move +0 -3
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/systems/address_system.move +25 -17
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/systems/dapp_system.move +2802 -343
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/systems/utils.move +1 -1
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/address.move +173 -55
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/dapp_test.move +769 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/fee_test.move +2965 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/integration_test.move +303 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/listing_test.move +1422 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/scene_session_test.move +269 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/session_test.move +624 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/storage_test.move +700 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/typed_object_test.move +177 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/typed_scene_test.move +452 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/user_storage_test.move +160 -0
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/utils/math.move +4 -3
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/utils/type_info.move +2 -2
- package/templates/contract/sui-template/dubhe.config.ts +0 -1
- package/templates/contract/sui-template/package.json +3 -3
- package/templates/contract/sui-template/src/dubhe/Move.lock +33 -30
- package/templates/contract/sui-template/src/dubhe/Move.toml +8 -3
- package/templates/contract/sui-template/src/dubhe/sources/codegen/dapp_key.move +45 -31
- package/templates/contract/sui-template/src/dubhe/sources/codegen/error.move +170 -0
- package/templates/contract/sui-template/src/dubhe/sources/codegen/genesis.move +16 -13
- package/templates/contract/sui-template/src/dubhe/sources/codegen/init_test.move +8 -14
- package/templates/contract/sui-template/src/dubhe/sources/core/account_key.move +1 -3
- package/templates/contract/sui-template/src/dubhe/sources/core/dapp_service.move +1776 -137
- package/templates/contract/sui-template/src/dubhe/sources/core/data_key.move +1 -20
- package/templates/contract/sui-template/src/dubhe/sources/core/events.move +864 -25
- package/templates/contract/sui-template/src/dubhe/sources/scripts/deploy_hook.move +15 -16
- package/templates/contract/sui-template/src/dubhe/sources/scripts/migrate.move +0 -3
- package/templates/contract/sui-template/src/dubhe/sources/systems/address_system.move +25 -17
- package/templates/contract/sui-template/src/dubhe/sources/systems/dapp_system.move +2802 -343
- package/templates/contract/sui-template/src/dubhe/sources/systems/utils.move +1 -1
- package/templates/contract/sui-template/src/dubhe/sources/tests/address.move +173 -55
- package/templates/contract/sui-template/src/dubhe/sources/tests/dapp_test.move +769 -0
- package/templates/contract/sui-template/src/dubhe/sources/tests/fee_test.move +2965 -0
- package/templates/contract/sui-template/src/dubhe/sources/tests/integration_test.move +303 -0
- package/templates/contract/sui-template/src/dubhe/sources/tests/listing_test.move +1422 -0
- package/templates/contract/sui-template/src/dubhe/sources/tests/scene_session_test.move +269 -0
- package/templates/contract/sui-template/src/dubhe/sources/tests/session_test.move +624 -0
- package/templates/contract/sui-template/src/dubhe/sources/tests/storage_test.move +700 -0
- package/templates/contract/sui-template/src/dubhe/sources/tests/typed_object_test.move +177 -0
- package/templates/contract/sui-template/src/dubhe/sources/tests/typed_scene_test.move +452 -0
- package/templates/contract/sui-template/src/dubhe/sources/tests/user_storage_test.move +160 -0
- package/templates/contract/sui-template/src/dubhe/sources/utils/math.move +4 -3
- package/templates/contract/sui-template/src/dubhe/sources/utils/type_info.move +2 -2
- package/templates/contract/sui-template/src/template/Move.toml +12 -0
- package/templates/contract/sui-template/src/template/sources/codegen/dapp_key.move +47 -0
- package/templates/contract/sui-template/src/template/sources/codegen/genesis.move +34 -0
- package/templates/contract/sui-template/src/template/sources/codegen/init_test.move +23 -0
- package/templates/contract/sui-template/src/template/sources/codegen/user_storage_init.move +27 -0
- package/templates/contract/sui-template/src/template/sources/scripts/deploy_hook.move +13 -0
- package/templates/contract/sui-template/src/template/sources/scripts/migrate.move +7 -0
- package/templates/nextjs/sui-card-duel/.gitignore_ +51 -0
- package/templates/nextjs/sui-card-duel/README.md +213 -0
- package/templates/nextjs/sui-card-duel/docker-compose.yml +34 -0
- package/templates/nextjs/sui-card-duel/mprocs.yaml +17 -0
- package/templates/nextjs/sui-card-duel/package.json +43 -0
- package/templates/nextjs/sui-card-duel/packages/client/.gitignore_ +48 -0
- package/templates/nextjs/sui-card-duel/packages/client/.prettierignore +1 -0
- package/templates/nextjs/sui-card-duel/packages/client/.prettierrc.json +8 -0
- package/templates/nextjs/sui-card-duel/packages/client/eslint.config.mjs +22 -0
- package/templates/nextjs/sui-card-duel/packages/client/next.config.mjs +8 -0
- package/templates/nextjs/sui-card-duel/packages/client/package.json +47 -0
- package/templates/nextjs/sui-card-duel/packages/client/postcss.config.mjs +8 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/admin/ArenaPanel.tsx +307 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/admin/page.tsx +622 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/brawl/[id]/page.tsx +559 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/collection/page.tsx +202 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/components/CardView.tsx +66 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/components/GameShell.tsx +294 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/components/icons.tsx +101 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/duel/[id]/page.tsx +477 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/favicon.ico +0 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/globals.css +85 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/hooks/useGame.ts +313 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/layout.tsx +24 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/leaderboard/page.tsx +123 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/lib/game.ts +77 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/lib/scenes.ts +226 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/market/page.tsx +418 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/page.tsx +427 -0
- package/templates/nextjs/sui-card-duel/packages/client/src/app/providers.tsx +69 -0
- package/templates/nextjs/sui-card-duel/packages/client/tailwind.config.ts +21 -0
- package/templates/nextjs/sui-card-duel/packages/client/tsconfig.json +30 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/.gitignore_ +51 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/.prettierignore +1 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/.prettierrc.json +8 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/Dockerfile +5 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/Pub.localnet.toml +13 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/card_duel.lock.json +66 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/docker-compose.yml +34 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/dubhe.config.ts +150 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/logs/combined.log +31383 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/package.json +49 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/scripts/config.ts +17 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/scripts/e2e-brawl.ts +270 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/scripts/e2e-duel.ts +272 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/scripts/e2e-lobby.ts +177 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/scripts/e2e-market.ts +219 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/scripts/e2e-session.ts +342 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/scripts/query-dapp-revenue.ts +95 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/scripts/seed.ts +92 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/scripts/withdraw-dapp-revenue.ts +56 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/Move.toml +15 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/dapp_key.move +46 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/enums/card_kind.move +47 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/enums/match_state.move +37 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/enums/rarity.move +37 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/error.move +126 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/genesis.move +33 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/init_test.move +23 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/objects/arena.move +137 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/permits/brawl_permit.move +125 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/permits/duel_permit.move +125 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/battle_state.move +255 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/card.move +282 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/deck.move +64 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/game_config.move +267 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/gold.move +205 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/resources/profile.move +255 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/scenes/brawl.move +313 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/scenes/duel.move +313 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/codegen/user_storage_init.move +26 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/scripts/deploy_hook.move +32 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/scripts/migrate.move +7 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/arena_system.move +57 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/brawl_system.move +559 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/card_system.move +146 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/duel_system.move +515 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/market_system.move +115 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/systems/player_system.move +37 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/tests/brawl_tests.move +385 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/tests/duel_tests.move +656 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/src/card_duel/sources/tests/test_helpers.move +31 -0
- package/templates/nextjs/sui-card-duel/packages/contracts/sui-indexer-schema.graphql +5973 -0
- package/templates/nextjs/sui-card-duel/pnpm-workspace.yaml +2 -0
- package/templates/nextjs/sui-farm/.gitignore_ +51 -0
- package/templates/nextjs/sui-farm/README.md +15 -0
- package/templates/nextjs/sui-farm/UPGRADE_NOTES.md +97 -0
- package/templates/nextjs/sui-farm/docker-compose.yml +34 -0
- package/templates/nextjs/sui-farm/mprocs.yaml +17 -0
- package/templates/nextjs/sui-farm/package.json +43 -0
- package/templates/nextjs/sui-farm/packages/client/.gitignore_ +48 -0
- package/templates/nextjs/sui-farm/packages/client/.prettierignore +1 -0
- package/templates/nextjs/sui-farm/packages/client/.prettierrc.json +8 -0
- package/templates/nextjs/sui-farm/packages/client/eslint.config.mjs +22 -0
- package/templates/nextjs/sui-farm/packages/client/next.config.mjs +8 -0
- package/templates/nextjs/sui-farm/packages/client/package.json +47 -0
- package/templates/nextjs/sui-farm/packages/client/postcss.config.mjs +8 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/admin/page.tsx +618 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/components/FarmLand.tsx +526 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/components/FarmPlotCard.tsx +215 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/components/PetAvatar.tsx +868 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/components/PetPanel.tsx +1360 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/components/PlantModal.tsx +147 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/components/ProxyCard.tsx +684 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/components/RanchLand.tsx +822 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/components/ResourceHUD.tsx +125 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/components/ShopPanel.tsx +232 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/components/icons/GameIcons.tsx +574 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/favicon.ico +0 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/globals.css +423 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/hooks/useWorldPermitId.ts +66 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/layout.tsx +23 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/leaderboard/page.tsx +185 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/lib/crops.ts +97 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/market/page.tsx +763 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/page.tsx +1173 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/providers.tsx +69 -0
- package/templates/nextjs/sui-farm/packages/client/src/app/state/index.tsx +5 -0
- package/templates/nextjs/sui-farm/packages/client/tailwind.config.ts +25 -0
- package/templates/nextjs/sui-farm/packages/client/tsconfig.json +30 -0
- package/templates/nextjs/sui-farm/packages/contracts/.gitignore_ +51 -0
- package/templates/nextjs/sui-farm/packages/contracts/.prettierignore +1 -0
- package/templates/nextjs/sui-farm/packages/contracts/.prettierrc.json +8 -0
- package/templates/nextjs/sui-farm/packages/contracts/Dockerfile +5 -0
- package/templates/nextjs/sui-farm/packages/contracts/Pub.localnet.toml +13 -0
- package/templates/nextjs/sui-farm/packages/contracts/counter.lock.json +14 -0
- package/templates/nextjs/sui-farm/packages/contracts/docker-compose.yml +34 -0
- package/templates/nextjs/sui-farm/packages/contracts/dubhe.config.ts +178 -0
- package/templates/nextjs/sui-farm/packages/contracts/harvest.lock.json +120 -0
- package/templates/nextjs/sui-farm/packages/contracts/package.json +48 -0
- package/templates/nextjs/sui-farm/packages/contracts/scripts/config.ts +17 -0
- package/templates/nextjs/sui-farm/packages/contracts/scripts/query-dapp-revenue.ts +95 -0
- package/templates/nextjs/sui-farm/packages/contracts/scripts/read-permit.ts +72 -0
- package/templates/nextjs/sui-farm/packages/contracts/scripts/seed.ts +85 -0
- package/templates/nextjs/sui-farm/packages/contracts/scripts/withdraw-dapp-revenue.ts +56 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/Move.toml +14 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/dapp_key.move +31 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/error.move +10 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/genesis.move +33 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/init_test.move +23 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/resources/counter1.move +64 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/resources/counter2.move +70 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/codegen/user_storage_init.move +26 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/scripts/deploy_hook.move +8 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/scripts/migrate.move +8 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/systems/counter.move +13 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/counter/sources/tests/counter.move +28 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/Move.toml +14 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/dapp_key.move +46 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/enums/crop_type.move +47 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/enums/egg_type.move +42 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/enums/pet_rarity.move +37 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/enums/pet_species.move +52 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/error.move +110 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/genesis.move +33 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/init_test.move +23 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/permits/world.move +125 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/carrot.move +136 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/carrot_seed.move +80 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/common_egg.move +136 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/corn.move +136 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/corn_seed.move +80 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/crow_charges.move +162 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/crow_damage.move +207 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/farm_plot.move +261 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/gold.move +80 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pet.move +467 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pet_config.move +372 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pet_hatch.move +162 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pet_slot_index.move +83 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pet_slots.move +64 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/profile.move +162 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pumpkin.move +136 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/pumpkin_seed.move +80 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/rare_egg.move +136 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/scarecrow.move +64 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/season_config.move +197 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/season_stats.move +64 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/seasonal_egg.move +136 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/shop_config.move +267 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/trophy.move +245 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/wheat.move +136 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/wheat_seed.move +80 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/world_permit_id.move +64 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/user_storage_init.move +26 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/scripts/deploy_hook.move +45 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/scripts/migrate.move +7 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/crow_system.move +96 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/farm_system.move +182 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/market_system.move +172 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/pet_system.move +495 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/season_system.move +70 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/shop_system.move +112 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/systems/world_system.move +34 -0
- package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/tests/farm_tests.move +1192 -0
- package/templates/nextjs/sui-farm/pnpm-workspace.yaml +2 -0
- package/templates/nextjs/sui-template/packages/client/src/app/components/ProxyCard.tsx +683 -0
- package/templates/nextjs/sui-template/packages/client/src/app/page.tsx +510 -5
- package/templates/nextjs/sui-template/packages/client/src/app/providers.tsx +13 -5
- package/templates/nextjs/sui-template/packages/contracts/Pub.localnet.toml +4 -4
- package/templates/nextjs/sui-template/packages/contracts/counter.lock.json +14 -0
- package/templates/nextjs/sui-template/packages/contracts/deployment.ts +8 -3
- package/templates/nextjs/sui-template/packages/contracts/dubhe.config.json +9 -9
- package/templates/nextjs/sui-template/packages/contracts/dubhe.config.ts +0 -4
- package/templates/nextjs/sui-template/packages/contracts/metadata.json +180 -124
- package/templates/nextjs/sui-template/packages/contracts/package.json +8 -4
- package/templates/nextjs/sui-template/packages/contracts/src/counter/Move.toml +4 -0
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/dapp_key.move +45 -31
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/error.move +10 -0
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/genesis.move +30 -13
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/init_test.move +19 -14
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/resources/counter1.move +30 -20
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/resources/counter2.move +35 -24
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/user_storage_init.move +26 -0
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/scripts/deploy_hook.move +6 -10
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/systems/counter.move +7 -20
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/tests/counter.move +14 -27
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/Move.lock +33 -30
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/Move.toml +8 -3
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/dapp_key.move +45 -31
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/error.move +170 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/genesis.move +16 -13
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/init_test.move +8 -14
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/account_key.move +1 -3
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/dapp_service.move +1776 -137
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/data_key.move +1 -20
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/events.move +864 -25
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/scripts/deploy_hook.move +15 -16
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/scripts/migrate.move +0 -3
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/address_system.move +25 -17
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/dapp_system.move +2802 -343
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/utils.move +1 -1
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/address.move +173 -55
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/dapp_test.move +769 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/fee_test.move +2965 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/integration_test.move +303 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/listing_test.move +1422 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/scene_session_test.move +269 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/session_test.move +624 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/storage_test.move +700 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/typed_object_test.move +177 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/typed_scene_test.move +452 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/user_storage_test.move +160 -0
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/utils/math.move +4 -3
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/utils/type_info.move +2 -2
- package/templates/101/sui-template/packages/contracts/src/counter/Move.lock +0 -41
- package/templates/101/sui-template/packages/contracts/src/counter/Published.toml +0 -9
- package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/errors.move +0 -12
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/errors.move +0 -140
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_config.move +0 -186
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_state.move +0 -306
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_metadata.move +0 -396
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dubhe_config.move +0 -246
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/dapp_store.move +0 -29
- package/templates/101/sui-template/packages/contracts/src/dubhe/sources/systems/session_system.move +0 -44
- package/templates/contract/sui-template/src/dubhe/sources/codegen/errors.move +0 -140
- package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dapp_fee_config.move +0 -186
- package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dapp_fee_state.move +0 -306
- package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dapp_metadata.move +0 -396
- package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dubhe_config.move +0 -246
- package/templates/contract/sui-template/src/dubhe/sources/core/dapp_store.move +0 -29
- package/templates/contract/sui-template/src/dubhe/sources/systems/session_system.move +0 -44
- package/templates/nextjs/sui-template/packages/contracts/src/counter/Move.lock +0 -47
- package/templates/nextjs/sui-template/packages/contracts/src/counter/Published.toml +0 -9
- package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/errors.move +0 -12
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/errors.move +0 -140
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_config.move +0 -186
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_state.move +0 -306
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_metadata.move +0 -396
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dubhe_config.move +0 -246
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/dapp_store.move +0 -29
- package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/session_system.move +0 -44
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import { Transaction, Ed25519Keypair, Dubhe } from '@0xobelisk/sui-client';
|
|
5
|
+
import {
|
|
6
|
+
useCurrentAccount,
|
|
7
|
+
useCurrentWallet,
|
|
8
|
+
useSignAndExecuteTransaction
|
|
9
|
+
} from '@mysten/dapp-kit';
|
|
10
|
+
import { toast } from 'sonner';
|
|
11
|
+
import { useDubhe } from '@0xobelisk/react/sui';
|
|
12
|
+
|
|
13
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
// Constants
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
const SESSION_SECRET_KEY_STORAGE = 'dubhe_session_secret_key';
|
|
17
|
+
const MIST_PER_SUI = BigInt(1_000_000_000);
|
|
18
|
+
const MS_PER_HOUR = 3_600_000;
|
|
19
|
+
const SUI_CLOCK_OBJECT_ID = '0x6';
|
|
20
|
+
|
|
21
|
+
type NetworkType = 'testnet' | 'mainnet' | 'devnet' | 'localnet';
|
|
22
|
+
|
|
23
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
+
// Props
|
|
25
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
26
|
+
interface ProxyCardProps {
|
|
27
|
+
/** The UserStorage object ID for the connected owner account. */
|
|
28
|
+
userStorageId: string | null;
|
|
29
|
+
/** Called after a session is activated or deactivated so the parent can refresh fields. */
|
|
30
|
+
onSessionChanged?: () => void | Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
34
|
+
// Helper — format epoch ms as a human-readable date string
|
|
35
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
36
|
+
function formatExpiry(ms: number): string {
|
|
37
|
+
return new Date(ms).toLocaleString();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
41
|
+
// ProxyCard component
|
|
42
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
43
|
+
export default function ProxyCard({ userStorageId, onSessionChanged }: ProxyCardProps) {
|
|
44
|
+
const { mutateAsync: signAndExecuteTransaction } = useSignAndExecuteTransaction();
|
|
45
|
+
const { connectionStatus } = useCurrentWallet();
|
|
46
|
+
const currentAccount = useCurrentAccount();
|
|
47
|
+
const ownerAddress = currentAccount?.address;
|
|
48
|
+
const { contract, graphqlClient, ecsWorld, network, packageId, dappHubId, frameworkPackageId } =
|
|
49
|
+
useDubhe();
|
|
50
|
+
|
|
51
|
+
// ── Session wallet state ─────────────────────────────────────────────────
|
|
52
|
+
const [sessionSecretKey, setSessionSecretKey] = useState<string | null>(null);
|
|
53
|
+
const [sessionAddress, setSessionAddress] = useState<string | null>(null);
|
|
54
|
+
const [sessionBalance, setSessionBalance] = useState<string>('0');
|
|
55
|
+
|
|
56
|
+
// ── Session binding state read from UserStorage fields ───────────────────
|
|
57
|
+
const [sessionKey, setSessionKey] = useState<string>('');
|
|
58
|
+
const [sessionExpiresAt, setSessionExpiresAt] = useState<number>(0);
|
|
59
|
+
|
|
60
|
+
// ── Counter state ─────────────────────────────────────────────────────────
|
|
61
|
+
const [ownerCounterValue, setOwnerCounterValue] = useState<number | null>(null);
|
|
62
|
+
|
|
63
|
+
// ── UI state ──────────────────────────────────────────────────────────────
|
|
64
|
+
const [loadingAction, setLoadingAction] = useState<string | null>(null);
|
|
65
|
+
const [expiryHours, setExpiryHours] = useState<number>(24);
|
|
66
|
+
|
|
67
|
+
// ── Resolve framework package ID ─────────────────────────────────────────
|
|
68
|
+
const frameworkPkgId = useMemo<string | undefined>(() => {
|
|
69
|
+
if (frameworkPackageId) return frameworkPackageId;
|
|
70
|
+
try {
|
|
71
|
+
return Dubhe.getDefaultConfig(network as NetworkType).frameworkPackageId;
|
|
72
|
+
} catch {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
}, [frameworkPackageId, network]);
|
|
76
|
+
|
|
77
|
+
// ── Session Dubhe client (signed with session wallet's secret key) ────────
|
|
78
|
+
const sessionDubhe = useMemo<Dubhe | null>(() => {
|
|
79
|
+
if (!sessionSecretKey || !frameworkPkgId) return null;
|
|
80
|
+
return new Dubhe({
|
|
81
|
+
networkType: network as NetworkType,
|
|
82
|
+
packageId,
|
|
83
|
+
frameworkPackageId: frameworkPkgId,
|
|
84
|
+
secretKey: sessionSecretKey
|
|
85
|
+
});
|
|
86
|
+
}, [sessionSecretKey, frameworkPkgId, network, packageId]);
|
|
87
|
+
|
|
88
|
+
// ── Load session secret key from localStorage on mount ───────────────────
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
if (typeof window === 'undefined') return;
|
|
91
|
+
const stored = localStorage.getItem(SESSION_SECRET_KEY_STORAGE);
|
|
92
|
+
if (stored) {
|
|
93
|
+
try {
|
|
94
|
+
const kp = Ed25519Keypair.fromSecretKey(stored);
|
|
95
|
+
setSessionSecretKey(stored);
|
|
96
|
+
setSessionAddress(kp.getPublicKey().toSuiAddress());
|
|
97
|
+
} catch {
|
|
98
|
+
localStorage.removeItem(SESSION_SECRET_KEY_STORAGE);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}, []);
|
|
102
|
+
|
|
103
|
+
// ── Sync session status from UserStorage fields ───────────────────────────
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!userStorageId) {
|
|
106
|
+
setSessionKey('');
|
|
107
|
+
setSessionExpiresAt(0);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
contract
|
|
111
|
+
.getUserStorageFields(userStorageId)
|
|
112
|
+
.then((f) => {
|
|
113
|
+
setSessionKey(f.session_key ?? '');
|
|
114
|
+
setSessionExpiresAt(Number(f.session_expires_at));
|
|
115
|
+
})
|
|
116
|
+
.catch(console.error);
|
|
117
|
+
}, [userStorageId]);
|
|
118
|
+
|
|
119
|
+
// ── Auto-refresh balance when session address changes ─────────────────────
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (sessionAddress) refreshSessionBalance(sessionAddress);
|
|
122
|
+
}, [sessionAddress]);
|
|
123
|
+
|
|
124
|
+
// ── Subscribe to counter1 changes for the owner address ──────────────────
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (!ownerAddress || !ecsWorld) return;
|
|
127
|
+
|
|
128
|
+
const subscription = ecsWorld.onEntityComponent<any>('counter1', ownerAddress).subscribe({
|
|
129
|
+
next: (result: any) => {
|
|
130
|
+
if (result && result.entityId === ownerAddress) {
|
|
131
|
+
const data = result.data as any;
|
|
132
|
+
if (data?.value !== undefined) {
|
|
133
|
+
setOwnerCounterValue(data.value);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
error: (err: any) => {
|
|
138
|
+
console.error('ECS counter1 subscription error:', err);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
return () => {
|
|
143
|
+
subscription.unsubscribe();
|
|
144
|
+
};
|
|
145
|
+
}, [ownerAddress, ecsWorld]);
|
|
146
|
+
|
|
147
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
148
|
+
// Helpers
|
|
149
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
/** Fetch and store the session account's SUI balance. */
|
|
152
|
+
async function refreshSessionBalance(address: string) {
|
|
153
|
+
try {
|
|
154
|
+
const bal = await contract.balanceOf(address);
|
|
155
|
+
setSessionBalance((Number(bal.totalBalance) / 1_000_000_000).toFixed(4));
|
|
156
|
+
} catch {
|
|
157
|
+
setSessionBalance('0');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Re-read session_key / session_expires_at from UserStorage. */
|
|
162
|
+
async function refreshSessionStatus() {
|
|
163
|
+
if (!userStorageId) return;
|
|
164
|
+
try {
|
|
165
|
+
const f = await contract.getUserStorageFields(userStorageId);
|
|
166
|
+
setSessionKey(f.session_key ?? '');
|
|
167
|
+
setSessionExpiresAt(Number(f.session_expires_at));
|
|
168
|
+
} catch (err) {
|
|
169
|
+
console.error('Failed to refresh session status:', err);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
174
|
+
// Actions
|
|
175
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
176
|
+
|
|
177
|
+
/** Generate a new Ed25519 keypair and cache the secret key in localStorage. */
|
|
178
|
+
function generateSessionAccount() {
|
|
179
|
+
const kp = Ed25519Keypair.generate();
|
|
180
|
+
const sk = kp.getSecretKey();
|
|
181
|
+
const addr = kp.getPublicKey().toSuiAddress();
|
|
182
|
+
localStorage.setItem(SESSION_SECRET_KEY_STORAGE, sk);
|
|
183
|
+
setSessionSecretKey(sk);
|
|
184
|
+
setSessionAddress(addr);
|
|
185
|
+
setSessionBalance('0');
|
|
186
|
+
setSessionKey('');
|
|
187
|
+
setSessionExpiresAt(0);
|
|
188
|
+
toast.success('New session account generated and saved to localStorage');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Clear the stored session keypair from localStorage. */
|
|
192
|
+
function clearSessionAccount() {
|
|
193
|
+
localStorage.removeItem(SESSION_SECRET_KEY_STORAGE);
|
|
194
|
+
setSessionSecretKey(null);
|
|
195
|
+
setSessionAddress(null);
|
|
196
|
+
setSessionBalance('0');
|
|
197
|
+
setSessionKey('');
|
|
198
|
+
setSessionExpiresAt(0);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Transfer 1 SUI from the connected wallet to the session address.
|
|
203
|
+
* The session wallet needs gas to submit transactions directly.
|
|
204
|
+
*/
|
|
205
|
+
async function fundSession() {
|
|
206
|
+
if (!ownerAddress || !sessionAddress) return;
|
|
207
|
+
setLoadingAction('fund');
|
|
208
|
+
try {
|
|
209
|
+
const tx = new Transaction();
|
|
210
|
+
tx.transferObjects([tx.splitCoins(tx.gas, [MIST_PER_SUI])], sessionAddress);
|
|
211
|
+
await signAndExecuteTransaction(
|
|
212
|
+
{ transaction: tx.serialize(), chain: `sui:${network}` },
|
|
213
|
+
{
|
|
214
|
+
onSuccess: async () => {
|
|
215
|
+
setTimeout(() => refreshSessionBalance(sessionAddress), 1500);
|
|
216
|
+
toast.success('1 SUI transferred to session account');
|
|
217
|
+
},
|
|
218
|
+
onError: (err) => {
|
|
219
|
+
console.error('Fund failed:', err);
|
|
220
|
+
toast.error('Transfer failed');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
} catch (err) {
|
|
225
|
+
console.error('Fund session error:', err);
|
|
226
|
+
toast.error('Transfer failed');
|
|
227
|
+
} finally {
|
|
228
|
+
setLoadingAction(null);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Activate a session on the owner's UserStorage.
|
|
234
|
+
*
|
|
235
|
+
* Flow:
|
|
236
|
+
* 1. Build a PTB calling `dapp_system::activate_session<DappKey>(
|
|
237
|
+
* user_storage, session_wallet, duration_ms, clock)`.
|
|
238
|
+
* 2. Owner's wallet signs and submits — no wallet pop-up for the session.
|
|
239
|
+
*/
|
|
240
|
+
async function setupSession() {
|
|
241
|
+
if (!ownerAddress || !sessionAddress || !userStorageId || !frameworkPkgId) return;
|
|
242
|
+
setLoadingAction('setup');
|
|
243
|
+
try {
|
|
244
|
+
const durationMs = expiryHours * MS_PER_HOUR;
|
|
245
|
+
const tx = new Transaction();
|
|
246
|
+
tx.moveCall({
|
|
247
|
+
target: `${frameworkPkgId}::dapp_system::activate_session`,
|
|
248
|
+
typeArguments: [contract.getDappKey()],
|
|
249
|
+
arguments: [
|
|
250
|
+
tx.object(userStorageId),
|
|
251
|
+
tx.pure.address(sessionAddress),
|
|
252
|
+
tx.pure.u64(durationMs),
|
|
253
|
+
tx.object(SUI_CLOCK_OBJECT_ID)
|
|
254
|
+
]
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
await signAndExecuteTransaction(
|
|
258
|
+
{ transaction: tx.serialize(), chain: `sui:${network}` },
|
|
259
|
+
{
|
|
260
|
+
onSuccess: async () => {
|
|
261
|
+
setTimeout(async () => {
|
|
262
|
+
await refreshSessionStatus();
|
|
263
|
+
if (onSessionChanged) await onSessionChanged();
|
|
264
|
+
toast.success('Session activated successfully');
|
|
265
|
+
}, 1500);
|
|
266
|
+
},
|
|
267
|
+
onError: (err) => {
|
|
268
|
+
console.error('activateSession failed:', err);
|
|
269
|
+
toast.error('Failed to activate session');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
} catch (err) {
|
|
274
|
+
console.error('Setup session error:', err);
|
|
275
|
+
toast.error(`Failed to activate session: ${(err as Error).message}`);
|
|
276
|
+
} finally {
|
|
277
|
+
setLoadingAction(null);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Deactivate the session on the owner's UserStorage.
|
|
283
|
+
* Owner's wallet signs. (The session wallet or anyone can also call once expired.)
|
|
284
|
+
*/
|
|
285
|
+
async function removeSession() {
|
|
286
|
+
if (!ownerAddress || !userStorageId || !frameworkPkgId) return;
|
|
287
|
+
setLoadingAction('remove');
|
|
288
|
+
try {
|
|
289
|
+
const tx = new Transaction();
|
|
290
|
+
tx.moveCall({
|
|
291
|
+
target: `${frameworkPkgId}::dapp_system::deactivate_session`,
|
|
292
|
+
typeArguments: [contract.getDappKey()],
|
|
293
|
+
arguments: [tx.object(userStorageId)]
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
await signAndExecuteTransaction(
|
|
297
|
+
{ transaction: tx.serialize(), chain: `sui:${network}` },
|
|
298
|
+
{
|
|
299
|
+
onSuccess: async () => {
|
|
300
|
+
setTimeout(async () => {
|
|
301
|
+
setSessionKey('');
|
|
302
|
+
setSessionExpiresAt(0);
|
|
303
|
+
if (onSessionChanged) await onSessionChanged();
|
|
304
|
+
toast.success('Session deactivated');
|
|
305
|
+
}, 1500);
|
|
306
|
+
},
|
|
307
|
+
onError: (err) => {
|
|
308
|
+
console.error('deactivateSession failed:', err);
|
|
309
|
+
toast.error('Failed to deactivate session');
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
);
|
|
313
|
+
} catch (err) {
|
|
314
|
+
console.error('Remove session error:', err);
|
|
315
|
+
toast.error(`Failed to deactivate session: ${(err as Error).message}`);
|
|
316
|
+
} finally {
|
|
317
|
+
setLoadingAction(null);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Increment the counter using the SESSION account — no wallet confirmation.
|
|
323
|
+
*
|
|
324
|
+
* Because the session wallet calls `counter_system::inc`, `ensure_origin` inside
|
|
325
|
+
* the Move contract resolves to the OWNER's address. So the counter is stored
|
|
326
|
+
* under the owner's address, not the session wallet's.
|
|
327
|
+
*/
|
|
328
|
+
async function incrementCounterViaSession() {
|
|
329
|
+
if (!sessionDubhe || !userStorageId) return;
|
|
330
|
+
setLoadingAction('counter');
|
|
331
|
+
try {
|
|
332
|
+
const tx = new Transaction();
|
|
333
|
+
// counter_system::inc(user_storage: &mut UserStorage, number: u32, ctx)
|
|
334
|
+
await contract.tx.counter_system.inc({
|
|
335
|
+
tx,
|
|
336
|
+
params: [tx.object(userStorageId), tx.pure.u32(1)],
|
|
337
|
+
isRaw: true
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Submit signed by the SESSION keypair — no wallet pop-up
|
|
341
|
+
const result = await sessionDubhe.signAndSendTxn({ tx });
|
|
342
|
+
console.log('Counter inc via session:', result.digest);
|
|
343
|
+
toast.success('Counter incremented via session (no wallet confirmation needed)', {
|
|
344
|
+
description: `Tx: ${result.digest.slice(0, 16)}...`,
|
|
345
|
+
action: {
|
|
346
|
+
label: 'Explorer',
|
|
347
|
+
onClick: () => window.open(contract.getTxExplorerUrl(result.digest), '_blank')
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
setTimeout(() => refreshOwnerCounterValue(), 2000);
|
|
351
|
+
} catch (err) {
|
|
352
|
+
console.error('Session counter increment failed:', err);
|
|
353
|
+
toast.error(`Session counter increment failed: ${(err as Error).message}`);
|
|
354
|
+
} finally {
|
|
355
|
+
setLoadingAction(null);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** Query the counter value stored under the OWNER's address. */
|
|
360
|
+
async function refreshOwnerCounterValue() {
|
|
361
|
+
if (!ownerAddress || !graphqlClient) return;
|
|
362
|
+
try {
|
|
363
|
+
const result = await graphqlClient.getTableByCondition('counter1', {
|
|
364
|
+
entityId: ownerAddress
|
|
365
|
+
});
|
|
366
|
+
if (result) {
|
|
367
|
+
setOwnerCounterValue(result.value ?? null);
|
|
368
|
+
} else {
|
|
369
|
+
setOwnerCounterValue(null);
|
|
370
|
+
}
|
|
371
|
+
} catch (err) {
|
|
372
|
+
console.log('Counter value not set yet or query failed:', err);
|
|
373
|
+
setOwnerCounterValue(null);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
378
|
+
// Derived state
|
|
379
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* A session is "active" when:
|
|
383
|
+
* - session_key matches the current session wallet address, AND
|
|
384
|
+
* - session_expires_at is in the future.
|
|
385
|
+
*/
|
|
386
|
+
const isSessionActive =
|
|
387
|
+
sessionAddress !== null &&
|
|
388
|
+
sessionKey.toLowerCase() === sessionAddress.toLowerCase() &&
|
|
389
|
+
sessionExpiresAt > Date.now();
|
|
390
|
+
|
|
391
|
+
const hasSessionSet = sessionKey !== '' && sessionKey !== '0x0';
|
|
392
|
+
const isLoading = (action: string) => loadingAction === action;
|
|
393
|
+
const connected = connectionStatus === 'connected';
|
|
394
|
+
|
|
395
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
396
|
+
// Render
|
|
397
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
398
|
+
if (!connected) return null;
|
|
399
|
+
|
|
400
|
+
return (
|
|
401
|
+
<div className="bg-white rounded-xl shadow-md p-6 mt-8">
|
|
402
|
+
{/* Header */}
|
|
403
|
+
<div className="flex items-center gap-3 mb-6">
|
|
404
|
+
<div className="inline-flex items-center justify-center w-12 h-12 bg-amber-100 rounded-full">
|
|
405
|
+
<span className="text-2xl">🔑</span>
|
|
406
|
+
</div>
|
|
407
|
+
<div>
|
|
408
|
+
<h2 className="text-2xl font-bold text-amber-700">Session Wallet Demo</h2>
|
|
409
|
+
<p className="text-sm text-gray-500">
|
|
410
|
+
Let a burner wallet transact on behalf of your main account — no wallet pop-ups.
|
|
411
|
+
</p>
|
|
412
|
+
</div>
|
|
413
|
+
</div>
|
|
414
|
+
|
|
415
|
+
{/* Framework package not configured warning */}
|
|
416
|
+
{!frameworkPkgId && (
|
|
417
|
+
<div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700">
|
|
418
|
+
<strong>Framework package ID not configured.</strong> Set{' '}
|
|
419
|
+
<code className="bg-red-100 px-1 rounded">FrameworkPackageId</code> in{' '}
|
|
420
|
+
<code className="bg-red-100 px-1 rounded">packages/contracts/deployment.ts</code> after
|
|
421
|
+
deploying the dubhe framework locally (or use testnet where it is auto-resolved).
|
|
422
|
+
</div>
|
|
423
|
+
)}
|
|
424
|
+
|
|
425
|
+
{/* UserStorage not ready warning */}
|
|
426
|
+
{!userStorageId && (
|
|
427
|
+
<div className="mb-6 p-4 bg-amber-50 border border-amber-200 rounded-lg text-sm text-amber-700">
|
|
428
|
+
<strong>UserStorage required.</strong> Register a UserStorage on the main page first
|
|
429
|
+
before activating a session.
|
|
430
|
+
</div>
|
|
431
|
+
)}
|
|
432
|
+
|
|
433
|
+
<div className="space-y-6">
|
|
434
|
+
{/* ── Section 1: Session Account ───────────────────────────────── */}
|
|
435
|
+
<div className="border border-amber-200 rounded-xl p-5 bg-amber-50">
|
|
436
|
+
<h3 className="text-lg font-semibold text-amber-800 mb-4">1. Session Account</h3>
|
|
437
|
+
|
|
438
|
+
{!sessionAddress ? (
|
|
439
|
+
<div className="text-center py-4">
|
|
440
|
+
<p className="text-gray-500 mb-4 text-sm">
|
|
441
|
+
Generate a burner keypair. The secret key is saved to{' '}
|
|
442
|
+
<code className="bg-gray-100 px-1 rounded text-xs">localStorage</code> so you can
|
|
443
|
+
reload the page.
|
|
444
|
+
</p>
|
|
445
|
+
<button
|
|
446
|
+
type="button"
|
|
447
|
+
onClick={generateSessionAccount}
|
|
448
|
+
className="px-6 py-2 bg-amber-600 text-white rounded-lg hover:bg-amber-700 font-medium"
|
|
449
|
+
>
|
|
450
|
+
Generate Session Account
|
|
451
|
+
</button>
|
|
452
|
+
</div>
|
|
453
|
+
) : (
|
|
454
|
+
<div className="space-y-3">
|
|
455
|
+
{/* Address */}
|
|
456
|
+
<div className="bg-white rounded-lg p-3 border border-amber-200">
|
|
457
|
+
<p className="text-xs text-gray-500 mb-1">Session address</p>
|
|
458
|
+
<p className="font-mono text-sm text-gray-800 break-all">{sessionAddress}</p>
|
|
459
|
+
</div>
|
|
460
|
+
|
|
461
|
+
{/* Balance + fund */}
|
|
462
|
+
<div className="flex items-center justify-between gap-4">
|
|
463
|
+
<div className="flex items-center gap-2">
|
|
464
|
+
<span className="text-sm text-gray-600">Balance:</span>
|
|
465
|
+
<span
|
|
466
|
+
className={`font-semibold text-sm ${
|
|
467
|
+
Number(sessionBalance) === 0 ? 'text-red-500' : 'text-green-600'
|
|
468
|
+
}`}
|
|
469
|
+
>
|
|
470
|
+
{sessionBalance} SUI
|
|
471
|
+
</span>
|
|
472
|
+
</div>
|
|
473
|
+
<div className="flex gap-2">
|
|
474
|
+
<button
|
|
475
|
+
type="button"
|
|
476
|
+
onClick={fundSession}
|
|
477
|
+
disabled={isLoading('fund')}
|
|
478
|
+
className="px-4 py-1.5 bg-green-600 text-white text-sm rounded-lg hover:bg-green-700 disabled:opacity-50"
|
|
479
|
+
>
|
|
480
|
+
{isLoading('fund') ? 'Sending…' : 'Fund 1 SUI'}
|
|
481
|
+
</button>
|
|
482
|
+
<button
|
|
483
|
+
type="button"
|
|
484
|
+
onClick={() => sessionAddress && refreshSessionBalance(sessionAddress)}
|
|
485
|
+
className="px-4 py-1.5 border border-gray-300 text-gray-600 text-sm rounded-lg hover:bg-gray-50"
|
|
486
|
+
>
|
|
487
|
+
↻
|
|
488
|
+
</button>
|
|
489
|
+
</div>
|
|
490
|
+
</div>
|
|
491
|
+
|
|
492
|
+
{/* Regenerate / clear */}
|
|
493
|
+
<div className="flex gap-2 pt-1">
|
|
494
|
+
<button
|
|
495
|
+
type="button"
|
|
496
|
+
onClick={generateSessionAccount}
|
|
497
|
+
className="px-4 py-1.5 border border-amber-400 text-amber-700 text-sm rounded-lg hover:bg-amber-100"
|
|
498
|
+
>
|
|
499
|
+
Regenerate
|
|
500
|
+
</button>
|
|
501
|
+
<button
|
|
502
|
+
type="button"
|
|
503
|
+
onClick={clearSessionAccount}
|
|
504
|
+
className="px-4 py-1.5 border border-red-300 text-red-600 text-sm rounded-lg hover:bg-red-50"
|
|
505
|
+
>
|
|
506
|
+
Clear
|
|
507
|
+
</button>
|
|
508
|
+
</div>
|
|
509
|
+
</div>
|
|
510
|
+
)}
|
|
511
|
+
</div>
|
|
512
|
+
|
|
513
|
+
{/* ── Section 2: Session Activation ────────────────────────────── */}
|
|
514
|
+
{sessionAddress && userStorageId && (
|
|
515
|
+
<div className="border border-amber-200 rounded-xl p-5">
|
|
516
|
+
<div className="flex items-center justify-between mb-4">
|
|
517
|
+
<h3 className="text-lg font-semibold text-amber-800">2. Session Activation</h3>
|
|
518
|
+
|
|
519
|
+
{/* Status badge */}
|
|
520
|
+
{isSessionActive ? (
|
|
521
|
+
<span className="px-3 py-1 bg-green-100 text-green-700 text-xs font-semibold rounded-full">
|
|
522
|
+
✓ Active
|
|
523
|
+
</span>
|
|
524
|
+
) : hasSessionSet ? (
|
|
525
|
+
<span className="px-3 py-1 bg-red-100 text-red-700 text-xs font-semibold rounded-full">
|
|
526
|
+
✗ Expired
|
|
527
|
+
</span>
|
|
528
|
+
) : (
|
|
529
|
+
<span className="px-3 py-1 bg-gray-100 text-gray-500 text-xs font-semibold rounded-full">
|
|
530
|
+
Not Set
|
|
531
|
+
</span>
|
|
532
|
+
)}
|
|
533
|
+
</div>
|
|
534
|
+
|
|
535
|
+
{/* Session details */}
|
|
536
|
+
{hasSessionSet && (
|
|
537
|
+
<div className="mb-4 bg-gray-50 rounded-lg p-3 text-sm space-y-1">
|
|
538
|
+
<p>
|
|
539
|
+
<span className="text-gray-500">Session key:</span>{' '}
|
|
540
|
+
<span className="font-mono text-gray-800">
|
|
541
|
+
{sessionKey.slice(0, 10)}…{sessionKey.slice(-6)}
|
|
542
|
+
</span>
|
|
543
|
+
</p>
|
|
544
|
+
<p>
|
|
545
|
+
<span className="text-gray-500">Expires at:</span>{' '}
|
|
546
|
+
<span
|
|
547
|
+
className={sessionExpiresAt > Date.now() ? 'text-green-700' : 'text-red-600'}
|
|
548
|
+
>
|
|
549
|
+
{formatExpiry(sessionExpiresAt)}
|
|
550
|
+
</span>
|
|
551
|
+
</p>
|
|
552
|
+
</div>
|
|
553
|
+
)}
|
|
554
|
+
|
|
555
|
+
{/* Duration selector + actions */}
|
|
556
|
+
<div className="space-y-3">
|
|
557
|
+
<div>
|
|
558
|
+
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
559
|
+
Session duration
|
|
560
|
+
</label>
|
|
561
|
+
<select
|
|
562
|
+
value={expiryHours}
|
|
563
|
+
onChange={(e) => setExpiryHours(Number(e.target.value))}
|
|
564
|
+
className="w-full px-3 py-2 border border-gray-300 rounded-md text-sm text-gray-900 bg-white focus:outline-none focus:ring-2 focus:ring-amber-400"
|
|
565
|
+
>
|
|
566
|
+
<option value={1}>1 hour</option>
|
|
567
|
+
<option value={6}>6 hours</option>
|
|
568
|
+
<option value={24}>1 day</option>
|
|
569
|
+
<option value={72}>3 days</option>
|
|
570
|
+
<option value={168}>7 days (max)</option>
|
|
571
|
+
</select>
|
|
572
|
+
</div>
|
|
573
|
+
|
|
574
|
+
<div className="flex flex-wrap gap-2">
|
|
575
|
+
{!frameworkPkgId ? (
|
|
576
|
+
<span className="text-xs text-gray-400 self-center">
|
|
577
|
+
Framework package ID required
|
|
578
|
+
</span>
|
|
579
|
+
) : (
|
|
580
|
+
<>
|
|
581
|
+
<button
|
|
582
|
+
type="button"
|
|
583
|
+
onClick={setupSession}
|
|
584
|
+
disabled={!!loadingAction}
|
|
585
|
+
className="px-4 py-2 bg-amber-600 text-white text-sm rounded-lg hover:bg-amber-700 disabled:opacity-50 font-medium"
|
|
586
|
+
>
|
|
587
|
+
{isLoading('setup')
|
|
588
|
+
? 'Activating…'
|
|
589
|
+
: isSessionActive
|
|
590
|
+
? 'Re-activate Session'
|
|
591
|
+
: 'Activate Session'}
|
|
592
|
+
</button>
|
|
593
|
+
{hasSessionSet && (
|
|
594
|
+
<button
|
|
595
|
+
type="button"
|
|
596
|
+
onClick={removeSession}
|
|
597
|
+
disabled={!!loadingAction}
|
|
598
|
+
className="px-4 py-2 border border-red-400 text-red-600 text-sm rounded-lg hover:bg-red-50 disabled:opacity-50"
|
|
599
|
+
>
|
|
600
|
+
{isLoading('remove') ? 'Deactivating…' : 'Deactivate Session'}
|
|
601
|
+
</button>
|
|
602
|
+
)}
|
|
603
|
+
<button
|
|
604
|
+
type="button"
|
|
605
|
+
onClick={refreshSessionStatus}
|
|
606
|
+
disabled={!!loadingAction}
|
|
607
|
+
className="px-4 py-2 border border-gray-300 text-gray-600 text-sm rounded-lg hover:bg-gray-50 disabled:opacity-50"
|
|
608
|
+
>
|
|
609
|
+
Refresh Status
|
|
610
|
+
</button>
|
|
611
|
+
</>
|
|
612
|
+
)}
|
|
613
|
+
</div>
|
|
614
|
+
</div>
|
|
615
|
+
</div>
|
|
616
|
+
)}
|
|
617
|
+
|
|
618
|
+
{/* ── Section 3: Counter via Session ──────────────────────────── */}
|
|
619
|
+
{isSessionActive && (
|
|
620
|
+
<div className="border border-violet-200 rounded-xl p-5 bg-violet-50">
|
|
621
|
+
<h3 className="text-lg font-semibold text-violet-800 mb-1">3. Counter via Session</h3>
|
|
622
|
+
<p className="text-sm text-gray-500 mb-4">
|
|
623
|
+
The session wallet submits the transaction directly — no wallet pop-up. The Move
|
|
624
|
+
contract's{' '}
|
|
625
|
+
<code className="bg-violet-100 text-violet-700 px-1 rounded text-xs">
|
|
626
|
+
ensure_origin
|
|
627
|
+
</code>{' '}
|
|
628
|
+
resolves the sender to your main account via the UserStorage session key.
|
|
629
|
+
</p>
|
|
630
|
+
|
|
631
|
+
{/* Owner counter value */}
|
|
632
|
+
<div className="flex items-center justify-between mb-4 bg-white rounded-lg p-4 border border-violet-200">
|
|
633
|
+
<div>
|
|
634
|
+
<p className="text-xs text-gray-500">Counter value (under owner's address)</p>
|
|
635
|
+
<p className="text-3xl font-bold text-violet-700">{ownerCounterValue ?? '—'}</p>
|
|
636
|
+
</div>
|
|
637
|
+
<button
|
|
638
|
+
type="button"
|
|
639
|
+
onClick={refreshOwnerCounterValue}
|
|
640
|
+
className="text-sm px-3 py-1.5 border border-violet-300 text-violet-600 rounded-lg hover:bg-violet-100"
|
|
641
|
+
>
|
|
642
|
+
↻ Refresh
|
|
643
|
+
</button>
|
|
644
|
+
</div>
|
|
645
|
+
|
|
646
|
+
<div className="flex flex-wrap gap-3">
|
|
647
|
+
<button
|
|
648
|
+
type="button"
|
|
649
|
+
onClick={incrementCounterViaSession}
|
|
650
|
+
disabled={isLoading('counter') || Number(sessionBalance) === 0}
|
|
651
|
+
className="px-6 py-2.5 bg-violet-600 text-white rounded-lg hover:bg-violet-700 disabled:opacity-50 font-medium text-sm"
|
|
652
|
+
>
|
|
653
|
+
{isLoading('counter') ? 'Sending…' : '🚀 Increment (via Session)'}
|
|
654
|
+
</button>
|
|
655
|
+
{Number(sessionBalance) === 0 && (
|
|
656
|
+
<p className="text-xs text-red-500 self-center">
|
|
657
|
+
Session wallet has no SUI — fund it first (section 1)
|
|
658
|
+
</p>
|
|
659
|
+
)}
|
|
660
|
+
</div>
|
|
661
|
+
|
|
662
|
+
{/* How it works info box */}
|
|
663
|
+
<div className="mt-4 p-3 bg-violet-100 rounded-lg text-xs text-violet-800 space-y-1">
|
|
664
|
+
<p>
|
|
665
|
+
<strong>How it works:</strong>
|
|
666
|
+
</p>
|
|
667
|
+
<p>
|
|
668
|
+
1. Owner activates a session key (this wallet address) on their{' '}
|
|
669
|
+
<code>UserStorage</code>.
|
|
670
|
+
</p>
|
|
671
|
+
<p>2. Session wallet signs and submits transactions with its own gas.</p>
|
|
672
|
+
<p>
|
|
673
|
+
3. On-chain, <code>ensure_origin</code> finds the session key in{' '}
|
|
674
|
+
<code>UserStorage</code> and returns your wallet address as the logical sender.
|
|
675
|
+
</p>
|
|
676
|
+
<p>4. The counter increments under your wallet address — not the session address.</p>
|
|
677
|
+
</div>
|
|
678
|
+
</div>
|
|
679
|
+
)}
|
|
680
|
+
</div>
|
|
681
|
+
</div>
|
|
682
|
+
);
|
|
683
|
+
}
|