create-dubhe 1.2.0-pre.122 → 1.2.0-pre.123

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 (28) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +1 -1
  4. package/templates/101/sui-template/packages/contracts/src/dubhe/Move.lock +2 -2
  5. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/codegen/error.move +0 -16
  6. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/core/dapp_service.move +51 -35
  7. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/systems/dapp_system.move +30 -135
  8. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/fee_test.move +3 -3
  9. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/listing_test.move +128 -0
  10. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/typed_object_test.move +33 -0
  11. package/templates/101/sui-template/packages/contracts/src/dubhe/sources/tests/typed_scene_test.move +151 -157
  12. package/templates/contract/sui-template/src/dubhe/Move.lock +2 -2
  13. package/templates/contract/sui-template/src/dubhe/sources/codegen/error.move +0 -16
  14. package/templates/contract/sui-template/src/dubhe/sources/core/dapp_service.move +51 -35
  15. package/templates/contract/sui-template/src/dubhe/sources/systems/dapp_system.move +30 -135
  16. package/templates/contract/sui-template/src/dubhe/sources/tests/fee_test.move +3 -3
  17. package/templates/contract/sui-template/src/dubhe/sources/tests/listing_test.move +128 -0
  18. package/templates/contract/sui-template/src/dubhe/sources/tests/typed_object_test.move +33 -0
  19. package/templates/contract/sui-template/src/dubhe/sources/tests/typed_scene_test.move +151 -157
  20. package/templates/nextjs/sui-farm/packages/contracts/src/harvest/sources/codegen/resources/crow_damage.move +10 -12
  21. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/Move.lock +2 -2
  22. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/codegen/error.move +0 -16
  23. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/core/dapp_service.move +51 -35
  24. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/systems/dapp_system.move +30 -135
  25. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/fee_test.move +3 -3
  26. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/listing_test.move +128 -0
  27. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/typed_object_test.move +33 -0
  28. package/templates/nextjs/sui-template/packages/contracts/src/dubhe/sources/tests/typed_scene_test.move +151 -157
