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,226 @@
1
+ /**
2
+ * Scene discovery via the Dubhe indexer system tables.
3
+ *
4
+ * The indexer mirrors every SceneStorage / ScenePermit into Postgres
5
+ * (scene_storages / scene_storage_fields / scene_permits), exposed through
6
+ * GraphQL as dubheSceneStorages / dubheSceneStorageFields. The raw queries
7
+ * and BCS decoding helpers live in @0xobelisk/graphql-client; this module
8
+ * only keeps the card_duel domain decoding (DuelScene / BrawlScene).
9
+ */
10
+
11
+ import {
12
+ type DubheGraphqlClient,
13
+ decodeU8,
14
+ decodeU32,
15
+ decodeU64,
16
+ decodeAddress,
17
+ decodeVectorAddress,
18
+ ZERO_ADDRESS
19
+ } from '@0xobelisk/graphql-client';
20
+ import { DappKey } from 'contracts/deployment';
21
+
22
+ // ── Decoded scene types ───────────────────────────────────────────────────────
23
+
24
+ export interface DuelScene {
25
+ sceneId: string;
26
+ permitId: string;
27
+ challenger: string;
28
+ opponent: string;
29
+ stake: bigint;
30
+ state: number;
31
+ turnAddr: string;
32
+ round: number;
33
+ winner: string;
34
+ usedCardsA: string[];
35
+ usedCardsB: string[];
36
+ lastActionMs: bigint;
37
+ /** Escrowed pot (scene bag) */
38
+ gold: bigint;
39
+ }
40
+
41
+ export interface BrawlScene {
42
+ sceneId: string;
43
+ permitId: string;
44
+ host: string;
45
+ entryFee: bigint;
46
+ maxPlayers: number;
47
+ state: number;
48
+ round: number;
49
+ turnIndex: number;
50
+ players: string[];
51
+ alive: string[];
52
+ winner: string;
53
+ lastActionMs: bigint;
54
+ gold: bigint;
55
+ }
56
+
57
+ // ── Raw row fetching ──────────────────────────────────────────────────────────
58
+
59
+ interface SceneRow {
60
+ sceneId: string;
61
+ permitId: string;
62
+ }
63
+
64
+ type FieldMap = Record<string, string>; // fieldName -> raw hex
65
+
66
+ async function fetchSceneRows(
67
+ graphqlClient: DubheGraphqlClient,
68
+ sceneType: string
69
+ ): Promise<SceneRow[]> {
70
+ const result = await graphqlClient.getSceneStorages({
71
+ dappKey: DappKey,
72
+ sceneType,
73
+ isDestroyed: false,
74
+ first: 100
75
+ });
76
+ return (result?.edges ?? [])
77
+ .map((e) => ({
78
+ sceneId: e.node.sceneId,
79
+ permitId: e.node.authorizedPermitId ?? ''
80
+ }))
81
+ .filter((r) => r.permitId);
82
+ }
83
+
84
+ async function fetchFieldMaps(
85
+ graphqlClient: DubheGraphqlClient,
86
+ sceneIds: string[]
87
+ ): Promise<Record<string, FieldMap>> {
88
+ if (sceneIds.length === 0) return {};
89
+ const result = await graphqlClient.getSceneStorageFields({
90
+ dappKey: DappKey,
91
+ sceneIds,
92
+ isDeleted: false,
93
+ first: 1000
94
+ });
95
+ const maps: Record<string, FieldMap> = {};
96
+ (result?.edges ?? []).forEach((e) => {
97
+ const { sceneId, fieldName, fieldValueRaw } = e.node;
98
+ if (!maps[sceneId]) maps[sceneId] = {};
99
+ if (fieldValueRaw != null) maps[sceneId][fieldName] = fieldValueRaw;
100
+ });
101
+ return maps;
102
+ }
103
+
104
+ // ── Decoders ──────────────────────────────────────────────────────────────────
105
+
106
+ function decodeDuel(row: SceneRow, f: FieldMap): DuelScene | null {
107
+ if (!f.challenger || !f.state) return null;
108
+ return {
109
+ sceneId: row.sceneId,
110
+ permitId: row.permitId,
111
+ challenger: decodeAddress(f.challenger),
112
+ opponent: decodeAddress(f.opponent ?? ZERO_ADDRESS),
113
+ stake: f.stake ? decodeU64(f.stake) : 0n,
114
+ state: decodeU8(f.state),
115
+ turnAddr: f.turn_addr ? decodeAddress(f.turn_addr) : ZERO_ADDRESS,
116
+ round: f.round ? decodeU32(f.round) : 0,
117
+ winner: f.winner ? decodeAddress(f.winner) : ZERO_ADDRESS,
118
+ usedCardsA: f.used_cards_a ? decodeVectorAddress(f.used_cards_a) : [],
119
+ usedCardsB: f.used_cards_b ? decodeVectorAddress(f.used_cards_b) : [],
120
+ lastActionMs: f.last_action_ms ? decodeU64(f.last_action_ms) : 0n,
121
+ gold: f.gold ? decodeU64(f.gold) : 0n
122
+ };
123
+ }
124
+
125
+ function decodeBrawl(row: SceneRow, f: FieldMap): BrawlScene | null {
126
+ if (!f.host || !f.state) return null;
127
+ return {
128
+ sceneId: row.sceneId,
129
+ permitId: row.permitId,
130
+ host: decodeAddress(f.host),
131
+ entryFee: f.entry_fee ? decodeU64(f.entry_fee) : 0n,
132
+ maxPlayers: f.max_players ? Number(decodeU64(f.max_players)) : 0,
133
+ state: decodeU8(f.state),
134
+ round: f.round ? decodeU32(f.round) : 0,
135
+ turnIndex: f.turn_index ? Number(decodeU64(f.turn_index)) : 0,
136
+ players: f.players ? decodeVectorAddress(f.players) : [],
137
+ alive: f.alive ? decodeVectorAddress(f.alive) : [],
138
+ winner: f.winner ? decodeAddress(f.winner) : ZERO_ADDRESS,
139
+ lastActionMs: f.last_action_ms ? decodeU64(f.last_action_ms) : 0n,
140
+ gold: f.gold ? decodeU64(f.gold) : 0n
141
+ };
142
+ }
143
+
144
+ // ── Public API ────────────────────────────────────────────────────────────────
145
+
146
+ export async function fetchDuels(graphqlClient: DubheGraphqlClient): Promise<DuelScene[]> {
147
+ const rows = await fetchSceneRows(graphqlClient, 'duel');
148
+ const fieldMaps = await fetchFieldMaps(
149
+ graphqlClient,
150
+ rows.map((r) => r.sceneId)
151
+ );
152
+ return rows
153
+ .map((r) => decodeDuel(r, fieldMaps[r.sceneId] ?? {}))
154
+ .filter((d): d is DuelScene => d !== null);
155
+ }
156
+
157
+ export async function fetchBrawls(graphqlClient: DubheGraphqlClient): Promise<BrawlScene[]> {
158
+ const rows = await fetchSceneRows(graphqlClient, 'brawl');
159
+ const fieldMaps = await fetchFieldMaps(
160
+ graphqlClient,
161
+ rows.map((r) => r.sceneId)
162
+ );
163
+ return rows
164
+ .map((r) => decodeBrawl(r, fieldMaps[r.sceneId] ?? {}))
165
+ .filter((b): b is BrawlScene => b !== null);
166
+ }
167
+
168
+ async function fetchSceneRowById(
169
+ graphqlClient: DubheGraphqlClient,
170
+ sceneId: string
171
+ ): Promise<SceneRow | null> {
172
+ const result = await graphqlClient.getSceneStorages({
173
+ dappKey: DappKey,
174
+ sceneId,
175
+ first: 1
176
+ });
177
+ const node = result?.edges?.[0]?.node;
178
+ if (!node || !node.authorizedPermitId) return null;
179
+ return { sceneId, permitId: node.authorizedPermitId };
180
+ }
181
+
182
+ export async function fetchDuelById(
183
+ graphqlClient: DubheGraphqlClient,
184
+ sceneId: string
185
+ ): Promise<DuelScene | null> {
186
+ const row = await fetchSceneRowById(graphqlClient, sceneId);
187
+ if (!row) return null;
188
+ const fieldMaps = await fetchFieldMaps(graphqlClient, [sceneId]);
189
+ return decodeDuel(row, fieldMaps[sceneId] ?? {});
190
+ }
191
+
192
+ export async function fetchBrawlById(
193
+ graphqlClient: DubheGraphqlClient,
194
+ sceneId: string
195
+ ): Promise<BrawlScene | null> {
196
+ const row = await fetchSceneRowById(graphqlClient, sceneId);
197
+ if (!row) return null;
198
+ const fieldMaps = await fetchFieldMaps(graphqlClient, [sceneId]);
199
+ return decodeBrawl(row, fieldMaps[sceneId] ?? {});
200
+ }
201
+
202
+ /** Look up which scene type a scene id belongs to ('duel' | 'brawl' | null). */
203
+ export async function fetchSceneType(
204
+ graphqlClient: DubheGraphqlClient,
205
+ sceneId: string
206
+ ): Promise<string | null> {
207
+ const result = await graphqlClient.getSceneStorages({
208
+ dappKey: DappKey,
209
+ sceneId,
210
+ first: 1
211
+ });
212
+ return result?.edges?.[0]?.node?.sceneType ?? null;
213
+ }
214
+
215
+ /** Find the shared Arena ObjectStorage id (entity "main", created by deploy_hook). */
216
+ export async function fetchArenaObjectId(
217
+ graphqlClient: DubheGraphqlClient
218
+ ): Promise<string | null> {
219
+ const result = await graphqlClient.getObjectStorages({
220
+ dappKey: DappKey,
221
+ objectType: 'arena',
222
+ isDestroyed: false,
223
+ first: 1
224
+ });
225
+ return result?.edges?.[0]?.node?.objectId ?? null;
226
+ }
@@ -0,0 +1,418 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * Market — card NFTs (keyed + listable) and gold (fungible + listable)
5
+ * traded for SUI through the framework marketplace.
6
+ *
7
+ * Listing/buying requires the main wallet: the framework rejects session
8
+ * keys for marketplace record operations.
9
+ */
10
+
11
+ import { useState, useEffect, useCallback } from 'react';
12
+ import { toast } from 'sonner';
13
+ import { motion } from 'framer-motion';
14
+
15
+ import { useGame } from '../hooks/useGame';
16
+ import { GameShell } from '../components/GameShell';
17
+ import { CardView } from '../components/CardView';
18
+ import { IconGold } from '../components/icons';
19
+ import { decodeU8, decodeU32, decodeU64, parseRecordData } from '@0xobelisk/graphql-client';
20
+ import { KIND_NAME, RARITY_NAME, shortAddr, type CardData } from '../lib/game';
21
+ import { ZERO_ADDRESS } from '@0xobelisk/graphql-client';
22
+
23
+ interface CardListing {
24
+ id: string;
25
+ seller: string;
26
+ card: CardData;
27
+ price: bigint;
28
+ }
29
+
30
+ interface GoldListing {
31
+ id: string;
32
+ seller: string;
33
+ amount: bigint;
34
+ price: bigint;
35
+ }
36
+
37
+ export default function MarketPage() {
38
+ const game = useGame(10000);
39
+ const {
40
+ account,
41
+ graphqlClient,
42
+ player,
43
+ userStorageId,
44
+ hubId,
45
+ storageId,
46
+ pkg,
47
+ execTxWithMainWallet,
48
+ isLoading
49
+ } = game;
50
+
51
+ const [activeTab, setActiveTab] = useState<'cards' | 'gold'>('cards');
52
+ const [cardListings, setCardListings] = useState<CardListing[]>([]);
53
+ const [goldListings, setGoldListings] = useState<GoldListing[]>([]);
54
+ const [cardToList, setCardToList] = useState<string>('');
55
+ const [cardPrice, setCardPrice] = useState(0.1);
56
+ const [goldForm, setGoldForm] = useState({ amount: 100, price: 0.05 });
57
+
58
+ const inMatch = player.battle.matchId !== ZERO_ADDRESS;
59
+
60
+ // ── Fetch listings ──────────────────────────────────────────────────────────
61
+
62
+ const fetchListings = useCallback(async () => {
63
+ if (!graphqlClient) return;
64
+ try {
65
+ const result = await graphqlClient.getMarketplaceListings({ status: 'listed' });
66
+ const cards: CardListing[] = [];
67
+ const gold: GoldListing[] = [];
68
+ result.edges.forEach(({ node }: any) => {
69
+ const { recordType, listingId, seller, price, recordDataRaw } = node;
70
+ if (recordType === 'card') {
71
+ try {
72
+ // Non-key fields in schema order: kind(u8), power(u32), rarity(u8)
73
+ const raw = parseRecordData(recordDataRaw);
74
+ cards.push({
75
+ id: listingId,
76
+ seller,
77
+ price: BigInt(price),
78
+ card: {
79
+ cardId: listingId,
80
+ kind: decodeU8(raw[0] ?? '0x00'),
81
+ power: decodeU32(raw[1] ?? '0x00000000'),
82
+ rarity: decodeU8(raw[2] ?? '0x00')
83
+ }
84
+ });
85
+ } catch {
86
+ /* skip malformed */
87
+ }
88
+ } else if (recordType === 'gold') {
89
+ const raw = parseRecordData(recordDataRaw);
90
+ gold.push({
91
+ id: listingId,
92
+ seller,
93
+ amount: decodeU64(raw[0] ?? '0x00'),
94
+ price: BigInt(price)
95
+ });
96
+ }
97
+ });
98
+ setCardListings(cards);
99
+ setGoldListings(gold);
100
+ } catch (err) {
101
+ console.error('[market] fetch error:', err);
102
+ }
103
+ }, [graphqlClient]);
104
+
105
+ useEffect(() => {
106
+ fetchListings();
107
+ const interval = setInterval(fetchListings, 5000);
108
+ return () => clearInterval(interval);
109
+ }, [fetchListings]);
110
+
111
+ // ── Actions (main wallet only) ──────────────────────────────────────────────
112
+
113
+ const handleListCard = () => {
114
+ if (!cardToList) {
115
+ toast.error('Pick a card to list');
116
+ return;
117
+ }
118
+ execTxWithMainWallet(
119
+ (tx) => {
120
+ if (!userStorageId) throw new Error('UserStorage not found');
121
+ tx.moveCall({
122
+ target: `${pkg}::market_system::list_card`,
123
+ arguments: [
124
+ tx.object(storageId),
125
+ tx.object(userStorageId),
126
+ tx.pure.address(cardToList),
127
+ tx.pure.u64(BigInt(Math.round(cardPrice * 1e9)))
128
+ ]
129
+ });
130
+ },
131
+ 'Card listed on the market!',
132
+ () => setCardToList('')
133
+ );
134
+ };
135
+
136
+ const handleBuyCard = (l: CardListing) =>
137
+ execTxWithMainWallet((tx) => {
138
+ if (!userStorageId) throw new Error('UserStorage not found');
139
+ const [payment] = tx.splitCoins(tx.gas, [tx.pure.u64(l.price)]);
140
+ tx.moveCall({
141
+ target: `${pkg}::market_system::buy_card`,
142
+ arguments: [
143
+ tx.object(hubId),
144
+ tx.object(storageId),
145
+ tx.object(l.id),
146
+ tx.object(userStorageId),
147
+ payment
148
+ ]
149
+ });
150
+ }, 'Card purchased!');
151
+
152
+ const handleCancelCard = (l: CardListing) =>
153
+ execTxWithMainWallet((tx) => {
154
+ if (!userStorageId) throw new Error('UserStorage not found');
155
+ tx.moveCall({
156
+ target: `${pkg}::market_system::cancel_card_listing`,
157
+ arguments: [tx.object(l.id), tx.object(userStorageId)]
158
+ });
159
+ }, 'Listing cancelled — card returned.');
160
+
161
+ const handleListGold = () =>
162
+ execTxWithMainWallet((tx) => {
163
+ if (!userStorageId) throw new Error('UserStorage not found');
164
+ tx.moveCall({
165
+ target: `${pkg}::market_system::list_gold`,
166
+ arguments: [
167
+ tx.object(storageId),
168
+ tx.object(userStorageId),
169
+ tx.pure.u64(goldForm.amount),
170
+ tx.pure.u64(BigInt(Math.round(goldForm.price * 1e9)))
171
+ ]
172
+ });
173
+ }, `Listed ${goldForm.amount} gold!`);
174
+
175
+ const handleBuyGold = (l: GoldListing) =>
176
+ execTxWithMainWallet((tx) => {
177
+ if (!userStorageId) throw new Error('UserStorage not found');
178
+ const [payment] = tx.splitCoins(tx.gas, [tx.pure.u64(l.price)]);
179
+ tx.moveCall({
180
+ target: `${pkg}::market_system::buy_gold`,
181
+ arguments: [
182
+ tx.object(hubId),
183
+ tx.object(storageId),
184
+ tx.object(l.id),
185
+ tx.object(userStorageId),
186
+ payment
187
+ ]
188
+ });
189
+ }, `Bought ${l.amount} gold!`);
190
+
191
+ const handleCancelGold = (l: GoldListing) =>
192
+ execTxWithMainWallet((tx) => {
193
+ if (!userStorageId) throw new Error('UserStorage not found');
194
+ tx.moveCall({
195
+ target: `${pkg}::market_system::cancel_gold_listing`,
196
+ arguments: [tx.object(l.id), tx.object(userStorageId)]
197
+ });
198
+ }, 'Listing cancelled — gold returned.');
199
+
200
+ // Cards I own that are NOT in my battle deck are the safest to list.
201
+ const listableCards = player.cards;
202
+
203
+ return (
204
+ <GameShell game={game}>
205
+ <p className="mb-4 text-[11px] text-indigo-700 font-pixel px-1">
206
+ Market requires main wallet signature (session keys are not permitted for marketplace
207
+ operations). Prices are in SUI.
208
+ </p>
209
+
210
+ {/* Tabs */}
211
+ <div className="flex gap-1 mb-6">
212
+ {(['cards', 'gold'] as const).map((tab) => (
213
+ <button
214
+ key={tab}
215
+ onClick={() => setActiveTab(tab)}
216
+ className={`flex-1 py-2 text-xs font-pixel rounded-xl transition-colors border capitalize ${
217
+ activeTab === tab
218
+ ? 'bg-indigo-700 text-indigo-100 border-indigo-600'
219
+ : 'bg-indigo-950/40 text-indigo-500 border-indigo-800/40 hover:bg-indigo-900/40'
220
+ }`}
221
+ >
222
+ {tab === 'cards' ? 'Card NFTs' : 'Gold'}
223
+ </button>
224
+ ))}
225
+ </div>
226
+
227
+ {activeTab === 'cards' && (
228
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
229
+ {/* List form */}
230
+ <div className="bg-slate-950/80 border-2 border-indigo-800 rounded-2xl p-4 space-y-3 self-start">
231
+ <h2 className="font-pixel text-indigo-300 text-xs">List a Card</h2>
232
+ {inMatch && (
233
+ <p className="text-red-500 text-[10px]">Cannot list cards while in a match.</p>
234
+ )}
235
+ <select
236
+ value={cardToList}
237
+ onChange={(e) => setCardToList(e.target.value)}
238
+ className="w-full bg-indigo-950/40 border border-indigo-800 text-indigo-200 rounded-lg px-3 py-2 text-xs"
239
+ >
240
+ <option value="">Select a card…</option>
241
+ {listableCards.map((c) => (
242
+ <option key={c.cardId} value={c.cardId}>
243
+ {KIND_NAME[c.kind]} {c.power} ({RARITY_NAME[c.rarity]})
244
+ {player.deck.includes(c.cardId) ? ' — in deck' : ''}
245
+ </option>
246
+ ))}
247
+ </select>
248
+ <input
249
+ type="number"
250
+ min={0.001}
251
+ step={0.001}
252
+ value={cardPrice}
253
+ onChange={(e) => setCardPrice(Number(e.target.value))}
254
+ placeholder="Price (SUI)"
255
+ className="w-full bg-indigo-950/40 border border-indigo-800 text-indigo-200 rounded-lg px-3 py-2 text-xs"
256
+ />
257
+ <button
258
+ onClick={handleListCard}
259
+ disabled={isLoading || !cardToList || inMatch}
260
+ className="w-full py-2 bg-emerald-700 hover:bg-emerald-600 text-white text-xs font-pixel rounded-lg disabled:opacity-40 transition-colors"
261
+ >
262
+ List Card
263
+ </button>
264
+ <p className="text-indigo-800 text-[10px]">
265
+ Listing removes the card from your storage (and battle deck) until sold or cancelled.
266
+ </p>
267
+ </div>
268
+
269
+ {/* Listings */}
270
+ <div className="lg:col-span-2">
271
+ <h2 className="font-pixel text-indigo-400 text-xs mb-3">Card Listings</h2>
272
+ {cardListings.length === 0 ? (
273
+ <EmptyState text="No cards listed yet." />
274
+ ) : (
275
+ <div className="flex flex-wrap gap-4">
276
+ {cardListings.map((l) => {
277
+ const isMine = l.seller === account?.address;
278
+ return (
279
+ <motion.div
280
+ key={l.id}
281
+ initial={{ opacity: 0, scale: 0.97 }}
282
+ animate={{ opacity: 1, scale: 1 }}
283
+ className="flex flex-col items-center gap-2"
284
+ >
285
+ <CardView card={l.card} />
286
+ <p className="text-indigo-400 text-[10px] font-pixel">
287
+ {(Number(l.price) / 1e9).toFixed(4)} SUI
288
+ </p>
289
+ <p className="text-indigo-700 text-[9px]">
290
+ {shortAddr(l.seller)}
291
+ {isMine && <span className="text-amber-500"> (you)</span>}
292
+ </p>
293
+ {isMine ? (
294
+ <button
295
+ onClick={() => handleCancelCard(l)}
296
+ disabled={isLoading}
297
+ className="w-full py-1 bg-red-900/70 hover:bg-red-800 text-red-300 text-[10px] font-pixel rounded-lg disabled:opacity-40 transition-colors"
298
+ >
299
+ Cancel
300
+ </button>
301
+ ) : (
302
+ <button
303
+ onClick={() => handleBuyCard(l)}
304
+ disabled={isLoading}
305
+ className="w-full py-1 bg-indigo-700 hover:bg-indigo-600 text-white text-[10px] font-pixel rounded-lg disabled:opacity-40 transition-colors"
306
+ >
307
+ Buy
308
+ </button>
309
+ )}
310
+ </motion.div>
311
+ );
312
+ })}
313
+ </div>
314
+ )}
315
+ </div>
316
+ </div>
317
+ )}
318
+
319
+ {activeTab === 'gold' && (
320
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
321
+ <div className="bg-slate-950/80 border-2 border-amber-800/60 rounded-2xl p-4 space-y-3 self-start">
322
+ <h2 className="font-pixel text-amber-300 text-xs">List Gold</h2>
323
+ <div className="flex items-center gap-2">
324
+ <label className="text-amber-600 text-[10px] font-pixel w-16">Amount</label>
325
+ <input
326
+ type="number"
327
+ min={1}
328
+ value={goldForm.amount}
329
+ onChange={(e) => setGoldForm((f) => ({ ...f, amount: Number(e.target.value) }))}
330
+ className="flex-1 bg-amber-950/30 border border-amber-800/60 text-amber-200 rounded-lg px-3 py-2 text-xs"
331
+ />
332
+ </div>
333
+ <div className="flex items-center gap-2">
334
+ <label className="text-amber-600 text-[10px] font-pixel w-16">Price SUI</label>
335
+ <input
336
+ type="number"
337
+ min={0.001}
338
+ step={0.001}
339
+ value={goldForm.price}
340
+ onChange={(e) => setGoldForm((f) => ({ ...f, price: Number(e.target.value) }))}
341
+ className="flex-1 bg-amber-950/30 border border-amber-800/60 text-amber-200 rounded-lg px-3 py-2 text-xs"
342
+ />
343
+ </div>
344
+ <button
345
+ onClick={handleListGold}
346
+ disabled={isLoading || player.gold < BigInt(goldForm.amount)}
347
+ className="w-full py-2 bg-emerald-700 hover:bg-emerald-600 text-white text-xs font-pixel rounded-lg disabled:opacity-40 transition-colors"
348
+ >
349
+ List Gold (own {player.gold.toString()})
350
+ </button>
351
+ </div>
352
+
353
+ <div className="lg:col-span-2 space-y-2">
354
+ <h2 className="font-pixel text-amber-400 text-xs mb-3">Gold Listings</h2>
355
+ {goldListings.length === 0 ? (
356
+ <EmptyState text="No gold listed yet." />
357
+ ) : (
358
+ goldListings.map((l) => {
359
+ const isMine = l.seller === account?.address;
360
+ return (
361
+ <motion.div
362
+ key={l.id}
363
+ initial={{ opacity: 0, y: 6 }}
364
+ animate={{ opacity: 1, y: 0 }}
365
+ className="flex items-center justify-between bg-amber-950/20 border border-amber-800/40 rounded-xl px-4 py-3"
366
+ >
367
+ <div className="flex items-center gap-2">
368
+ <IconGold size={18} />
369
+ <div>
370
+ <p className="font-pixel text-amber-200 text-xs">
371
+ {l.amount.toString()} gold
372
+ </p>
373
+ <p className="text-amber-700 text-[10px]">
374
+ {shortAddr(l.seller)}
375
+ {isMine && <span className="text-amber-500"> (you)</span>}
376
+ </p>
377
+ </div>
378
+ </div>
379
+ <div className="flex items-center gap-3">
380
+ <span className="text-amber-400 text-xs">
381
+ {(Number(l.price) / 1e9).toFixed(4)} SUI
382
+ </span>
383
+ {isMine ? (
384
+ <button
385
+ onClick={() => handleCancelGold(l)}
386
+ disabled={isLoading}
387
+ className="px-3 py-1.5 bg-red-900/70 hover:bg-red-800 text-red-300 text-[10px] font-pixel rounded-lg disabled:opacity-40 transition-colors"
388
+ >
389
+ Cancel
390
+ </button>
391
+ ) : (
392
+ <button
393
+ onClick={() => handleBuyGold(l)}
394
+ disabled={isLoading}
395
+ className="px-4 py-1.5 bg-amber-700 hover:bg-amber-600 text-white text-[10px] font-pixel rounded-lg disabled:opacity-40 transition-colors"
396
+ >
397
+ Buy
398
+ </button>
399
+ )}
400
+ </div>
401
+ </motion.div>
402
+ );
403
+ })
404
+ )}
405
+ </div>
406
+ </div>
407
+ )}
408
+ </GameShell>
409
+ );
410
+ }
411
+
412
+ function EmptyState({ text }: { text: string }) {
413
+ return (
414
+ <div className="bg-slate-950/40 border border-indigo-900/40 rounded-xl p-8 text-center">
415
+ <p className="text-indigo-700 font-pixel text-[11px]">{text}</p>
416
+ </div>
417
+ );
418
+ }