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