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.
Files changed (361) 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 +8 -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 +8 -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/Move.toml +4 -0
  297. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/dapp_key.move +45 -31
  298. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/error.move +10 -0
  299. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/genesis.move +30 -13
  300. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/init_test.move +19 -14
  301. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/resources/counter1.move +30 -20
  302. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/resources/counter2.move +35 -24
  303. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/user_storage_init.move +26 -0
  304. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/scripts/deploy_hook.move +6 -10
  305. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/systems/counter.move +7 -20
  306. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/tests/counter.move +14 -27
  307. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/Move.lock +33 -30
  308. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/Move.toml +8 -3
  309. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/dapp_key.move +45 -31
  310. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/error.move +170 -0
  311. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/genesis.move +16 -13
  312. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/init_test.move +8 -14
  313. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/account_key.move +1 -3
  314. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/dapp_service.move +1776 -137
  315. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/data_key.move +1 -20
  316. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/events.move +864 -25
  317. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/scripts/deploy_hook.move +15 -16
  318. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/scripts/migrate.move +0 -3
  319. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/address_system.move +25 -17
  320. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/dapp_system.move +2802 -343
  321. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/utils.move +1 -1
  322. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/address.move +173 -55
  323. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/dapp_test.move +769 -0
  324. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/fee_test.move +2965 -0
  325. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/integration_test.move +303 -0
  326. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/listing_test.move +1422 -0
  327. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/scene_session_test.move +269 -0
  328. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/session_test.move +624 -0
  329. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/storage_test.move +700 -0
  330. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/typed_object_test.move +177 -0
  331. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/typed_scene_test.move +452 -0
  332. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/user_storage_test.move +160 -0
  333. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/utils/math.move +4 -3
  334. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/utils/type_info.move +2 -2
  335. package/templates/101/sui-template/packages/contracts/src/counter/Move.lock +0 -41
  336. package/templates/101/sui-template/packages/contracts/src/counter/Published.toml +0 -9
  337. package/templates/101/sui-template/packages/contracts/src/counter/sources/codegen/errors.move +0 -12
  338. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/errors.move +0 -140
  339. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_config.move +0 -186
  340. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_state.move +0 -306
  341. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_metadata.move +0 -396
  342. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dubhe_config.move +0 -246
  343. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/dapp_store.move +0 -29
  344. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/systems/session_system.move +0 -44
  345. package/templates/contract/sui-template/src/dubhe/sources/codegen/errors.move +0 -140
  346. package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dapp_fee_config.move +0 -186
  347. package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dapp_fee_state.move +0 -306
  348. package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dapp_metadata.move +0 -396
  349. package/templates/contract/sui-template/src/dubhe/sources/codegen/resources/dubhe_config.move +0 -246
  350. package/templates/contract/sui-template/src/dubhe/sources/core/dapp_store.move +0 -29
  351. package/templates/contract/sui-template/src/dubhe/sources/systems/session_system.move +0 -44
  352. package/templates/nextjs/sui-template/packages/contracts/src/counter/Move.lock +0 -47
  353. package/templates/nextjs/sui-template/packages/contracts/src/counter/Published.toml +0 -9
  354. package/templates/nextjs/sui-template/packages/contracts/src/counter/sources/codegen/errors.move +0 -12
  355. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/errors.move +0 -140
  356. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_config.move +0 -186
  357. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_fee_state.move +0 -306
  358. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dapp_metadata.move +0 -396
  359. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/resources/dubhe_config.move +0 -246
  360. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/dapp_store.move +0 -29
  361. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/session_system.move +0 -44
@@ -0,0 +1,2 @@
1
+ packages:
2
+ - packages/*
@@ -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&apos;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&apos;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
+ }