package/dist/cli.js CHANGED
@@ -62,7 +62,7 @@ var CHAINS = [
62
62
  // package.json
63
63
  var package_default = {
64
64
  name: "create-dubhe",
65
- version: "1.2.0-pre.122",
65
+ version: "1.2.0-pre.123",
66
66
  repository: {
67
67
  type: "git",
68
68
  url: "https://github.com/0xobelisk/dubhe.git"
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin/cli.ts","../src/config/chains.ts","../package.json","../src/exists.ts"],"sourcesContent":["import { fileURLToPath } from 'node:url';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport glob from 'fast-glob';\nimport yargsInteractive from 'yargs-interactive';\nimport { CHAINS } from '../config/chains';\nimport packageJson from '../../package.json';\nimport { exists } from '../exists';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst cwd = process.cwd();\n\nconst init = async () => {\n // Prepare chain options\n const chainChoices = CHAINS.map(({ title, description, value }) => ({\n name: `${title} - ${description}`,\n value\n }));\n\n // Step 1: Choose project name and chain\n const firstStep = await yargsInteractive()\n .usage('$0 [args]')\n .interactive({\n interactive: { default: true },\n projectName: {\n describe: 'Name your project',\n type: 'input'\n },\n chain: {\n describe: 'Pick your chain',\n type: 'list',\n choices: chainChoices.map((c) => c.value)\n },\n dubheVersion: {\n describe: 'The version of Dubhe packages to use, defaults to latest',\n type: 'input',\n default: packageJson.version\n }\n });\n\n const { projectName, chain, dubheVersion } = firstStep;\n if (!projectName) throw new Error('No project name provided.');\n\n // Get available templates based on the selected chain\n const selectedChain = CHAINS.find((c) => c.value === chain);\n if (!selectedChain) {\n throw new Error('Invalid chain selection');\n }\n\n // Prepare platform options\n const platformChoices = selectedChain.supportedTemplates.map(({ title, description, value }) => ({\n name: `${title} - ${description}`,\n value\n }));\n\n // Step 2: Choose platform\n const secondStep = await yargsInteractive()\n .usage('$0 [args]')\n .interactive({\n interactive: { default: true },\n platform: {\n describe: 'Pick your platform',\n type: 'list',\n choices: platformChoices.map((c) => c.value)\n }\n });\n\n const { platform } = secondStep;\n\n const selectedTemplate = selectedChain.supportedTemplates.find((t) => t.value === platform);\n if (!selectedTemplate) {\n throw new Error('Invalid platform selection');\n }\n\n const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent);\n const pkgManager = pkgInfo ? pkgInfo.name : 'npm';\n\n const sourceDir = path.join(\n __dirname,\n '..',\n 'templates',\n selectedTemplate.path.replace('{chain}', chain)\n );\n\n if (!(await exists(sourceDir))) {\n throw new Error(`Template directory not found: ${sourceDir}`);\n }\n\n const destDir = path.join(process.cwd(), projectName);\n if (await exists(destDir)) {\n throw new Error(`Target directory \"${destDir}\" already exists.`);\n }\n\n const files = await glob('**/*', { cwd: sourceDir, dot: true });\n\n for (const filename of files) {\n const sourceFile = path.join(sourceDir, filename);\n const destFile = path.join(destDir, filename);\n\n await fs.mkdir(path.dirname(destFile), { recursive: true });\n\n if (/package\\.json$/.test(sourceFile)) {\n const source = await fs.readFile(sourceFile, 'utf-8');\n await fs.writeFile(destFile, source.replaceAll(/{{dubhe-version}}/g, dubheVersion), 'utf-8');\n } else if (/\\.gitignore_$/.test(sourceFile)) {\n await fs.copyFile(sourceFile, destFile.replace(/_$/, ''));\n } else {\n await fs.copyFile(sourceFile, destFile);\n }\n }\n\n const cdProjectName = path.relative(cwd, destDir);\n\n const styles = {\n success: '\\x1b[32m%s\\x1b[0m',\n info: '\\x1b[36m%s\\x1b[0m',\n command: '\\x1b[33m%s\\x1b[0m',\n separator: '\\x1b[90m%s\\x1b[0m'\n };\n\n console.log('\\n' + '='.repeat(60));\n console.log(styles.success, '🎉 Project creation successful!');\n console.log(styles.info, `📁 Project location: ${destDir}`);\n console.log(styles.separator, '-'.repeat(60));\n console.log(styles.info, 'Next steps:\\n');\n\n if (destDir !== cwd) {\n console.log(\n styles.command,\n ` cd ${cdProjectName.includes(' ') ? `\"${cdProjectName}\"` : cdProjectName}`\n );\n }\n\n const actualTemplate = selectedTemplate.value;\n\n switch (actualTemplate) {\n case '101':\n case 'web':\n console.log(styles.command, ` ${pkgManager} install`);\n console.log(styles.command, ` ${pkgManager} dubhe doctor`);\n console.log(styles.command, ` ${pkgManager} run dev`);\n break;\n case 'contract':\n console.log(styles.command, ` ${pkgManager} install`);\n console.log(styles.command, ` ${pkgManager} dubhe doctor`);\n break;\n }\n\n console.log(styles.separator, '\\n' + '='.repeat(60) + '\\n');\n};\n\nfunction pkgFromUserAgent(userAgent: string | undefined) {\n if (!userAgent) return undefined;\n const pkgSpec = userAgent.split(' ')[0];\n const pkgSpecArr = pkgSpec.split('/');\n return {\n name: pkgSpecArr[0],\n version: pkgSpecArr[1]\n };\n}\n\ninit().catch((e) => {\n console.error(e);\n});\n","interface Template {\n title: string;\n description: string;\n value: string;\n path: string;\n}\n\ninterface Chain {\n title: string;\n description: string;\n value: string;\n supportedTemplates: Template[];\n}\n\nconst TEMPLATES = {\n QUICK_START: {\n title: '101',\n description: 'Quick start',\n value: '101',\n path: '101/{chain}-template'\n },\n WEB: {\n title: 'Web',\n description: 'Web template',\n value: 'web',\n path: 'nextjs/{chain}-template'\n },\n CONTRACT: {\n title: 'Contract',\n description: 'Contract template',\n value: 'contract',\n path: 'contract/{chain}-template'\n }\n} as const;\n\nexport const CHAINS: Chain[] = [\n {\n title: 'sui',\n description: 'Sui',\n value: 'sui',\n supportedTemplates: [TEMPLATES.QUICK_START, TEMPLATES.WEB, TEMPLATES.CONTRACT]\n },\n {\n title: 'aptos',\n description: 'Aptos',\n value: 'aptos',\n supportedTemplates: [TEMPLATES.QUICK_START, TEMPLATES.WEB, TEMPLATES.CONTRACT]\n },\n {\n title: 'rooch',\n description: 'Rooch',\n value: 'rooch',\n supportedTemplates: [TEMPLATES.QUICK_START]\n },\n {\n title: 'initia',\n description: 'Initia',\n value: 'initia',\n supportedTemplates: [TEMPLATES.QUICK_START]\n },\n {\n title: 'movement',\n description: 'Movement',\n value: 'movement',\n supportedTemplates: [TEMPLATES.QUICK_START]\n }\n];\n","{\n \"name\": \"create-dubhe\",\n \"version\": \"1.2.0-pre.122\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/0xobelisk/dubhe.git\"\n },\n \"license\": \"MIT\",\n \"author\": \"team@obelisk.build\",\n \"type\": \"module\",\n \"bin\": \"bin/cli.js\",\n \"files\": [\n \"bin\",\n \"dist\",\n \"templates\"\n ],\n \"scripts\": {\n \"build\": \"pnpm run type-check && pnpm run build:js\",\n \"build:js\": \"tsup && pnpm run copy-templates\",\n \"clean\": \"pnpm run clean:js\",\n \"clean:js\": \"shx rm -rf dist\",\n \"cocos-js-build\": \"cd cocos-lib-builder && npm i && browserify aptos.js -p esmify > ../templates/cocos/aptos-template/assets/lib/dubhe.js && browserify sui.js -p esmify > ../templates/cocos/sui-template/assets/lib/dubhe.js\",\n \"copy-templates\": \"tsx ./scripts/copy-templates.ts\",\n \"dev\": \"tsup --watch\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"lint\": \"eslint . --ext .ts\",\n \"type-check\": \"tsc --noEmit\",\n \"validate\": \"pnpm format:check && pnpm lint && pnpm type-check\"\n },\n \"dependencies\": {\n \"browser-resolve\": \"^2.0.0\",\n \"browser-sync\": \"^2.29.3\",\n \"fast-glob\": \"^3.3.3\",\n \"yargs-interactive\": \"^3.0.1\"\n },\n \"devDependencies\": {\n \"@types/cross-spawn\": \"^6.0.2\",\n \"@types/minimist\": \"^1.2.2\",\n \"@types/prompts\": \"^2.4.3\",\n \"@types/yargs-interactive\": \"^2.1.6\",\n \"browserify\": \"^17.0.0\",\n \"cross-spawn\": \"^7.0.3\",\n \"eslint\": \"^9.0.0\",\n \"eslint-config-prettier\": \"^9.1.0\",\n \"esmify\": \"^2.1.1\",\n \"kolorist\": \"^1.7.0\",\n \"prettier\": \"3.3.3\",\n \"prompts\": \"^2.4.2\",\n \"typescript\": \"^5.8.3\"\n },\n \"engines\": {\n \"node\": \">=22.0.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import fs from 'node:fs/promises';\n\nexport async function exists(path: string) {\n try {\n await fs.access(path);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":["fs","path","fs"]}
1
+ {"version":3,"sources":["../src/bin/cli.ts","../src/config/chains.ts","../package.json","../src/exists.ts"],"sourcesContent":["import { fileURLToPath } from 'node:url';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport glob from 'fast-glob';\nimport yargsInteractive from 'yargs-interactive';\nimport { CHAINS } from '../config/chains';\nimport packageJson from '../../package.json';\nimport { exists } from '../exists';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst cwd = process.cwd();\n\nconst init = async () => {\n // Prepare chain options\n const chainChoices = CHAINS.map(({ title, description, value }) => ({\n name: `${title} - ${description}`,\n value\n }));\n\n // Step 1: Choose project name and chain\n const firstStep = await yargsInteractive()\n .usage('$0 [args]')\n .interactive({\n interactive: { default: true },\n projectName: {\n describe: 'Name your project',\n type: 'input'\n },\n chain: {\n describe: 'Pick your chain',\n type: 'list',\n choices: chainChoices.map((c) => c.value)\n },\n dubheVersion: {\n describe: 'The version of Dubhe packages to use, defaults to latest',\n type: 'input',\n default: packageJson.version\n }\n });\n\n const { projectName, chain, dubheVersion } = firstStep;\n if (!projectName) throw new Error('No project name provided.');\n\n // Get available templates based on the selected chain\n const selectedChain = CHAINS.find((c) => c.value === chain);\n if (!selectedChain) {\n throw new Error('Invalid chain selection');\n }\n\n // Prepare platform options\n const platformChoices = selectedChain.supportedTemplates.map(({ title, description, value }) => ({\n name: `${title} - ${description}`,\n value\n }));\n\n // Step 2: Choose platform\n const secondStep = await yargsInteractive()\n .usage('$0 [args]')\n .interactive({\n interactive: { default: true },\n platform: {\n describe: 'Pick your platform',\n type: 'list',\n choices: platformChoices.map((c) => c.value)\n }\n });\n\n const { platform } = secondStep;\n\n const selectedTemplate = selectedChain.supportedTemplates.find((t) => t.value === platform);\n if (!selectedTemplate) {\n throw new Error('Invalid platform selection');\n }\n\n const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent);\n const pkgManager = pkgInfo ? pkgInfo.name : 'npm';\n\n const sourceDir = path.join(\n __dirname,\n '..',\n 'templates',\n selectedTemplate.path.replace('{chain}', chain)\n );\n\n if (!(await exists(sourceDir))) {\n throw new Error(`Template directory not found: ${sourceDir}`);\n }\n\n const destDir = path.join(process.cwd(), projectName);\n if (await exists(destDir)) {\n throw new Error(`Target directory \"${destDir}\" already exists.`);\n }\n\n const files = await glob('**/*', { cwd: sourceDir, dot: true });\n\n for (const filename of files) {\n const sourceFile = path.join(sourceDir, filename);\n const destFile = path.join(destDir, filename);\n\n await fs.mkdir(path.dirname(destFile), { recursive: true });\n\n if (/package\\.json$/.test(sourceFile)) {\n const source = await fs.readFile(sourceFile, 'utf-8');\n await fs.writeFile(destFile, source.replaceAll(/{{dubhe-version}}/g, dubheVersion), 'utf-8');\n } else if (/\\.gitignore_$/.test(sourceFile)) {\n await fs.copyFile(sourceFile, destFile.replace(/_$/, ''));\n } else {\n await fs.copyFile(sourceFile, destFile);\n }\n }\n\n const cdProjectName = path.relative(cwd, destDir);\n\n const styles = {\n success: '\\x1b[32m%s\\x1b[0m',\n info: '\\x1b[36m%s\\x1b[0m',\n command: '\\x1b[33m%s\\x1b[0m',\n separator: '\\x1b[90m%s\\x1b[0m'\n };\n\n console.log('\\n' + '='.repeat(60));\n console.log(styles.success, '🎉 Project creation successful!');\n console.log(styles.info, `📁 Project location: ${destDir}`);\n console.log(styles.separator, '-'.repeat(60));\n console.log(styles.info, 'Next steps:\\n');\n\n if (destDir !== cwd) {\n console.log(\n styles.command,\n ` cd ${cdProjectName.includes(' ') ? `\"${cdProjectName}\"` : cdProjectName}`\n );\n }\n\n const actualTemplate = selectedTemplate.value;\n\n switch (actualTemplate) {\n case '101':\n case 'web':\n console.log(styles.command, ` ${pkgManager} install`);\n console.log(styles.command, ` ${pkgManager} dubhe doctor`);\n console.log(styles.command, ` ${pkgManager} run dev`);\n break;\n case 'contract':\n console.log(styles.command, ` ${pkgManager} install`);\n console.log(styles.command, ` ${pkgManager} dubhe doctor`);\n break;\n }\n\n console.log(styles.separator, '\\n' + '='.repeat(60) + '\\n');\n};\n\nfunction pkgFromUserAgent(userAgent: string | undefined) {\n if (!userAgent) return undefined;\n const pkgSpec = userAgent.split(' ')[0];\n const pkgSpecArr = pkgSpec.split('/');\n return {\n name: pkgSpecArr[0],\n version: pkgSpecArr[1]\n };\n}\n\ninit().catch((e) => {\n console.error(e);\n});\n","interface Template {\n title: string;\n description: string;\n value: string;\n path: string;\n}\n\ninterface Chain {\n title: string;\n description: string;\n value: string;\n supportedTemplates: Template[];\n}\n\nconst TEMPLATES = {\n QUICK_START: {\n title: '101',\n description: 'Quick start',\n value: '101',\n path: '101/{chain}-template'\n },\n WEB: {\n title: 'Web',\n description: 'Web template',\n value: 'web',\n path: 'nextjs/{chain}-template'\n },\n CONTRACT: {\n title: 'Contract',\n description: 'Contract template',\n value: 'contract',\n path: 'contract/{chain}-template'\n }\n} as const;\n\nexport const CHAINS: Chain[] = [\n {\n title: 'sui',\n description: 'Sui',\n value: 'sui',\n supportedTemplates: [TEMPLATES.QUICK_START, TEMPLATES.WEB, TEMPLATES.CONTRACT]\n },\n {\n title: 'aptos',\n description: 'Aptos',\n value: 'aptos',\n supportedTemplates: [TEMPLATES.QUICK_START, TEMPLATES.WEB, TEMPLATES.CONTRACT]\n },\n {\n title: 'rooch',\n description: 'Rooch',\n value: 'rooch',\n supportedTemplates: [TEMPLATES.QUICK_START]\n },\n {\n title: 'initia',\n description: 'Initia',\n value: 'initia',\n supportedTemplates: [TEMPLATES.QUICK_START]\n },\n {\n title: 'movement',\n description: 'Movement',\n value: 'movement',\n supportedTemplates: [TEMPLATES.QUICK_START]\n }\n];\n","{\n \"name\": \"create-dubhe\",\n \"version\": \"1.2.0-pre.123\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/0xobelisk/dubhe.git\"\n },\n \"license\": \"MIT\",\n \"author\": \"team@obelisk.build\",\n \"type\": \"module\",\n \"bin\": \"bin/cli.js\",\n \"files\": [\n \"bin\",\n \"dist\",\n \"templates\"\n ],\n \"scripts\": {\n \"build\": \"pnpm run type-check && pnpm run build:js\",\n \"build:js\": \"tsup && pnpm run copy-templates\",\n \"clean\": \"pnpm run clean:js\",\n \"clean:js\": \"shx rm -rf dist\",\n \"cocos-js-build\": \"cd cocos-lib-builder && npm i && browserify aptos.js -p esmify > ../templates/cocos/aptos-template/assets/lib/dubhe.js && browserify sui.js -p esmify > ../templates/cocos/sui-template/assets/lib/dubhe.js\",\n \"copy-templates\": \"tsx ./scripts/copy-templates.ts\",\n \"dev\": \"tsup --watch\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"lint\": \"eslint . --ext .ts\",\n \"type-check\": \"tsc --noEmit\",\n \"validate\": \"pnpm format:check && pnpm lint && pnpm type-check\"\n },\n \"dependencies\": {\n \"browser-resolve\": \"^2.0.0\",\n \"browser-sync\": \"^2.29.3\",\n \"fast-glob\": \"^3.3.3\",\n \"yargs-interactive\": \"^3.0.1\"\n },\n \"devDependencies\": {\n \"@types/cross-spawn\": \"^6.0.2\",\n \"@types/minimist\": \"^1.2.2\",\n \"@types/prompts\": \"^2.4.3\",\n \"@types/yargs-interactive\": \"^2.1.6\",\n \"browserify\": \"^17.0.0\",\n \"cross-spawn\": \"^7.0.3\",\n \"eslint\": \"^9.0.0\",\n \"eslint-config-prettier\": \"^9.1.0\",\n \"esmify\": \"^2.1.1\",\n \"kolorist\": \"^1.7.0\",\n \"prettier\": \"3.3.3\",\n \"prompts\": \"^2.4.2\",\n \"typescript\": \"^5.8.3\"\n },\n \"engines\": {\n \"node\": \">=22.0.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import fs from 'node:fs/promises';\n\nexport async function exists(path: string) {\n try {\n await fs.access(path);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":["fs","path","fs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-dubhe",
3
- "version": "1.2.0-pre.122",
3
+ "version": "1.2.0-pre.123",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/0xobelisk/dubhe.git"
@@ -42,6 +42,6 @@ deps = { MoveStdlib = "MoveStdlib" }
42
42
 
43
43
  [env.mainnet]
44
44
  chain-id = "35834a8a"
45
- original-published-id = "0x1a79c1611ab49723b388510813553ad912d96a4f1a9ed5fdbdb57e446c6fe946"
46
- latest-published-id = "0x1a79c1611ab49723b388510813553ad912d96a4f1a9ed5fdbdb57e446c6fe946"
45
+ original-published-id = "0xdd59a0e210585ec38da6d966d2936c7476b9e08b3cc2f785ca998d084bf24c81"
46
+ latest-published-id = "0xdd59a0e210585ec38da6d966d2936c7476b9e08b3cc2f785ca998d084bf24c81"
47
47
  published-version = "1"
@@ -40,10 +40,6 @@ module dubhe::error {
40
40
  const EUserDebtLimitExceeded: vector<u8> = b"User debt limit exceeded";
41
41
  public fun user_debt_limit_exceeded(condition: bool) { assert!(condition, EUserDebtLimitExceeded) }
42
42
 
43
- #[error]
44
- const EDappSuspended: vector<u8> = b"Dapp is suspended";
45
- public fun dapp_suspended(condition: bool) { assert!(condition, EDappSuspended) }
46
-
47
43
  #[error]
48
44
  const EDappKeyMismatch: vector<u8> = b"Dapp key mismatch";
49
45
  public fun dapp_key_mismatch(condition: bool) { assert!(condition, EDappKeyMismatch) }
@@ -56,10 +52,6 @@ module dubhe::error {
56
52
  const ENotCanonicalOwner: vector<u8> = b"Not canonical owner";
57
53
  public fun not_canonical_owner(condition: bool) { assert!(condition, ENotCanonicalOwner) }
58
54
 
59
- #[error]
60
- const EInsufficientCreditToUnsuspend: vector<u8> = b"Insufficient credit to unsuspend";
61
- public fun insufficient_credit_to_unsuspend(condition: bool) { assert!(condition, EInsufficientCreditToUnsuspend) }
62
-
63
55
  #[error]
64
56
  const EUserStorageAlreadyExists: vector<u8> = b"User storage already exists";
65
57
  public fun user_storage_already_exists(condition: bool) { assert!(condition, EUserStorageAlreadyExists) }
@@ -104,14 +96,6 @@ module dubhe::error {
104
96
  const ENotSceneParticipant: vector<u8> = b"Not a scene participant";
105
97
  public fun not_scene_participant(condition: bool) { assert!(condition, ENotSceneParticipant) }
106
98
 
107
- #[error]
108
- const ENonceAlreadyUsed: vector<u8> = b"Nonce already used";
109
- public fun nonce_already_used(condition: bool) { assert!(condition, ENonceAlreadyUsed) }
110
-
111
- #[error]
112
- const EInvalidConsentSignature: vector<u8> = b"Invalid consent signature";
113
- public fun invalid_consent_signature(condition: bool) { assert!(condition, EInvalidConsentSignature) }
114
-
115
99
  #[error]
116
100
  const EEntityNotFound: vector<u8> = b"Entity not found";
117
101
  public fun entity_not_found(condition: bool) { assert!(condition, EEntityNotFound) }
@@ -33,9 +33,9 @@ module dubhe::dapp_service {
33
33
  // ─── PermitMetadata — authorization token for reactive writes ─────────────
34
34
  //
35
35
  // Embedded in every codegen-generated typed SceneStorage struct.
36
- // Reactive write functions require a (&UID, &PermitMetadata) pair to verify
37
- // that both the initiator and the target are registered participants and that
38
- // the scene is still active.
36
+ // Reactive write functions require a &ScenePermit<T> to verify that both
37
+ // the initiator and the target are registered participants and that the
38
+ // scene is still active.
39
39
  //
40
40
  // Participants are stored as dynamic fields on the scene object's UID
41
41
  // (key = ParticipantKey { addr }, value = bool true). This gives O(1)
@@ -56,7 +56,7 @@ module dubhe::dapp_service {
56
56
  /// None = invitations never expire. Once passed, accept_<scene> aborts.
57
57
  invites_expire_at: Option<u64>,
58
58
  /// Maximum number of confirmed participants allowed in this scene.
59
- /// None = unlimited. Enforced by add_scene_participant.
59
+ /// None = unlimited. Enforced on participant add.
60
60
  max_participants: Option<u64>,
61
61
  /// Current confirmed participant count — updated by add/remove.
62
62
  participant_count: u64,
@@ -114,36 +114,6 @@ module dubhe::dapp_service {
114
114
  meta.invitees.contains(&addr)
115
115
  }
116
116
 
117
- /// Moves `addr` from the invitees list into the confirmed participants list.
118
- /// Aborts if addr is not in invitees.
119
- public fun accept_scene_invitation_meta(id: &mut UID, meta: &mut PermitMetadata, addr: address) {
120
- let (found, idx) = meta.invitees.index_of(&addr);
121
- error::not_participant(found);
122
- meta.invitees.remove(idx);
123
- add_scene_participant(id, meta, addr);
124
- }
125
-
126
- /// Add `addr` as a confirmed participant (O(1) dynamic field write).
127
- /// Enforces max_participants cap if set. No-op if already a participant.
128
- public fun add_scene_participant(id: &mut UID, meta: &mut PermitMetadata, addr: address) {
129
- if (dynamic_field::exists_(id, ParticipantKey { addr })) { return };
130
- if (meta.max_participants.is_some()) {
131
- error::scene_full(
132
- meta.participant_count < *option::borrow(&meta.max_participants)
133
- );
134
- };
135
- dynamic_field::add(id, ParticipantKey { addr }, true);
136
- meta.participant_count = meta.participant_count + 1;
137
- }
138
-
139
- /// Remove `addr` from confirmed participants (O(1) dynamic field remove).
140
- /// No-op if not a participant.
141
- public fun remove_scene_participant(id: &mut UID, meta: &mut PermitMetadata, addr: address) {
142
- if (!dynamic_field::exists_(id, ParticipantKey { addr })) { return };
143
- let _: bool = dynamic_field::remove(id, ParticipantKey { addr });
144
- meta.participant_count = meta.participant_count - 1;
145
- }
146
-
147
117
  /// O(1) participant check via dynamic field existence.
148
118
  public fun is_scene_participant(id: &UID, addr: address): bool {
149
119
  dynamic_field::exists_(id, ParticipantKey { addr })
@@ -189,6 +159,7 @@ module dubhe::dapp_service {
189
159
  };
190
160
  }
191
161
 
162
+ #[test_only]
192
163
  public fun has_object_entity_id(
193
164
  ds: &DappStorage,
194
165
  type_tag: vector<u8>,
@@ -197,6 +168,7 @@ module dubhe::dapp_service {
197
168
  dynamic_field::exists_(&ds.id, ObjectEntityIdKey { type_tag, entity_id })
198
169
  }
199
170
 
171
+ #[test_only]
200
172
  public fun get_object_entity_id(
201
173
  ds: &DappStorage,
202
174
  type_tag: vector<u8>,
@@ -535,7 +507,7 @@ module dubhe::dapp_service {
535
507
  let mut i = 0;
536
508
  let len = participants.length();
537
509
  while (i < len) {
538
- add_scene_participant(&mut permit.id, &mut permit.meta, *participants.borrow(i));
510
+ add_participant_in_scene_permit(&mut permit, *participants.borrow(i));
539
511
  i = i + 1;
540
512
  };
541
513
  let permit_id = object::uid_to_address(&permit.id);
@@ -933,11 +905,17 @@ module dubhe::dapp_service {
933
905
  };
934
906
  }
935
907
 
908
+ /// Return the full fee-change history ring buffer (most recent at the back).
909
+ /// Useful for off-chain explorers and billing tools that need to determine
910
+ /// the applicable fee rate for a historical write operation.
936
911
  public fun fee_history(cfg: &FrameworkFeeConfig): &vector<FeeHistoryEntry> {
937
912
  &cfg.fee_history
938
913
  }
914
+ /// Base fee that was committed in this history entry (MIST per write).
939
915
  public fun fee_history_base_fee(e: &FeeHistoryEntry): u256 { e.base_fee }
916
+ /// Bytes fee that was committed in this history entry (MIST per byte).
940
917
  public fun fee_history_bytes_fee(e: &FeeHistoryEntry): u256 { e.bytes_fee }
918
+ /// Epoch-ms timestamp from which this history entry's rates became effective.
941
919
  public fun fee_history_effective_from_ms(e: &FeeHistoryEntry): u64 { e.effective_from_ms }
942
920
 
943
921
  public fun is_fee_config_initialized(dh: &DappHub): bool {
@@ -1823,4 +1801,42 @@ module dubhe::dapp_service {
1823
1801
  object::delete(id);
1824
1802
  }
1825
1803
 
1804
+ #[test_only]
1805
+ public fun create_scene_permit_for_testing<DappKey: copy + drop, PermType>(
1806
+ participants: vector<address>,
1807
+ expires_at: std::option::Option<u64>,
1808
+ max_participants: std::option::Option<u64>,
1809
+ ctx: &mut TxContext,
1810
+ ): ScenePermit<PermType> {
1811
+ let mut permit = ScenePermit<PermType> {
1812
+ id: object::new(ctx),
1813
+ dapp_key: type_name::with_defining_ids<DappKey>().into_string(),
1814
+ permit_type: b"test",
1815
+ meta: new_scene_meta(expires_at, max_participants),
1816
+ };
1817
+ participants.do!(|addr| { add_participant_in_scene_permit(&mut permit, addr) });
1818
+ permit
1819
+ }
1820
+
1821
+ #[test_only]
1822
+ public fun create_scene_permit_with_invitations_for_testing<DappKey: copy + drop, PermType>(
1823
+ invitees: vector<address>,
1824
+ invites_expire_at: std::option::Option<u64>,
1825
+ expires_at: std::option::Option<u64>,
1826
+ ctx: &mut TxContext,
1827
+ ): ScenePermit<PermType> {
1828
+ ScenePermit<PermType> {
1829
+ id: object::new(ctx),
1830
+ dapp_key: type_name::with_defining_ids<DappKey>().into_string(),
1831
+ permit_type: b"test",
1832
+ meta: new_scene_meta_with_invitations(invitees, invites_expire_at, expires_at, option::none()),
1833
+ }
1834
+ }
1835
+
1836
+ #[test_only]
1837
+ public fun destroy_scene_permit_for_testing<PermType>(permit: ScenePermit<PermType>) {
1838
+ let ScenePermit { id, dapp_key: _, permit_type: _, meta: _ } = permit;
1839
+ object::delete(id);
1840
+ }
1841
+
1826
1842
  }
@@ -152,12 +152,13 @@ public fun create_user_storage<DappKey: copy + drop>(
152
152
  ctx: &mut TxContext,
153
153
  ) {
154
154
  assert_framework_version(dapp_hub);
155
+ let dapp_key_str = type_info::get_type_name_string<DappKey>();
156
+ error::dapp_key_mismatch(dapp_service::dapp_storage_dapp_key(dapp_storage) == dapp_key_str);
155
157
  error::dapp_paused(!dapp_service::dapp_paused(dapp_storage));
156
158
  let sender = ctx.sender();
157
159
  error::user_storage_already_exists(!dapp_service::has_registered_user_storage(dapp_storage, sender));
158
160
  dapp_service::register_user_storage(dapp_storage, sender);
159
161
  let write_limit = dapp_service::framework_max_write_limit(dapp_service::get_config(dapp_hub));
160
- let dapp_key_str = type_info::get_type_name_string<DappKey>();
161
162
  let us = dapp_service::new_user_storage<DappKey>(sender, write_limit, ctx);
162
163
  dubhe_events::emit_user_storage_created(
163
164
  dapp_key_str,
@@ -283,11 +284,10 @@ public fun delete_field<DappKey: copy + drop>(
283
284
  //
284
285
  // Write fees are charged to the initiator (`from`) under the initiator-pays model.
285
286
 
286
- /// Write a full record to another user's UserStorage, authorized by PermitMetadata.
287
- public fun set_record_reactive<DappKey: copy + drop>(
287
+ /// Write a full record to another user's UserStorage, authorized by a ScenePermit.
288
+ public fun set_record_reactive<DappKey: copy + drop, PermType>(
288
289
  _auth: DappKey,
289
- scene_id: &UID,
290
- meta: &PermitMetadata,
290
+ permit: &ScenePermit<PermType>,
291
291
  from: &mut UserStorage,
292
292
  target: &mut UserStorage,
293
293
  key: vector<vector<u8>>,
@@ -298,6 +298,10 @@ public fun set_record_reactive<DappKey: copy + drop>(
298
298
  let dapp_key_str = type_info::get_type_name_string<DappKey>();
299
299
  error::dapp_key_mismatch(dapp_service::user_storage_dapp_key(from) == dapp_key_str);
300
300
  error::dapp_key_mismatch(dapp_service::user_storage_dapp_key(target) == dapp_key_str);
301
+ error::dapp_key_mismatch(dapp_service::scene_permit_dapp_key(permit) == dapp_key_str);
302
+
303
+ let scene_id = dapp_service::scene_permit_id(permit);
304
+ let meta = dapp_service::scene_permit_meta(permit);
301
305
 
302
306
  // 1. Sender must be the initiator's canonical owner.
303
307
  error::not_canonical_owner(ctx.sender() == dapp_service::canonical_owner(from));
@@ -319,11 +323,10 @@ public fun set_record_reactive<DappKey: copy + drop>(
319
323
  dapp_service::set_user_record<DappKey>(target, key, field_names, values, false);
320
324
  }
321
325
 
322
- /// Update a single named field in another user's UserStorage, authorized by PermitMetadata.
323
- public fun set_field_reactive<DappKey: copy + drop>(
326
+ /// Update a single named field in another user's UserStorage, authorized by a ScenePermit.
327
+ public fun set_field_reactive<DappKey: copy + drop, PermType>(
324
328
  _auth: DappKey,
325
- scene_id: &UID,
326
- meta: &PermitMetadata,
329
+ permit: &ScenePermit<PermType>,
327
330
  from: &mut UserStorage,
328
331
  target: &mut UserStorage,
329
332
  key: vector<vector<u8>>,
@@ -334,6 +337,10 @@ public fun set_field_reactive<DappKey: copy + drop>(
334
337
  let dapp_key_str = type_info::get_type_name_string<DappKey>();
335
338
  error::dapp_key_mismatch(dapp_service::user_storage_dapp_key(from) == dapp_key_str);
336
339
  error::dapp_key_mismatch(dapp_service::user_storage_dapp_key(target) == dapp_key_str);
340
+ error::dapp_key_mismatch(dapp_service::scene_permit_dapp_key(permit) == dapp_key_str);
341
+
342
+ let scene_id = dapp_service::scene_permit_id(permit);
343
+ let meta = dapp_service::scene_permit_meta(permit);
337
344
 
338
345
  error::not_canonical_owner(ctx.sender() == dapp_service::canonical_owner(from));
339
346
  error::not_scene_participant(dapp_service::is_scene_participant(scene_id, dapp_service::canonical_owner(from)));
@@ -347,98 +354,14 @@ public fun set_field_reactive<DappKey: copy + drop>(
347
354
  dapp_service::add_write_bytes(from, (field_value.length() as u256));
348
355
  }
349
356
 
350
- // ─── PermitMetadata primitives (public wrappers) ───────────────────────────────
351
-
352
- /// Create a new PermitMetadata (no participants yet) and bulk-add initial
353
- /// participants as dynamic fields. This is the standard entry point called
354
- /// by codegen-generated create_<scene> functions.
355
- ///
356
- /// The caller must pass `&mut id` — the scene object's UID — before wrapping
357
- /// it in the scene struct. Initial participants are seeded via O(1) dynamic
358
- /// field writes; subsequent joins also use the same path.
359
- public fun init_scene_meta(
360
- id: &mut UID,
361
- participants: vector<address>,
362
- expires_at: Option<u64>,
363
- max_participants: Option<u64>,
364
- ): PermitMetadata {
365
- let mut meta = dapp_service::new_scene_meta(expires_at, max_participants);
366
- let mut i = 0;
367
- let n = participants.length();
368
- while (i < n) {
369
- dapp_service::add_scene_participant(id, &mut meta, *participants.borrow(i));
370
- i = i + 1;
371
- };
372
- meta
373
- }
374
-
375
- /// Create a PermitMetadata in invitation mode: participants list starts empty,
376
- /// invitees must call accept_scene_invitation to confirm before they can react.
377
- public fun new_scene_meta_with_invitations(
378
- invitees: vector<address>,
379
- invites_expire_at: Option<u64>,
380
- scene_expires_at: Option<u64>,
381
- max_participants: Option<u64>,
382
- ): PermitMetadata {
383
- dapp_service::new_scene_meta_with_invitations(invitees, invites_expire_at, scene_expires_at, max_participants)
384
- }
385
-
386
- /// Called by an invitee to confirm their participation in a scene.
387
- ///
388
- /// Validates:
389
- /// 1. The scene itself has not expired.
390
- /// 2. The invitation window is still open (if invites_expire_at is set).
391
- /// 3. ctx.sender() is in the invitees list.
392
- /// On success: sender is moved from invitees into confirmed participants (DF).
393
- ///
394
- /// Works for ALL Sui wallet types (Ed25519, Secp256k1, Secp256r1, zkLogin, multisig)
395
- /// because authorization relies on Sui's native transaction sender verification.
396
- public fun accept_scene_invitation<DappKey: copy + drop>(
397
- _auth: DappKey,
398
- id: &mut UID,
399
- meta: &mut PermitMetadata,
400
- ctx: &TxContext,
401
- ) {
402
- // Scene must still be active.
403
- error::scene_expired(dapp_service::is_scene_active(meta, ctx.epoch_timestamp_ms()));
404
- let expire_opt = dapp_service::scene_invites_expire_at(meta);
405
- if (option::is_some(&expire_opt)) {
406
- error::invitation_expired(ctx.epoch_timestamp_ms() <= *option::borrow(&expire_opt));
407
- };
408
- let sender = ctx.sender();
409
- error::not_participant(dapp_service::is_scene_invitee(meta, sender));
410
- dapp_service::accept_scene_invitation_meta(id, meta, sender);
411
- }
412
-
413
- /// Add a participant to a scene (O(1) dynamic field write).
414
- public fun add_scene_participant(id: &mut UID, meta: &mut PermitMetadata, addr: address) {
415
- dapp_service::add_scene_participant(id, meta, addr)
416
- }
417
-
418
- /// Remove a participant from a scene (O(1) dynamic field remove).
419
- public fun remove_scene_participant(id: &mut UID, meta: &mut PermitMetadata, addr: address) {
420
- dapp_service::remove_scene_participant(id, meta, addr)
421
- }
422
-
423
- /// Returns true if the scene is still active (not expired).
424
- public fun is_scene_active(meta: &PermitMetadata, now_ms: u64): bool {
425
- dapp_service::is_scene_active(meta, now_ms)
426
- }
427
-
428
- /// Returns true if addr is a registered participant in this scene (O(1) DF lookup).
429
- public fun is_scene_participant(scene_id: &UID, addr: address): bool {
430
- dapp_service::is_scene_participant(scene_id, addr)
431
- }
432
-
433
357
  // ─── Typed Object management primitives ──────────────────────────────────────
434
358
  //
435
- // Called by codegen-generated create_<key> / destroy_<key> entry functions.
359
+ // Production path: create_and_share_typed_object / destroy_typed_object (used by codegen).
436
360
  // entity_id uniqueness is scoped per (DApp, type_tag) — a guild and a boss
437
361
  // can share the same entity_id bytes without collision.
438
362
 
439
- /// Register a new typed object's entity_id in DappStorage.
440
- /// Aborts if (type_tag, entity_id) is already registered for this DApp.
441
- /// Returns the new object's UID for the caller to embed in its struct.
363
+ /// Low-level UID primitive test-only. Production code uses create_and_share_typed_object.
364
+ #[test_only]
442
365
  public fun create_object<DappKey: copy + drop>(
443
366
  _auth: DappKey,
444
367
  dapp_storage: &mut DappStorage,
@@ -455,36 +378,8 @@ public fun create_object<DappKey: copy + drop>(
455
378
  uid
456
379
  }
457
380
 
458
- /// Register an entity_id for a typed object that was created with a locally-owned UID.
459
- /// Use this in codegen-generated create_<key> functions where the UID must remain in
460
- /// the local scope (Sui verifier requires UID to be directly from sui::object::new).
461
- public fun register_object_entity<DappKey: copy + drop>(
462
- _auth: DappKey,
463
- dapp_storage: &mut DappStorage,
464
- type_tag: vector<u8>,
465
- entity_id: vector<u8>,
466
- object_id: address,
467
- ) {
468
- let dapp_key_str = type_info::get_type_name_string<DappKey>();
469
- error::dapp_key_mismatch(dapp_service::dapp_storage_dapp_key(dapp_storage) == dapp_key_str);
470
- dapp_service::register_object_entity_id(dapp_storage, type_tag, entity_id, object_id);
471
- }
472
-
473
- /// Unregister an entity_id for a typed object. Use in codegen-generated destroy_<key>.
474
- /// The caller must separately delete the UID with `sui::object::delete`.
475
- public fun unregister_object_entity<DappKey: copy + drop>(
476
- _auth: DappKey,
477
- dapp_storage: &mut DappStorage,
478
- type_tag: vector<u8>,
479
- entity_id: vector<u8>,
480
- ) {
481
- let dapp_key_str = type_info::get_type_name_string<DappKey>();
482
- error::dapp_key_mismatch(dapp_service::dapp_storage_dapp_key(dapp_storage) == dapp_key_str);
483
- dapp_service::unregister_object_entity_id(dapp_storage, type_tag, entity_id);
484
- }
485
-
486
381
  /// Unregister a typed object's entity_id from DappStorage and delete its UID.
487
- /// Called by codegen-generated destroy_<key> entry functions.
382
+ #[test_only]
488
383
  public fun destroy_object<DappKey: copy + drop>(
489
384
  _auth: DappKey,
490
385
  dapp_storage: &mut DappStorage,
@@ -499,16 +394,6 @@ public fun destroy_object<DappKey: copy + drop>(
499
394
  sui::object::delete(uid);
500
395
  }
501
396
 
502
- /// Returns true if (type_tag, entity_id) is already registered for this DApp.
503
- public fun has_object_entity_id<DappKey: copy + drop>(
504
- _auth: DappKey,
505
- dapp_storage: &DappStorage,
506
- type_tag: vector<u8>,
507
- entity_id: vector<u8>,
508
- ): bool {
509
- dapp_service::has_object_entity_id(dapp_storage, type_tag, entity_id)
510
- }
511
-
512
397
  // ─── Framework-controlled ObjectStorage CRUD ─────────────────────────────────
513
398
  //
514
399
  // These functions replace the old DApp-side Bag manipulation pattern.
@@ -667,6 +552,7 @@ public fun destroy_typed_object<DappKey: copy + drop, ObjType>(
667
552
  ) {
668
553
  let dapp_key_str = type_info::get_type_name_string<DappKey>();
669
554
  error::dapp_key_mismatch(dapp_service::dapp_storage_dapp_key(dapp_storage) == dapp_key_str);
555
+ error::dapp_paused(!dapp_service::dapp_paused(dapp_storage));
670
556
 
671
557
  let type_tag = *dapp_service::object_storage_type(&storage); // &vector<u8> → copy
672
558
  let entity_id = *dapp_service::object_storage_entity_id(&storage); // same
@@ -1388,6 +1274,7 @@ public fun buy_record<DappKey: copy + drop, CoinType>(
1388
1274
  error::dapp_key_mismatch(dapp_service::listing_dapp_key(&listing) == dapp_key_str);
1389
1275
  error::dapp_key_mismatch(dapp_service::user_storage_dapp_key(buyer_storage) == dapp_key_str);
1390
1276
  error::dapp_key_mismatch(dapp_service::dapp_storage_dapp_key(dapp_storage) == dapp_key_str);
1277
+ error::dapp_paused(!dapp_service::dapp_paused(dapp_storage));
1391
1278
 
1392
1279
  // Buyer must own buyer_storage.
1393
1280
  error::no_permission(ctx.sender() == dapp_service::canonical_owner(buyer_storage));
@@ -1466,6 +1353,7 @@ public fun buy_fungible_record<DappKey: copy + drop, CoinType>(
1466
1353
  error::dapp_key_mismatch(dapp_service::listing_dapp_key(&listing) == dapp_key_str);
1467
1354
  error::dapp_key_mismatch(dapp_service::user_storage_dapp_key(buyer_storage) == dapp_key_str);
1468
1355
  error::dapp_key_mismatch(dapp_service::dapp_storage_dapp_key(dapp_storage) == dapp_key_str);
1356
+ error::dapp_paused(!dapp_service::dapp_paused(dapp_storage));
1469
1357
 
1470
1358
  error::no_permission(ctx.sender() == dapp_service::canonical_owner(buyer_storage));
1471
1359
  // Buyer must not be the seller (prevents self-trade exploits).
@@ -2195,6 +2083,7 @@ public fun update_marketplace_fee(
2195
2083
  /// Used by generated DApp buy functions to compute the fee to charge buyers.
2196
2084
  /// All DApps share the same global rate; there is no per-DApp override.
2197
2085
  public fun marketplace_fee_bps(dh: &DappHub): u64 {
2086
+ assert_framework_version(dh);
2198
2087
  dapp_service::marketplace_fee_bps(dapp_service::get_config(dh))
2199
2088
  }
2200
2089
 
@@ -2232,6 +2121,7 @@ public fun settle_marketplace_fee<DappKey: copy + drop, CoinType>(
2232
2121
  assert_framework_version(dh);
2233
2122
  let dapp_key_str = type_info::get_type_name_string<DappKey>();
2234
2123
  error::dapp_key_mismatch(dapp_service::dapp_storage_dapp_key(dapp_storage) == dapp_key_str);
2124
+ error::dapp_paused(!dapp_service::dapp_paused(dapp_storage));
2235
2125
 
2236
2126
  let total_fee = coin::value(&fee_coin);
2237
2127
  if (total_fee == 0) {
@@ -2535,6 +2425,7 @@ public fun update_framework_fee(
2535
2425
  /// sync_dapp_fee), not from this function. Use sync_dapp_fee after a pending fee
2536
2426
  /// change has been committed to propagate the new rates to each DApp.
2537
2427
  public fun get_effective_fees_at(dh: &DappHub, now_ms: u64): (u256, u256) {
2428
+ assert_framework_version(dh);
2538
2429
  let cfg = dapp_service::get_fee_config(dh);
2539
2430
  let effective_at = dapp_service::fee_effective_at_ms(cfg);
2540
2431
  let pb = dapp_service::pending_base_fee(cfg);
@@ -2553,6 +2444,7 @@ public fun get_effective_fees_at(dh: &DappHub, now_ms: u64): (u256, u256) {
2553
2444
 
2554
2445
  /// Return the current base-fee and bytes-fee without accounting for pending increases.
2555
2446
  public fun get_effective_fees(dh: &DappHub): (u256, u256) {
2447
+ assert_framework_version(dh);
2556
2448
  let cfg = dapp_service::get_fee_config(dh);
2557
2449
  (
2558
2450
  dapp_service::base_fee_per_write(cfg),
@@ -2821,6 +2713,9 @@ public fun ensure_not_paused<DappKey: copy + drop>(
2821
2713
 
2822
2714
  // ─── Utility ─────────────────────────────────────────────────────────────────
2823
2715
 
2716
+ /// Returns the canonical dapp key string for a given DappKey type.
2717
+ /// Convenience helper for DApp developers who need to reference their key string
2718
+ /// (e.g. for off-chain indexing or event filtering).
2824
2719
  public fun dapp_key<DappKey: copy + drop>(): String {
2825
2720
  type_name::with_defining_ids<DappKey>().into_string()
2826
2721
  }
@@ -3,7 +3,7 @@
3
3
  /// Covers the write_count / settled_count model (lazy settlement):
4
4
  /// write_count tracking: set_record increments, offchain/delete do not
5
5
  /// set_field increments write_count
6
- /// max_unsettled_writes guard (hardcoded constant MAX_UNSETTLED_WRITES=1000)
6
+ /// max_unsettled_writes guard (test harness write_limit=1_000; production default is 2_000)
7
7
  /// settle_writes full settlement (all unsettled writes charged)
8
8
  /// settle_writes skip when credit_pool == 0
9
9
  /// settle_writes partial settlement (limited by available credits)
@@ -184,7 +184,7 @@ fun test_set_record_aborts_at_max_unsettled_writes() {
184
184
  let ctx = test_scenario::ctx(&mut scenario);
185
185
  let mut us = new_us(ctx);
186
186
 
187
- // MAX_UNSETTLED_WRITES = 1000: fill exactly to the limit.
187
+ // write_limit = 1_000 in test harness (production default: 2_000); fill to the limit.
188
188
  let max_writes = 1000u64;
189
189
  let mut i = 0u64;
190
190
  while (i < max_writes) {
@@ -213,7 +213,7 @@ fun test_write_allowed_after_settlement_clears_debt() {
213
213
 
214
214
  let mut us = new_us(ctx);
215
215
 
216
- // Fill up to max: 1000 writes = MAX_UNSETTLED_WRITES.
216
+ // Fill up to test harness write_limit = 1_000 (production default: 2_000).
217
217
  let max_writes = 1000u64;
218
218
  let mut i = 0u64;
219
219
  while (i < max_writes) {