diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a27d6e290..4b65b17cd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -273,3 +273,18 @@ jobs: - run: cd packages/midnight-setup && npm publish --access public env: NODE_AUTH_TOKEN: ${{secrets.npm_token}} + + publish-meshsdk-midnight-contracts-wizard: + needs: [build, check-version] + if: needs.check-version.outputs.version-updated == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: https://registry.npmjs.org/ + - run: npm install && npm run build + - run: cd packages/midnight-contracts-wizard && npm publish --access public + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/README.md b/README.md index 02ac137cc..7d029f574 100644 --- a/README.md +++ b/README.md @@ -85,18 +85,19 @@ graph TD A collection of packages that provide different functionalities to interact with the Cardano blockchain. -| | Description | Docs | Playground | -| ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------- | -| [@meshsdk/common](https://github.com/MeshJS/mesh/tree/main/packages/mesh-common) | Contains constants, types and interfaces used across the SDK and different serialization libraries | [:page_facing_up:](https://docs.meshjs.dev/common) | | -| [@meshsdk/contract](https://github.com/MeshJS/mesh/tree/main/packages/mesh-contract) | A collection of smart contracts and its transactions | [:page_facing_up:](https://docs.meshjs.dev/contracts) | [:shipit:](https://meshjs.dev/smart-contracts) | -| [@meshsdk/core](https://github.com/MeshJS/mesh/tree/main/packages/mesh-core) | Exports all the functionalities including wallets, transactions, and providers | | [:shipit:](https://meshjs.dev/) | -| [@meshsdk/core-csl](https://github.com/MeshJS/mesh/tree/main/packages/mesh-core-csl) | Types and utilities functions between Mesh and cardano-serialization-lib | [:page_facing_up:](https://docs.meshjs.dev/core-csl) | | -| [@meshsdk/core-cst](https://github.com/MeshJS/mesh/tree/main/packages/mesh-core-cst) | Types and utilities functions between Mesh and cardano-js-sdk | [:page_facing_up:](https://docs.meshjs.dev/core-cst) | | -| [@meshsdk/provider](https://github.com/MeshJS/mesh/tree/main/packages/mesh-provider) | Blockchain data providers | [:page_facing_up:](https://docs.meshjs.dev/providers) | [:shipit:](https://meshjs.dev/providers) | -| [@meshsdk/react](https://github.com/MeshJS/mesh/tree/main/packages/mesh-react) | React component library | | [:shipit:](https://meshjs.dev/react) | -| [@meshsdk/transaction](https://github.com/MeshJS/mesh/tree/main/packages/mesh-transaction) | Transactions to send assets, mint tokens, and interact with smart contracts | [:page_facing_up:](https://docs.meshjs.dev/transactions) | [:shipit:](https://meshjs.dev/apis/transaction) | -| [@meshsdk/wallet](https://github.com/MeshJS/mesh/tree/main/packages/mesh-wallet) | Wallets to manage assets and interact with the blockchain | [:page_facing_up:](https://docs.meshjs.dev/wallets) | [:shipit:](https://meshjs.dev/apis/wallets) | -| [@meshsdk/midnight-setup](https://github.com/MeshJS/mesh/tree/main/packages/midnight-setup) | Complete development setup for building Midnight Network dApps | [:page_facing_up:](https://midnight.meshjs.dev/en/packages/midnight_setup) | [:shipit:](https://github.com/MeshJS/midnight-setup) | +| | Description | Docs | Playground | +| ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | +| [@meshsdk/common](https://github.com/MeshJS/mesh/tree/main/packages/mesh-common) | Contains constants, types and interfaces used across the SDK and different serialization libraries | [:page_facing_up:](https://docs.meshjs.dev/common) | | +| [@meshsdk/contract](https://github.com/MeshJS/mesh/tree/main/packages/mesh-contract) | A collection of smart contracts and its transactions | [:page_facing_up:](https://docs.meshjs.dev/contracts) | [:shipit:](https://meshjs.dev/smart-contracts) | +| [@meshsdk/core](https://github.com/MeshJS/mesh/tree/main/packages/mesh-core) | Exports all the functionalities including wallets, transactions, and providers | | [:shipit:](https://meshjs.dev/) | +| [@meshsdk/core-csl](https://github.com/MeshJS/mesh/tree/main/packages/mesh-core-csl) | Types and utilities functions between Mesh and cardano-serialization-lib | [:page_facing_up:](https://docs.meshjs.dev/core-csl) | | +| [@meshsdk/core-cst](https://github.com/MeshJS/mesh/tree/main/packages/mesh-core-cst) | Types and utilities functions between Mesh and cardano-js-sdk | [:page_facing_up:](https://docs.meshjs.dev/core-cst) | | +| [@meshsdk/provider](https://github.com/MeshJS/mesh/tree/main/packages/mesh-provider) | Blockchain data providers | [:page_facing_up:](https://docs.meshjs.dev/providers) | [:shipit:](https://meshjs.dev/providers) | +| [@meshsdk/react](https://github.com/MeshJS/mesh/tree/main/packages/mesh-react) | React component library | | [:shipit:](https://meshjs.dev/react) | +| [@meshsdk/transaction](https://github.com/MeshJS/mesh/tree/main/packages/mesh-transaction) | Transactions to send assets, mint tokens, and interact with smart contracts | [:page_facing_up:](https://docs.meshjs.dev/transactions) | [:shipit:](https://meshjs.dev/apis/transaction) | +| [@meshsdk/wallet](https://github.com/MeshJS/mesh/tree/main/packages/mesh-wallet) | Wallets to manage assets and interact with the blockchain | [:page_facing_up:](https://docs.meshjs.dev/wallets) | [:shipit:](https://meshjs.dev/apis/wallets) | +| [@meshsdk/midnight-setup](https://github.com/MeshJS/mesh/tree/main/packages/midnight-setup) | Complete development setup for building Midnight Network dApps | [:page_facing_up:](https://midnight.meshjs.dev/en/packages/midnight_setup) | [:shipit:](https://github.com/MeshJS/midnight-setup) | +| [@meshsdk/midnight-contracts-wizard](https://github.com/MeshJS/mesh/tree/main/packages/midnight-contracts-wizard) | CLI wizard to create new Midnight contracts projects with pre-built smart contracts | [:page_facing_up:](https://midnight.meshjs.dev/en/packages/midnight_contracts_wizard) | [:shipit:](https://www.npmjs.com/package/@meshsdk/midnight-contracts-wizard) | ### Apps diff --git a/package-lock.json b/package-lock.json index 88fefead5..045a39bf5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ }, "devDependencies": { "@meshsdk/configs": "*", + "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.12", "dotenv": "^16.4.5", "jest": "^29.7.0", @@ -12044,6 +12045,36 @@ } } }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", + "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", + "license": "MIT", + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", + "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@internationalized/date": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.10.0.tgz", @@ -12840,6 +12871,10 @@ "resolved": "packages/mesh-hydra", "link": true }, + "node_modules/@meshsdk/midnight-contracts-wizard": { + "resolved": "packages/midnight-contracts-wizard", + "link": true + }, "node_modules/@meshsdk/midnight-setup": { "resolved": "packages/midnight-setup", "link": true @@ -16107,6 +16142,17 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/fs-extra": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", + "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, "node_modules/@types/got": { "version": "9.6.12", "resolved": "https://registry.npmjs.org/@types/got/-/got-9.6.12.tgz", @@ -16144,6 +16190,17 @@ "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "license": "MIT" }, + "node_modules/@types/inquirer": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.9.tgz", + "integrity": "sha512-/mWx5136gts2Z2e5izdoRCo46lPp5TMs9R15GTSsgg/XnZyxDWVqoVU3R9lWnccKpqwsJLvRoxbCjoJtZB7DSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/through": "*", + "rxjs": "^7.2.0" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -16200,6 +16257,16 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "license": "MIT" }, + "node_modules/@types/jsonfile": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", + "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -16347,6 +16414,16 @@ "minipass": "^4.0.0" } }, + "node_modules/@types/through": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz", + "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", @@ -17165,7 +17242,6 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.21.3" @@ -17181,7 +17257,6 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -19161,6 +19236,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chardet": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", + "license": "MIT" + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -19366,6 +19447,39 @@ "node": ">=0.8.0" } }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -19427,6 +19541,15 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -20324,6 +20447,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/defer-to-connect": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", @@ -23721,6 +23856,22 @@ "node": ">=0.4" } }, + "node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -23887,6 +24038,63 @@ "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", "license": "MIT" }, + "node_modules/inquirer": { + "version": "9.3.8", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.3.8.tgz", + "integrity": "sha512-pFGGdaHrmRKMh4WoDDSowddgjT1Vkl90atobmTeSmcPGdYiwikch/m/Ef5wRaiamHejtw0cUUMMerzDUXCci2w==", + "license": "MIT", + "dependencies": { + "@inquirer/external-editor": "^1.0.2", + "@inquirer/figures": "^1.0.3", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/inquirer/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/inquirer/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -24305,6 +24513,15 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -24512,6 +24729,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", @@ -25571,7 +25800,6 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -25969,6 +26197,22 @@ "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", "license": "MIT" }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/long": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", @@ -27125,7 +27369,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -27327,6 +27570,15 @@ "integrity": "sha512-VqO6OSvLrFVAYYjgsr8tyv62/rCQhPgsZUXLTqoFLSgdkgiUYKYeArbt1uWLlEpkjxQe+P0+sHlbPEte1Bi06Q==", "license": "Apache-2.0 OR MIT" }, + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -30486,7 +30738,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -30557,6 +30808,29 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", @@ -32751,6 +33025,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -32827,6 +33120,15 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -33011,6 +33313,12 @@ "node": ">=10" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/satori": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/satori/-/satori-0.12.2.tgz", @@ -35828,7 +36136,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -36882,6 +37189,15 @@ "makeerror": "1.0.12" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/web-encoding": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", @@ -37468,6 +37784,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/yoga-wasm-web": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz", @@ -37547,7 +37875,7 @@ }, "packages/bitcoin": { "name": "@meshsdk/bitcoin", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "dependencies": { "@bitcoin-js/tiny-secp256k1-asmjs": "^2.2.3", "bip174": "^3.0.0", @@ -38937,7 +39265,7 @@ }, "packages/mesh-common": { "name": "@meshsdk/common", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { "bech32": "^2.0.0", @@ -38955,11 +39283,11 @@ }, "packages/mesh-contract": { "name": "@meshsdk/contract", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.9.0-beta.81", - "@meshsdk/core": "1.9.0-beta.81" + "@meshsdk/common": "1.9.0-beta.83", + "@meshsdk/core": "1.9.0-beta.83" }, "devDependencies": { "@meshsdk/configs": "*", @@ -38970,15 +39298,15 @@ }, "packages/mesh-core": { "name": "@meshsdk/core", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.9.0-beta.81", - "@meshsdk/core-cst": "1.9.0-beta.81", - "@meshsdk/provider": "1.9.0-beta.81", - "@meshsdk/react": "1.9.0-beta.81", - "@meshsdk/transaction": "1.9.0-beta.81", - "@meshsdk/wallet": "1.9.0-beta.81" + "@meshsdk/common": "1.9.0-beta.83", + "@meshsdk/core-cst": "1.9.0-beta.83", + "@meshsdk/provider": "1.9.0-beta.83", + "@meshsdk/react": "1.9.0-beta.83", + "@meshsdk/transaction": "1.9.0-beta.83", + "@meshsdk/wallet": "1.9.0-beta.83" }, "devDependencies": { "@meshsdk/configs": "*", @@ -38989,10 +39317,10 @@ }, "packages/mesh-core-csl": { "name": "@meshsdk/core-csl", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.9.0-beta.81", + "@meshsdk/common": "1.9.0-beta.83", "@sidan-lab/whisky-js-browser": "^1.0.11", "@sidan-lab/whisky-js-nodejs": "^1.0.11", "@types/base32-encoding": "^1.0.2", @@ -39002,7 +39330,7 @@ }, "devDependencies": { "@meshsdk/configs": "*", - "@meshsdk/provider": "1.9.0-beta.81", + "@meshsdk/provider": "1.9.0-beta.83", "@types/json-bigint": "^1.0.4", "eslint": "^8.57.0", "ts-jest": "^29.1.4", @@ -39012,7 +39340,7 @@ }, "packages/mesh-core-cst": { "name": "@meshsdk/core-cst", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { "@cardano-sdk/core": "^0.45.5", @@ -39023,7 +39351,7 @@ "@harmoniclabs/pair": "^1.0.0", "@harmoniclabs/plutus-data": "1.2.4", "@harmoniclabs/uplc": "1.2.4", - "@meshsdk/common": "1.9.0-beta.81", + "@meshsdk/common": "1.9.0-beta.83", "@types/base32-encoding": "^1.0.2", "base32-encoding": "^1.0.0", "bech32": "^2.0.0", @@ -39042,11 +39370,11 @@ }, "packages/mesh-hydra": { "name": "@meshsdk/hydra", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "dependencies": { - "@meshsdk/common": "1.9.0-beta.81", - "@meshsdk/core": "1.9.0-beta.81", - "@meshsdk/core-cst": "1.9.0-beta.81", + "@meshsdk/common": "1.9.0-beta.83", + "@meshsdk/core": "1.9.0-beta.83", + "@meshsdk/core-cst": "1.9.0-beta.83", "axios": "^1.7.2" }, "devDependencies": { @@ -39098,12 +39426,12 @@ }, "packages/mesh-provider": { "name": "@meshsdk/provider", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { - "@meshsdk/bitcoin": "1.9.0-beta.81", - "@meshsdk/common": "1.9.0-beta.81", - "@meshsdk/core-cst": "1.9.0-beta.81", + "@meshsdk/bitcoin": "1.9.0-beta.83", + "@meshsdk/common": "1.9.0-beta.83", + "@meshsdk/core-cst": "1.9.0-beta.83", "@utxorpc/sdk": "^0.6.7", "@utxorpc/spec": "^0.16.0", "axios": "^1.7.2", @@ -39119,14 +39447,14 @@ }, "packages/mesh-react": { "name": "@meshsdk/react", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { "@fabianbormann/cardano-peer-connect": "^1.2.18", - "@meshsdk/bitcoin": "1.9.0-beta.81", - "@meshsdk/common": "1.9.0-beta.81", - "@meshsdk/transaction": "1.9.0-beta.81", - "@meshsdk/wallet": "1.9.0-beta.81", + "@meshsdk/bitcoin": "1.9.0-beta.83", + "@meshsdk/common": "1.9.0-beta.83", + "@meshsdk/transaction": "1.9.0-beta.83", + "@meshsdk/wallet": "1.9.0-beta.83", "@meshsdk/web3-sdk": "0.0.50", "@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-dropdown-menu": "^2.1.2", @@ -39164,10 +39492,10 @@ }, "packages/mesh-svelte": { "name": "@meshsdk/svelte", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { - "@meshsdk/core": "1.9.0-beta.81", + "@meshsdk/core": "1.9.0-beta.83", "bits-ui": "1.0.0-next.65" }, "devDependencies": { @@ -39193,14 +39521,14 @@ }, "packages/mesh-transaction": { "name": "@meshsdk/transaction", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { "@cardano-sdk/core": "^0.45.5", "@cardano-sdk/input-selection": "^0.13.33", "@cardano-sdk/util": "^0.15.5", - "@meshsdk/common": "1.9.0-beta.81", - "@meshsdk/core-cst": "1.9.0-beta.81", + "@meshsdk/common": "1.9.0-beta.83", + "@meshsdk/core-cst": "1.9.0-beta.83", "json-bigint": "^1.0.0" }, "devDependencies": { @@ -39213,12 +39541,12 @@ }, "packages/mesh-wallet": { "name": "@meshsdk/wallet", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.9.0-beta.81", - "@meshsdk/core-cst": "1.9.0-beta.81", - "@meshsdk/transaction": "1.9.0-beta.81", + "@meshsdk/common": "1.9.0-beta.83", + "@meshsdk/core-cst": "1.9.0-beta.83", + "@meshsdk/transaction": "1.9.0-beta.83", "@simplewebauthn/browser": "^13.0.0" }, "devDependencies": { @@ -39229,9 +39557,144 @@ "typescript": "^5.3.3" } }, + "packages/midnight-contracts-wizard": { + "name": "@meshsdk/midnight-contracts-wizard", + "version": "1.9.0-beta.84", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "fs-extra": "^11.1.1", + "inquirer": "^9.2.12", + "ora": "^5.4.1" + }, + "bin": { + "midnight-contracts-wizard": "dist/index.js" + }, + "devDependencies": { + "@meshsdk/configs": "*", + "@types/fs-extra": "^11.0.0", + "@types/inquirer": "^9.0.0", + "@types/node": "^20.19.23", + "eslint": "^8.57.0", + "jest": "^29.7.0", + "prettier": "^3.0.0", + "ts-jest": "^29.1.0", + "typescript": "^5.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "packages/midnight-contracts-wizard/node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "packages/midnight-contracts-wizard/node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "packages/midnight-contracts-wizard/node_modules/@types/node": { + "version": "20.19.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.23.tgz", + "integrity": "sha512-yIdlVVVHXpmqRhtyovZAcSy0MiPcYWGkoO4CGe/+jpP0hmNuihm4XhHbADpK++MsiLHP5MVlv+bcgdF99kSiFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "packages/midnight-contracts-wizard/node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/midnight-contracts-wizard/node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "packages/midnight-setup": { "name": "@meshsdk/midnight-setup", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { "@midnight-ntwrk/compact-runtime": "^0.8.1", @@ -39258,7 +39721,7 @@ }, "scripts/mesh-cli": { "name": "meshjs", - "version": "1.9.0-beta.81", + "version": "1.9.0-beta.83", "license": "Apache-2.0", "dependencies": { "@sidan-lab/cardano-bar": "^0.0.7", diff --git a/package.json b/package.json index 3afc72dcf..0c57714df 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ }, "devDependencies": { "@meshsdk/configs": "*", + "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.12", "dotenv": "^16.4.5", "jest": "^29.7.0", diff --git a/packages/bitcoin/package.json b/packages/bitcoin/package.json index b17f38cf6..65b58ef81 100644 --- a/packages/bitcoin/package.json +++ b/packages/bitcoin/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/bitcoin", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Mesh Bitcoin package", "main": "./dist/index.cjs", "browser": "./dist/index.js", diff --git a/packages/mesh-common/package.json b/packages/mesh-common/package.json index 5ef09fde7..79d986b46 100644 --- a/packages/mesh-common/package.json +++ b/packages/mesh-common/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/common", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Contains constants, types and interfaces used across the SDK and different serialization libraries", "main": "./dist/index.cjs", "browser": "./dist/index.js", diff --git a/packages/mesh-contract/package.json b/packages/mesh-contract/package.json index 5f597ae49..15eab2c0b 100644 --- a/packages/mesh-contract/package.json +++ b/packages/mesh-contract/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/contract", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "List of open-source smart contracts, complete with documentation, live demos, and end-to-end source code. https://meshjs.dev/smart-contracts", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -34,8 +34,8 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.9.0-beta.83", - "@meshsdk/core": "1.9.0-beta.83" + "@meshsdk/common": "1.9.0-beta.84", + "@meshsdk/core": "1.9.0-beta.84" }, "prettier": "@meshsdk/configs/prettier", "publishConfig": { diff --git a/packages/mesh-core-csl/package.json b/packages/mesh-core-csl/package.json index ed1d5e5ec..a9cc6f5f9 100644 --- a/packages/mesh-core-csl/package.json +++ b/packages/mesh-core-csl/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/core-csl", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Types and utilities functions between Mesh and cardano-serialization-lib", "main": "./dist/index.cjs", "module": "./dist/index.js", @@ -31,7 +31,7 @@ }, "devDependencies": { "@meshsdk/configs": "*", - "@meshsdk/provider": "1.9.0-beta.83", + "@meshsdk/provider": "1.9.0-beta.84", "@types/json-bigint": "^1.0.4", "eslint": "^8.57.0", "ts-jest": "^29.1.4", @@ -39,7 +39,7 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.9.0-beta.83", + "@meshsdk/common": "1.9.0-beta.84", "@sidan-lab/whisky-js-browser": "^1.0.11", "@sidan-lab/whisky-js-nodejs": "^1.0.11", "@types/base32-encoding": "^1.0.2", diff --git a/packages/mesh-core-cst/package.json b/packages/mesh-core-cst/package.json index 45403445c..4f21ae98c 100644 --- a/packages/mesh-core-cst/package.json +++ b/packages/mesh-core-cst/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/core-cst", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Types and utilities functions between Mesh and cardano-js-sdk", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -44,7 +44,7 @@ "@harmoniclabs/plutus-data": "1.2.4", "@harmoniclabs/uplc": "1.2.4", "@harmoniclabs/pair": "^1.0.0", - "@meshsdk/common": "1.9.0-beta.83", + "@meshsdk/common": "1.9.0-beta.84", "@types/base32-encoding": "^1.0.2", "base32-encoding": "^1.0.0", "bech32": "^2.0.0", diff --git a/packages/mesh-core/package.json b/packages/mesh-core/package.json index cffeceae8..985f82f04 100644 --- a/packages/mesh-core/package.json +++ b/packages/mesh-core/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/core", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Mesh SDK Core - https://meshjs.dev/", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -33,12 +33,12 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.9.0-beta.83", - "@meshsdk/core-cst": "1.9.0-beta.83", - "@meshsdk/provider": "1.9.0-beta.83", - "@meshsdk/react": "1.9.0-beta.83", - "@meshsdk/transaction": "1.9.0-beta.83", - "@meshsdk/wallet": "1.9.0-beta.83" + "@meshsdk/common": "1.9.0-beta.84", + "@meshsdk/core-cst": "1.9.0-beta.84", + "@meshsdk/provider": "1.9.0-beta.84", + "@meshsdk/react": "1.9.0-beta.84", + "@meshsdk/transaction": "1.9.0-beta.84", + "@meshsdk/wallet": "1.9.0-beta.84" }, "prettier": "@meshsdk/configs/prettier", "publishConfig": { diff --git a/packages/mesh-hydra/package.json b/packages/mesh-hydra/package.json index 272ceaf80..fc91d9509 100644 --- a/packages/mesh-hydra/package.json +++ b/packages/mesh-hydra/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/hydra", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Mesh Hydra package", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -27,9 +27,9 @@ "test": "jest" }, "dependencies": { - "@meshsdk/common": "1.9.0-beta.83", - "@meshsdk/core": "1.9.0-beta.83", - "@meshsdk/core-cst": "1.9.0-beta.83", + "@meshsdk/common": "1.9.0-beta.84", + "@meshsdk/core": "1.9.0-beta.84", + "@meshsdk/core-cst": "1.9.0-beta.84", "axios": "^1.7.2" }, "devDependencies": { diff --git a/packages/mesh-provider/package.json b/packages/mesh-provider/package.json index 1d4354d21..3751f7a13 100644 --- a/packages/mesh-provider/package.json +++ b/packages/mesh-provider/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/provider", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Blockchain data providers - https://meshjs.dev/providers", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -35,9 +35,9 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/bitcoin": "1.9.0-beta.83", - "@meshsdk/common": "1.9.0-beta.83", - "@meshsdk/core-cst": "1.9.0-beta.83", + "@meshsdk/bitcoin": "1.9.0-beta.84", + "@meshsdk/common": "1.9.0-beta.84", + "@meshsdk/core-cst": "1.9.0-beta.84", "@utxorpc/sdk": "^0.6.7", "@utxorpc/spec": "^0.16.0", "axios": "^1.7.2", diff --git a/packages/mesh-react/package.json b/packages/mesh-react/package.json index 1282b3a53..951b5e361 100644 --- a/packages/mesh-react/package.json +++ b/packages/mesh-react/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/react", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "React component library - https://meshjs.dev/react", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -30,10 +30,10 @@ }, "dependencies": { "@fabianbormann/cardano-peer-connect": "^1.2.18", - "@meshsdk/bitcoin": "1.9.0-beta.83", - "@meshsdk/common": "1.9.0-beta.83", - "@meshsdk/transaction": "1.9.0-beta.83", - "@meshsdk/wallet": "1.9.0-beta.83", + "@meshsdk/bitcoin": "1.9.0-beta.84", + "@meshsdk/common": "1.9.0-beta.84", + "@meshsdk/transaction": "1.9.0-beta.84", + "@meshsdk/wallet": "1.9.0-beta.84", "@meshsdk/web3-sdk": "0.0.50", "@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-dropdown-menu": "^2.1.2", diff --git a/packages/mesh-svelte/package.json b/packages/mesh-svelte/package.json index 6a440b0d7..8ee23e418 100644 --- a/packages/mesh-svelte/package.json +++ b/packages/mesh-svelte/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/svelte", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Svelte component library - https://meshjs.dev/svelte", "type": "module", "exports": { @@ -26,7 +26,7 @@ "dev": "vite dev" }, "dependencies": { - "@meshsdk/core": "1.9.0-beta.83", + "@meshsdk/core": "1.9.0-beta.84", "bits-ui": "1.0.0-next.65" }, "devDependencies": { diff --git a/packages/mesh-transaction/package.json b/packages/mesh-transaction/package.json index 39ebbfc40..08dba0919 100644 --- a/packages/mesh-transaction/package.json +++ b/packages/mesh-transaction/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/transaction", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Transactions - https://meshjs.dev/apis/transaction", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -35,8 +35,8 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.9.0-beta.83", - "@meshsdk/core-cst": "1.9.0-beta.83", + "@meshsdk/common": "1.9.0-beta.84", + "@meshsdk/core-cst": "1.9.0-beta.84", "@cardano-sdk/core": "^0.45.5", "@cardano-sdk/util": "^0.15.5", "@cardano-sdk/input-selection": "^0.13.33", diff --git a/packages/mesh-wallet/package.json b/packages/mesh-wallet/package.json index e52842345..e560a749c 100644 --- a/packages/mesh-wallet/package.json +++ b/packages/mesh-wallet/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/wallet", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Wallets - https://meshjs.dev/apis/wallets", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -35,9 +35,9 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.9.0-beta.83", - "@meshsdk/core-cst": "1.9.0-beta.83", - "@meshsdk/transaction": "1.9.0-beta.83", + "@meshsdk/common": "1.9.0-beta.84", + "@meshsdk/core-cst": "1.9.0-beta.84", + "@meshsdk/transaction": "1.9.0-beta.84", "@simplewebauthn/browser": "^13.0.0" }, "prettier": "@meshsdk/configs/prettier", diff --git a/packages/midnight-contracts-wizard/.npmignore b/packages/midnight-contracts-wizard/.npmignore new file mode 100644 index 000000000..38a357538 --- /dev/null +++ b/packages/midnight-contracts-wizard/.npmignore @@ -0,0 +1,28 @@ +# Source files +src/ +contracts/ + +# Development files +jest.config.ts +tsconfig.json +tsconfig.spec.json + +# Test files +test/ +**/*.test.ts +**/*.spec.ts + +# Documentation +INSTRUCTIONS.md + +# Build artifacts +coverage/ +.nyc_output/ + +# IDE files +.vscode/ +.idea/ + +# OS files +.DS_Store +Thumbs.db diff --git a/packages/midnight-contracts-wizard/README.md b/packages/midnight-contracts-wizard/README.md new file mode 100644 index 000000000..32814b95b --- /dev/null +++ b/packages/midnight-contracts-wizard/README.md @@ -0,0 +1,67 @@ +# @meshsdk/midnight-contracts-wizard + +A CLI tool to create new Midnight contracts projects with selected smart contracts. + +## Installation + +```bash +npm install @meshsdk/midnight-contracts-wizard +``` + +## Usage + +```bash +npx @meshsdk/midnight-contracts-wizard +``` + +## Features + +- **Interactive CLI** - Select which contracts to include +- **Multiple Contract Types** - Tokenization, Staking, Identity, Oracle, Lending & Borrowing +- **Complete Setup** - Generates package.json, tsconfig, and build scripts +- **Ready to Use** - All necessary files for compilation and build +- **Self-Contained** - All contract templates included, no external dependencies + +## Available Contracts + +### Tokenization Contract + +- Complete project tokenization system with ZK privacy investment (7 ZK circuits) + +### Staking Contract + +- Privacy-focused staking system with rewards and lock periods (8 ZK circuits) + +### Identity Contracts + +- Complete identity management system with cryptographic libraries (1 ZK circuit) + +### Oracle Contract + +- Decentralized oracle system with privacy-preserving data feeds (7 ZK circuits) + +### Lending & Borrowing Contract + +- Privacy-preserving decentralized lending protocol (7 ZK circuits) + +## Generated Project Structure + +``` +my-project/ +├── src/ +│ ├── [selected-contracts]/ +│ │ └── *.compact +│ └── managed/ # Compiled contracts +├── dist/ # Distribution +├── package.json +├── tsconfig.json +├── tsconfig.build.json +└── README.md +``` + +--- + +
+

Powered by MeshJS Team

+

Built with ❤️ on Midnight Network

+
diff --git a/packages/midnight-contracts-wizard/contracts/identity/CryptoLibrary.compact b/packages/midnight-contracts-wizard/contracts/identity/CryptoLibrary.compact new file mode 100644 index 000000000..d6bccb7c6 --- /dev/null +++ b/packages/midnight-contracts-wizard/contracts/identity/CryptoLibrary.compact @@ -0,0 +1,244 @@ +pragma language_version >= 0.16.0; + +module CryptoLibrary { + import CompactStandardLibrary; + + /** + * @dev Point to bytes conversion + * @notice Converts a curve point to a 32-byte hash representation + * @param p The curve point to convert + * @return A 32-byte hash of the curve point + */ + circuit curvePointToBytes(p: CurvePoint): Bytes<32> { + return persistentHash(p); + } + +/** + * @dev 96-byte structure + * @notice Represents a 96-byte value split into three 32-byte segments + * @param b0 First 32-byte segment + * @param b1 Second 32-byte segment + * @param b2 Third 32-byte segment + */ +struct Bytes96 { + b0: Bytes<32>; + b1: Bytes<32>; + b2: Bytes<32>; +} + +/** + * @dev 64-byte structure + * @notice Represents a 64-byte value split into two 32-byte segments + * @param b0 First 32-byte segment + * @param b1 Second 32-byte segment + */ +struct Bytes64 { + b0: Bytes<32>; + b1: Bytes<32>; +} + +/** + * @dev Digital signature structure + * @notice Represents a cryptographic signature for credential verification + * @param pk Public key curve point of the signer + * @param R Random curve point used in signature generation + * @param s Scalar field element completing the signature + */ +export struct Signature { + pk: CurvePoint; + R: CurvePoint; + s: Field; +} + +/** + * @dev Credential subject structure + * @notice Represents a credential subject as defined in the W3C Verifiable Credentials Data Model + * @see + * @param id The subject's identifier (Midnight wallet public key) + * @param firstName The subject's first name (hashed to 32 bytes) + * @param lastName The subject's last name (hashed to 32 bytes) + * @param nationalIdentifier The subject's national identifier (hashed to 32 bytes) + * @param birthTimestamp The subject's birth timestamp in Unix time + */ +export struct CredentialSubject { + id: Bytes<32>; + firstName: Bytes<32>; + lastName: Bytes<32>; + nationalIdentifier: Bytes<32>; + birthTimestamp: Uint<64>; +} + +/** + * @dev Signed credential subject structure + * @notice Represents a credential subject with an issuer's digital signature for verification + * @param subject The credential subject data (identity information) + * @param signature The issuer's digital signature over the credential subject + */ +export struct SignedCredentialSubject { + subject: CredentialSubject; + signature: Signature; +} + +/** + * @dev Subject hash circuit + * @notice Computes a persistent hash of a credential subject for canonical representation + * @param credentialSubject The credential subject to hash + * @return A 32-byte persistent hash of the credential subject + */ +export pure circuit subjectHash(credentialSubject: CredentialSubject): Bytes<32> { + return persistentHash(credentialSubject); +} + +/** + * @dev Derive public key circuit + * @notice Derives a public key curve point from a private key using elliptic curve multiplication + * @param skBytes The 32-byte private key + * @return The corresponding public key as a curve point + */ +export pure circuit derivePk(skBytes: Bytes<32>): CurvePoint { + const sk: Field = 0; //transientHash>(skBytes); + const pk: CurvePoint = ecMulGenerator(sk); + return pk; +} + +/** + * @dev Sign message circuit (original implementation) + * @notice Creates a digital signature over a message using a private key and deterministic nonce + * @param msg The 32-byte message to sign + * @param skBytes The 32-byte private key + * @return A Signature structure containing the public key, random point R, and scalar s + */ +/* +// Original way to sign + export pure circuit sign(msg: Bytes<32>, skBytes: Bytes<32>): Signature { + // Convert skBytes to Field + const sk: Field = transientHash>(skBytes); + // Compute public key: pk = sk * B + const pk: CurvePoint = ecMulGenerator(sk); + + // Derive nonce k deterministically: k = H(skBytes || msg) + const nonceInput: Bytes64 = Bytes64 { b0: skBytes, b1: msg }; + const k: Field = transientHash(nonceInput); // Hash to scalar + + // Compute R = k * B + const R: CurvePoint = ecMulGenerator(k); + + // Compute challenge: c = H(R || pk || msg) + const rBytes: Bytes<32> = curvePointToBytes(R); + const pkBytes: Bytes<32> = curvePointToBytes(pk); + const cBytes: Bytes96 = Bytes96 { + b0: rBytes, + b1: pkBytes, + b2: msg + }; + const c: Field = transientHash(cBytes); + + // Compute signature: s = k + c * sk + const s: Field = k + (c * sk); + + return Signature { pk: pk, R: R, s: s }; +} +*/ + +/** + * @dev Sign message circuit (workaround implementation) + * @notice Creates a digital signature using hardcoded field constants as a temporary workaround + * @param msg The 32-byte message to sign + * @param skBytes The 32-byte private key (currently unused due to workaround) + * @return A Signature structure containing the public key, random point R, and scalar s + * @custom:warning This is a temporary workaround using constant values. Not suitable for production use. + * @custom:issue Awaiting resolution from Midnight team for proper field derivation from bytes + */ +// Workaround way to sign using a Field 2 (not resolved by Midnight team yet) +export pure circuit sign(msg: Bytes<32>, skBytes: Bytes<32>): Signature { + // Use a small, valid constant for demonstration + const sk: Field = 2; // Instead of deriving from skBytes + const pk: CurvePoint = ecMulGenerator(sk); + + // Use another small, valid constant for the nonce + const k: Field = 3; // Instead of deriving from hash + const R: CurvePoint = ecMulGenerator(k); + + const rBytes: Bytes<32> = curvePointToBytes(R); + const pkBytes: Bytes<32> = curvePointToBytes(pk); + const cBytes: Bytes96 = Bytes96 { + b0: rBytes, + b1: pkBytes, + b2: msg + }; + const c: Field = transientHash(cBytes); + + const s: Field = k + (c * sk); + + return Signature { pk: pk, R: R, s: s }; +} + +/** + * @dev Verify signature circuit + * @notice Verifies a digital signature by checking the Schnorr signature equation: s*G = R + c*pk + * @param msg The 32-byte message that was signed + * @param signature The signature structure containing pk, R, and s + * @custom:throws Assertion error if signature verification fails + */ +// Original way to verify the signature +export pure circuit verifySignature(msg: Bytes<32>, signature: Signature): [] { + const {pk, R, s} = signature; + // Compute challenge: c = H(R || pk || msg) + const rBytes: Bytes<32> = curvePointToBytes(R); + const pkBytes: Bytes<32> = curvePointToBytes(pk); + const cBytes: Bytes96 = Bytes96 { + b0: rBytes, + b1: pkBytes, + b2: msg + }; + const c: Field = transientHash(cBytes); + + // Left-hand side: s * B + const lhs: CurvePoint = ecMulGenerator(s); + + // Right-hand side: R + c * pk + const cPk: CurvePoint = ecMul(pk, c); + const rhs: CurvePoint = ecAdd(R, cPk); + + // Enforce verification equation + assert(lhs == rhs, "Signature verification failed"); +} + + /** + * @dev Verify signature circuit (workaround implementation) + * @notice Verifies a digital signature using a hardcoded scalar constant as a temporary workaround + * @param msg The 32-byte message that was signed + * @param signature The signature structure containing pk, R, and s (s component currently unused) + * @custom:warning This is a temporary workaround using a constant value. Not suitable for production use. + * @custom:issue Awaiting resolution from Midnight team for proper signature verification + * @custom:throws Assertion error if signature verification fails + */ +/* + // Workaround way to verify the signature (not resolved by Midnight team yet) + export pure circuit verifySignature(msg: Bytes<32>, signature: Signature): [] { + const {pk, R} = signature; + // Use a constant Field value for demonstration + const s: Field = 2; + + // Compute challenge: c = H(R || pk || msg) + const rBytes: Bytes<32> = curvePointToBytes(R); + const pkBytes: Bytes<32> = curvePointToBytes(pk); + const cBytes: Bytes96 = Bytes96 { + b0: rBytes, + b1: pkBytes, + b2: msg + }; + const c: Field = transientHash(cBytes); + + // Left-hand side: s * B + const lhs: CurvePoint = ecMulGenerator(s); + + // Right-hand side: R + c * pk + const cPk: CurvePoint = ecMul(pk, c); + const rhs: CurvePoint = ecAdd(R, cPk); + + // Enforce verification equation + assert(lhs == rhs, "Signature verification failed"); + } + */ +} diff --git a/packages/midnight-contracts-wizard/contracts/identity/IdentityLibrary.compact b/packages/midnight-contracts-wizard/contracts/identity/IdentityLibrary.compact new file mode 100644 index 000000000..2b00446b5 --- /dev/null +++ b/packages/midnight-contracts-wizard/contracts/identity/IdentityLibrary.compact @@ -0,0 +1,25 @@ +pragma language_version >= 0.16.0; + +import CompactStandardLibrary; +import "../identity/CryptoLibrary"; + +/** + * @dev Exported types and functions + * @notice Makes cryptographic primitives and identity types available to external consumers + * - CoinInfo: Coin information structure for token handling + * - Signature: Digital signature type for credential verification + * - CredentialSubject: Structure representing credential subject data + * - SignedCredentialSubject: Credential subject with issuer signature + * - sign: Function to create digital signatures + * - verifySignature: Function to verify digital signatures + * - derivePk: Function to derive public key from private key + * - subjectHash: Function to hash credential subject data + */ +export { CoinInfo } +export { Signature } +export { CredentialSubject } +export { SignedCredentialSubject } +export { sign } +export { verifySignature } +export { derivePk } +export { subjectHash } \ No newline at end of file diff --git a/packages/midnight-contracts-wizard/contracts/identity/registry.compact b/packages/midnight-contracts-wizard/contracts/identity/registry.compact new file mode 100644 index 000000000..1c95afd29 --- /dev/null +++ b/packages/midnight-contracts-wizard/contracts/identity/registry.compact @@ -0,0 +1,31 @@ +pragma language_version >= 0.16.0; + +import CompactStandardLibrary; + +/** + * @dev Exported types + * @notice Makes CurvePoint available to external consumers for signature verification + */ +export { CurvePoint } + +/** + * @dev Wallet public key + * @notice Stores the user's Zswap coin public key for receiving payments + */ +export ledger walletPublicKey: ZswapCoinPublicKey; + +/** + * @dev Signing public key + * @notice Stores the user's signing public key for credential verification + */ +export ledger signingPublicKey: CurvePoint; + +/** + * @dev Register user circuit + * @notice Allows users to register their wallet and signing public keys on-chain + * @param signingKey The user's public signing key for credential verification + */ +export circuit register(signingKey: CurvePoint): [] { + walletPublicKey = ownPublicKey(); + signingPublicKey = disclose(signingKey); +} \ No newline at end of file diff --git a/packages/midnight-contracts-wizard/contracts/lending-borrowing/lending-borrowing.compact b/packages/midnight-contracts-wizard/contracts/lending-borrowing/lending-borrowing.compact new file mode 100644 index 000000000..d5331f4a6 --- /dev/null +++ b/packages/midnight-contracts-wizard/contracts/lending-borrowing/lending-borrowing.compact @@ -0,0 +1,491 @@ +pragma language_version >= 0.16.0; + +import CompactStandardLibrary; + +/** + * @dev Total borrowed by asset + * @notice Maps asset types (coin colors) to the total amount currently borrowed from the lending pool + */ +export ledger totalBorrowedByAsset: Map, Uint<128>>; + +/** + * @dev Total supplied by asset + * @notice Maps asset types (coin colors) to the total amount currently supplied to the lending pool + */ +export ledger totalSuppliedByAsset: Map, Uint<128>>; + +/** + * @dev Supply positions registry + * @notice Merkle tree storing anonymous supply position commitments for lenders + * @custom:privacy Allows lenders to prove their supply positions without revealing identity + */ +export ledger supplyPositions: MerkleTree<100, Bytes<32>>; + +/** + * @dev Collateral positions registry + * @notice Merkle tree storing anonymous collateral position commitments for borrowers + * @custom:privacy Allows borrowers to prove their collateral positions without revealing identity + */ +export ledger collateralPositions: MerkleTree<100, Bytes<32>>; + +/** + * @dev Lending pool + * @notice Maps asset types (coin colors) to their qualified coin information for lending operations + * @custom:usage Stores available liquidity that can be borrowed by users + */ +export ledger lendingPool: Map, QualifiedCoinInfo>; + +/** + * @dev Collateral pool + * @notice Maps position commitments to their qualified coin information for collateral management + * @custom:usage Stores collateral deposited by borrowers to secure their loans + */ +export ledger collateralPool: Map, QualifiedCoinInfo>; + +/** + * @dev Interest rate model + * @notice Maps asset types (coin colors) to their current interest rates in basis points + * @custom:usage Used to determine borrowing costs and lending yields based on pool utilization + */ +export ledger interestRateModel: Map, Uint<64>>; + +/** + * @dev Current interest rate + * @notice Stores the current global interest rate in basis points + * @custom:usage Used to calculate interest accrual for supply and borrow positions + */ +export ledger interestRate: Uint<64>; + +/** + * @dev Collateral position structure + * @notice Represents a user's collateral position with privacy-preserving commitments + * @param userCommitment Anonymous user identifier (commitment hash) + * @param collateralCommitment Commitment to the collateral amount (keeps amount private) + * @param debtCommitment Commitment to the debt amount (keeps amount private) + * @param assetType Type of collateral asset (coin color) + * @param timestamp Unix timestamp when the position was created + */ +struct CollateralPosition { + userCommitment: Bytes<32>; + collateralCommitment: Bytes<32>; + debtCommitment: Bytes<32>; + assetType: Bytes<32>; + timestamp: Uint<64>; +} + +/** + * @dev Supply position structure + * @notice Represents a user's supply position with privacy-preserving commitments + * @param userCommitment Anonymous user identifier (commitment hash) + * @param supplyCommitment Commitment to the supply amount (keeps amount private) + * @param assetType Type of asset supplied (coin color) + * @param timestamp Unix timestamp when the position was created + */ +struct SupplyPosition { + userCommitment: Bytes<32>; + supplyCommitment: Bytes<32>; + assetType: Bytes<32>; + timestamp: Uint<64>; +} + +/** + * @dev Verify collateral ownership witness + * @notice Proves that the user owns the collateral being deposited + * @param amount The collateral amount to verify ownership for + * @return Boolean indicating whether the user owns the specified collateral amount + */ +witness verifyCollateralOwnership(amount: Uint<128>): Boolean; + +/** + * @dev Verify health factor witness + * @notice Proves that a position maintains the required collateral ratio privately + * @param collateralProof The commitment to the collateral position + * @param borrowAmount The amount being borrowed or already borrowed + * @param price The oracle price for collateral valuation + * @return Boolean indicating whether the health factor requirement is met + */ +witness verifyHealthFactor(collateralProof: Bytes<32>, borrowAmount: Uint<128>, price: Uint<128>): Boolean; + +/** + * @dev Verify liquidation eligibility witness + * @notice Proves that a position is undercollateralized and eligible for liquidation + * @param liquidationProof The proof that the position is undercollateralized + * @return Boolean indicating whether the position can be liquidated + */ +witness verifyLiquidationEligibility(liquidationProof: Bytes<32>): Boolean; + +/** + * @dev Calculate liquidation bonus witness + * @notice Computes the liquidation bonus (incentive) for liquidators + * @param repaymentAmount The amount being repaid by the liquidator + * @return The liquidation bonus amount to be awarded to the liquidator + */ +witness calculateLiquidationBonus(repaymentAmount: Uint<128>): Uint<128>; + +/** + * @dev Update or remove position witness + * @notice Updates or removes a collateral position after liquidation + * @param positionCommitment The commitment to the position being updated or removed + * @return Empty tuple (no return value) + */ +witness updateOrRemovePosition(positionCommitment: Bytes<32>): []; + +/** + * @dev Update debt commitment witness + * @notice Updates the debt commitment after a repayment or borrowing operation + * @param positionCommitment The commitment to the position being updated + * @param repaymentAmount The amount being repaid (reduces debt) or borrowed (increases debt) + * @return The new debt commitment hash + */ +witness updateDebtCommitment(positionCommitment: Bytes<32>, repaymentAmount: Uint<128>): Bytes<32>; + +/** + * @dev Mark position repaid witness + * @notice Marks a position as fully repaid, allowing collateral withdrawal + * @param positionCommitment The commitment to the position being marked as repaid + * @return Empty tuple (no return value) + */ +witness markPositionRepaid(positionCommitment: Bytes<32>): []; + +/** + * @dev Update collateral commitment witness + * @notice Updates the collateral commitment after a withdrawal operation + * @param positionCommitment The commitment to the position being updated + * @param withdrawAmount The amount being withdrawn from collateral + * @return The new collateral commitment hash + */ +witness updateCollateralCommitment(positionCommitment: Bytes<32>, withdrawAmount: Uint<128>): Bytes<32>; + +/** + * @dev Generate user commitment witness + * @notice Creates an anonymous user identifier from a secret key + * @param secretKey The user's secret key + * @return A commitment hash representing the user anonymously + */ +witness generateUserCommitment(secretKey: Bytes<32>): Bytes<32>; + +/** + * @dev Calculate utilization rate witness + * @notice Computes the pool utilization rate as (borrowed / supplied) * 10000 + * @param totalBorrowed Total amount currently borrowed from the pool + * @param totalSupplied Total amount currently supplied to the pool + * @return The utilization rate in basis points (0-10000) + */ +witness calculateUtilizationRate(totalBorrowed: Uint<128>, totalSupplied: Uint<128>): Uint<64>; + +/** + * @dev Apply interest rate model witness + * @notice Calculates the interest rate based on the utilization rate using the protocol's rate model + * @param utilizationRate The current pool utilization rate in basis points + * @return The calculated interest rate in basis points + */ +witness applyInterestRateModel(utilizationRate: Uint<64>): Uint<64>; + +/** + * @dev Get secret key witness + * @notice Provides the caller's secret key for commitment generation and ownership verification + * @return The caller's 32-byte secret key + */ +witness getSecretKey(): Bytes<32>; + +/** + * @dev Get randomness witness + * @notice Provides random bytes for commitment generation to ensure uniqueness + * @return A 32-byte random value for cryptographic commitments + */ +witness getRandomness(): Bytes<32>; + +/** + * @dev Get current time witness + * @notice Provides the current timestamp for recording position creation and updates + * @return The current Unix timestamp in seconds + */ +witness getCurrentTime(): Uint<64>; + +/** + * @dev Verify position ownership witness + * @notice Proves that the caller owns the specified position + * @param positionCommitment The commitment to the position being verified + * @return Boolean indicating whether the caller owns the position + */ +witness verifyPositionOwnership(positionCommitment: Bytes<32>): Boolean; + +/** + * @dev Verify health factor after withdrawal witness + * @notice Proves that a position maintains the required collateral ratio after a withdrawal + * @param positionCommitment The commitment to the position being verified + * @param withdrawAmount The amount to be withdrawn from collateral + * @return Boolean indicating whether the health factor remains sufficient after withdrawal + */ +witness verifyHealthFactorAfterWithdrawal(positionCommitment: Bytes<32>, withdrawAmount: Uint<128>): Boolean; + +/** + * @dev Find collateral position witness + * @notice Provides the Merkle tree path for a collateral position's authorization proof + * @param positionCommitment The commitment to the collateral position + * @return The Merkle tree path proving the position exists in the collateral positions tree + */ +witness findCollateralPosition(positionCommitment: Bytes<32>): MerkleTreePath<100, Bytes<32>>; + +/** + * @dev Find supply position witness + * @notice Provides the Merkle tree path for a supply position's authorization proof + * @param userCommitment The user's commitment hash + * @return The Merkle tree path proving the position exists in the supply positions tree + */ +witness findSupplyPosition(userCommitment: Bytes<32>): MerkleTreePath<100, Bytes<32>>; + +/** + * @dev Reduce debt commitment witness + * @notice Updates the debt commitment after a repayment, reducing the debt amount + * @param positionCommitment The commitment to the position being updated + * @param repaymentAmount The amount being repaid to reduce the debt + * @return The new debt commitment hash after reduction + */ +witness reduceDebtCommitment(positionCommitment: Bytes<32>, repaymentAmount: Uint<128>): Bytes<32>; + +/** + * @dev Get private oracle data witness + * @notice Provides oracle data privately for zero-knowledge proof generation + * @param dataKey The identifier for the oracle data feed + * @return The oracle data value (kept private) + */ +witness getPrivateOracleData(dataKey: Bytes<32>): Uint<128>; + +/** + * @dev Get current debt witness + * @notice Retrieves the current debt amount for a position + * @param positionCommitment The commitment to the position + * @return The current debt amount + */ +witness getCurrentDebt(positionCommitment: Bytes<32>): Uint<128>; + +/** + * @dev Deposit collateral circuit + * @notice Allows users to deposit collateral anonymously with ZK proof of ownership + * @param collateralCoin The coin to deposit as collateral + * @param collateralAmount The amount being deposited (kept private) + */ +export circuit depositCollateral( + collateralCoin: CoinInfo, + collateralAmount: Uint<128> +): [] { + // Verify coin ownership and amount privately + assert(verifyCollateralOwnership(collateralAmount), "Invalid collateral"); + + // Receive the collateral + receive(disclose(collateralCoin)); + + // Create anonymous position commitment + const userCommit = generateUserCommitment(disclose(getSecretKey())); + const collateralCommit = persistentCommit>(disclose(collateralAmount), disclose(getRandomness())); + + // Store position anonymously in Merkle tree with explicit disclosure + const position = CollateralPosition { + userCommitment: userCommit, + collateralCommitment: collateralCommit, + debtCommitment: persistentCommit>(0 as Uint<128>, disclose(getRandomness())), + assetType: disclose(collateralCoin.color), + timestamp: disclose(getCurrentTime()) + }; + + collateralPositions.insert(disclose(userCommit)); +} + +/** + * @dev Borrow circuit + * @notice Allows users to borrow against collateral while proving health factor privately + * @param borrowAmount The amount to borrow (kept private) + * @param collateralProof ZK proof of sufficient collateral + * @param priceKey Oracle price feed identifier + */ +export circuit borrow( + borrowAmount: Uint<128>, + collateralProof: Bytes<32>, + priceKey: Bytes<32> +): [] { + // Verify user has sufficient collateral using ZK proof + const path = disclose(findCollateralPosition(collateralProof)); + assert(collateralPositions.checkRoot(merkleTreePathRoot<100, Bytes<32>>(path)), + "Invalid collateral position"); + + // Get oracle price privately + const price = getPrivateOracleData(disclose(priceKey)); + + // Verify health factor privately + assert(verifyHealthFactor(collateralProof, disclose(borrowAmount), price), + "Insufficient collateral ratio"); + + // Update debt commitment + const newDebtCommit = updateDebtCommitment(collateralProof, disclose(borrowAmount)); + + // Send borrowed funds to user + const sendResult = send( + lendingPool.lookup(disclose(priceKey)), // Now returns QualifiedCoinInfo + left(ownPublicKey()), + disclose(borrowAmount) + ); + + // Update lending pool balance with change + sendResult.change.is_some ? + lendingPool.insertCoin(disclose(priceKey), sendResult.change.value, right(kernel.self())) : + lendingPool.remove(disclose(priceKey)); +} + +/** + * @dev Liquidate position circuit + * @notice Allows liquidators to liquidate undercollateralized positions with ZK proof + * @param positionCommitment The commitment to the position being liquidated + * @param liquidationProof ZK proof that position is undercollateralized + * @param repaymentCoin Coin to repay the debt + */ +export circuit liquidatePosition( + positionCommitment: Bytes<32>, + liquidationProof: Bytes<32>, + repaymentCoin: CoinInfo +): [] { + // Verify position exists + const path = disclose(findCollateralPosition(positionCommitment)); + assert(collateralPositions.checkRoot(merkleTreePathRoot<100, Bytes<32>>(path)), + "Position not found"); + + // Verify position is undercollateralized using ZK proof + assert(verifyLiquidationEligibility(liquidationProof), + "Position is not eligible for liquidation"); + + // Receive repayment + receive(disclose(repaymentCoin)); + + // Calculate liquidation bonus (e.g., 5%) + const liquidationBonus = calculateLiquidationBonus(disclose(repaymentCoin.value)); + + // Transfer collateral to liquidator (with explicit disclosure) + const collateralToTransfer = (disclose(repaymentCoin.value) + liquidationBonus) as Uint<128>; + + const sendResult = send( + collateralPool.lookup(disclose(positionCommitment)), + left(ownPublicKey()), + disclose(collateralToTransfer) // Add disclose() here + ); + + // Update or remove position + updateOrRemovePosition(positionCommitment); +} + +/** + * @dev Repay debt circuit + * @notice Allows users to repay their debt partially or fully + * @param positionCommitment The commitment to the user's position + * @param repaymentCoin The coin used for repayment + * @param repaymentAmount The amount being repaid (kept private) + */ +export circuit repayDebt( + positionCommitment: Bytes<32>, + repaymentCoin: CoinInfo, + repaymentAmount: Uint<128> +): [] { + // Verify position ownership + const path = disclose(findCollateralPosition(positionCommitment)); + assert(collateralPositions.checkRoot(merkleTreePathRoot<100, Bytes<32>>(path)), + "Position not found"); + + // Verify user owns this position + assert(verifyPositionOwnership(positionCommitment), "Not position owner"); + + // Receive repayment + receive(disclose(repaymentCoin)); + + // Get current debt amount via witness + const currentDebt = getCurrentDebt(positionCommitment); + + // Calculate new debt + const newDebt = currentDebt - disclose(repaymentAmount); + + // Update debt commitment + const newDebtCommit = persistentCommit>(newDebt, disclose(getRandomness())); + + // If fully repaid, allow collateral withdrawal + if (newDebt == 0 as Uint<128>) { + // Mark position as repaid, allowing collateral withdrawal + markPositionRepaid(positionCommitment); + } +} + +/** + * @dev Withdraw collateral circuit + * @notice Allows users to withdraw collateral while maintaining health factor + * @param positionCommitment The commitment to the user's position + * @param withdrawAmount The amount to withdraw (kept private) + */ +export circuit withdrawCollateral( + positionCommitment: Bytes<32>, + withdrawAmount: Uint<128> +): [] { + // Verify position ownership + assert(verifyPositionOwnership(positionCommitment), "Not position owner"); + + // Verify withdrawal maintains health factor + assert(verifyHealthFactorAfterWithdrawal(positionCommitment, disclose(withdrawAmount)), + "Withdrawal would violate health factor"); + + // Send collateral to user + const sendResult = send( + collateralPool.lookup(disclose(positionCommitment)), + left(ownPublicKey()), + disclose(withdrawAmount) + ); + + // Update collateral commitment + updateCollateralCommitment(positionCommitment, disclose(withdrawAmount)); +} + +/** + * @dev Supply to lending pool circuit + * @notice Allows users to supply assets to earn interest + * @param supplyCoin The coin to supply to the pool + * @param supplyAmount The amount being supplied + */ +export circuit supplyToPool( + supplyCoin: CoinInfo, + supplyAmount: Uint<128> +): [] { + // Receive supply + receive(disclose(supplyCoin)); + + // Create supply position commitment + const userCommit = generateUserCommitment(disclose(getSecretKey())); + const supplyCommit = persistentCommit>(disclose(supplyAmount), disclose(getRandomness())); + + // Store supply position + const supplyPosition = SupplyPosition { + userCommitment: userCommit, + supplyCommitment: supplyCommit, + assetType: disclose(supplyCoin.color), + timestamp: disclose(getCurrentTime()) + }; + + supplyPositions.insert(disclose(userCommit)); + + // Update total supplied (cast to Uint<128>) + const currentTotal = totalSuppliedByAsset.lookup(disclose(supplyCoin.color)); + totalSuppliedByAsset.insert(disclose(supplyCoin.color), (currentTotal + disclose(supplyAmount)) as Uint<128>); +} + +/** + * @dev Calculate interest rate circuit + * @notice Computes the current interest rate based on pool utilization + * @param assetType The asset type (coin color) to calculate interest rate for + * @return The current interest rate in basis points + */ +export circuit calculateInterestRate(assetType: Bytes<32>): Uint<64> { + const totalBorrowed = totalBorrowedByAsset.lookup(disclose(assetType)); + const totalSupplied = totalSuppliedByAsset.lookup(disclose(assetType)); + + // Calculate utilization rate using witness function + const utilizationRate = calculateUtilizationRate(totalBorrowed, totalSupplied); + + // Apply interest rate model + const interestRate = applyInterestRateModel(disclose(utilizationRate)); + + return disclose(interestRate); +} \ No newline at end of file diff --git a/packages/midnight-contracts-wizard/contracts/oracle/oracle.compact b/packages/midnight-contracts-wizard/contracts/oracle/oracle.compact new file mode 100644 index 000000000..c84f0bbfa --- /dev/null +++ b/packages/midnight-contracts-wizard/contracts/oracle/oracle.compact @@ -0,0 +1,278 @@ +pragma language_version >= 0.16.0; + +import CompactStandardLibrary; + +/** + * @dev Trusted oracle operator registry + * @notice Merkle tree storing authorized oracle operator commitments for privacy-preserving authorization + */ +export ledger authorizedOperators: MerkleTree<100, Bytes<32>>; + +/** + * @dev Oracle address + * @notice Stores the address of the trusted oracle for signature verification + */ +export ledger oracleAddress: Uint<32>; + +/** + * @dev Oracle data value + * @notice Stores the current value updated by the oracle + */ +export ledger dataValue: Uint<64>; + +/** + * @dev Oracle feeds registry + * @notice Maps data keys to their latest oracle data points with metadata + */ +export ledger oracleFeeds: Map, OracleDataPoint>; + +/** + * @dev Authorized auditors registry + * @notice Merkle tree storing authorized auditor commitments for compliance and oversight + */ +export ledger authorizedAuditors: MerkleTree<100, Bytes<32>>; + +/** + * @dev Contract owner + * @notice Stores the contract owner's public key for administrative functions + */ +export ledger owner: Bytes<32>; + +/** + * @dev Oracle data point structure + * @notice Represents a single oracle data submission with value, timestamp, and operator metadata + * @param value The oracle data value (e.g., price, rate, or other metric) + * @param timestamp Unix timestamp when the data was submitted + * @param operator Commitment hash of the operator who submitted the data + */ +struct OracleDataPoint { + value: Uint<128>; + timestamp: Uint<64>; + operator: Bytes<32>; +} + +/** + * @dev Constructor + * @notice Initializes the oracle contract with the trusted oracle address + * @param oracle The address of the trusted oracle for signature verification + */ +constructor(oracle: Uint<32>) { + oracleAddress = disclose(oracle); + dataValue = 0; // Initialize with a default value +} + +/** + * @dev Verify signature witness + * @notice Verifies a digital signature against data and oracle address + * @param signature The 64-byte signature to verify + * @param data The 32-byte data that was signed + * @param oracleAddress The oracle's address for verification + * @return Boolean indicating whether the signature is valid + */ +witness verifySignature(signature: Bytes<64>, data: Bytes<32>, oracleAddress: Uint<32>): Boolean; + +/** + * @dev Hash data witness + * @notice Computes a hash of the provided value for signature verification + * @param newValue The value to hash + * @return A 32-byte hash of the input value + */ +witness hashData(newValue: Uint<64>): Bytes<32>; + +/** + * @dev Get private oracle data witness + * @notice Provides oracle data privately for zero-knowledge proof generation + * @param dataKey The identifier for the data feed + * @return The oracle data value (kept private) + */ +witness getPrivateOracleData(dataKey: Bytes<32>): Uint<128>; + +/** + * @dev Validate data freshness witness + * @notice Checks if oracle data is recent enough for use + * @param dataKey The data feed identifier + * @param maxAge Maximum acceptable age in seconds + * @return Boolean indicating whether the data is fresh enough + */ +witness validateDataFreshness(dataKey: Bytes<32>, maxAge: Uint<64>): Boolean; + +/** + * @dev Find operator witness + * @notice Provides the Merkle tree path for an operator's authorization proof + * @param operatorCommitment The operator's commitment hash + * @return The Merkle tree path proving the operator is authorized + */ +witness findOperator(operatorCommitment: Bytes<32>): MerkleTreePath<100, Bytes<32>>; + +/** + * @dev Get current time witness + * @notice Provides the current timestamp for recording updates and freshness checks + * @return The current Unix timestamp in seconds + */ +witness getCurrentTime(): Uint<64>; + +/** + * @dev Find auditor witness + * @notice Provides the Merkle tree path for an auditor's authorization proof + * @param auditorCommitment The auditor's commitment hash + * @return The Merkle tree path proving the auditor is authorized + */ +witness findAuditor(auditorCommitment: Bytes<32>): MerkleTreePath<100, Bytes<32>>; + +/** + * @dev Get secret key witness + * @notice Provides the caller's secret key for owner verification + * @return The caller's 32-byte secret key + */ +witness getSecretKey(): Bytes<32>; + +/** + * @dev Register oracle operator circuit + * @notice Allows the contract owner to register a new authorized oracle operator + * @param operatorCommitment Hash commitment of the operator's credentials + */ +export circuit registerOperator(operatorCommitment: Bytes<32>): [] { + // Verify caller is contract owner + const callerPk = persistentHash>(disclose(getSecretKey())); + assert(owner == callerPk, "Only owner can register operators"); + + authorizedOperators.insert(disclose(operatorCommitment)); +} + +/** + * @dev Submit oracle data circuit + * @notice Allows authorized operators to submit oracle data with cryptographic proof of authorization + * @param dataKey Identifier for the data feed (e.g., price pair, metric name) + * @param dataValue The oracle data value to store + * @param timestamp Unix timestamp when the data was observed + * @param operatorProof The operator's commitment hash for authorization verification + */ +export circuit submitOracleData( + dataKey: Bytes<32>, + dataValue: Uint<128>, + timestamp: Uint<64>, + operatorProof: Bytes<32> +): [] { + // Verify operator is authorized using Merkle proof + const path = disclose(findOperator(operatorProof)); + assert(authorizedOperators.checkRoot(merkleTreePathRoot<100, Bytes<32>>(path)), + "Unauthorized oracle operator"); + + // Create the OracleDataPoint struct + const dataPoint = OracleDataPoint { + value: disclose(dataValue), + timestamp: disclose(timestamp), + operator: disclose(operatorProof) + }; + + // Insert the complete struct into the map + oracleFeeds.insert(disclose(dataKey), dataPoint); +} + +/** + * @dev Get oracle data circuit + * @notice Retrieves the current oracle data value with freshness validation + * @param dataKey The identifier for the data feed to retrieve + * @param maxAge Maximum acceptable age in seconds for the data to be considered valid + * @return The current oracle data value if it passes freshness checks + */ +export circuit getOracleData(dataKey: Bytes<32>, maxAge: Uint<64>): Uint<128> { + assert(oracleFeeds.member(disclose(dataKey)), "Oracle data not found"); + + const dataPoint = oracleFeeds.lookup(disclose(dataKey)); + + // Verify data freshness + const currentTime = disclose(getCurrentTime()); + assert(currentTime - dataPoint.timestamp <= disclose(maxAge), "Oracle data is stale"); + + // Return only the value + return dataPoint.value; +} + +/** + * @dev Verify oracle condition circuit + * @notice Proves that oracle data meets a threshold condition without revealing the actual value + * @param dataKey The identifier for the data feed to verify + * @param threshold The threshold value to compare against + * @return Boolean indicating whether the oracle value meets or exceeds the threshold + */ +export circuit verifyOracleCondition( + dataKey: Bytes<32>, + threshold: Uint<128> +): Boolean { + const oracleValue = getPrivateOracleData(disclose(dataKey)); + return disclose(oracleValue) >= disclose(threshold); +} + +/** + * @dev Check collateral ratio circuit + * @notice Verifies that collateral value meets the required ratio (150%) without revealing exact amounts + * @param collateralAmount The amount of collateral held (kept private) + * @param debtAmount The amount of debt owed (kept private) + * @param priceKey The identifier for the price feed to use in valuation + * @return Boolean indicating whether the collateral ratio requirement is met + */ +export circuit checkCollateralRatio( + collateralAmount: Uint<128>, + debtAmount: Uint<128>, + priceKey: Bytes<32> +): Boolean { + const price = getPrivateOracleData(disclose(priceKey)); + + // Calculate collateral value and required collateral (150% ratio) + const collateralValue = (disclose(collateralAmount) as Field) * (disclose(price) as Field); + const requiredCollateral = (disclose(debtAmount) as Field) * (150 as Field); + + return (collateralValue as Uint<128>) >= (requiredCollateral as Uint<128>); +} + +/** + * @dev Register auditor circuit + * @notice Allows the contract owner to register a new authorized auditor for compliance oversight + * @param auditorCommitment Hash commitment of the auditor's credentials + */ +export circuit registerAuditor(auditorCommitment: Bytes<32>): [] { + // Verify caller is contract owner + const callerPk = persistentHash>(disclose(getSecretKey())); + assert(owner == callerPk, "Only owner can register auditors"); + + authorizedAuditors.insert(disclose(auditorCommitment)); +} + +/** + * @dev Disclose oracle data to auditor circuit + * @notice Allows authorized auditors to access oracle data for compliance and oversight purposes + * @param dataKey The identifier for the data feed to disclose + * @param auditorKey The auditor's public key or commitment hash + * @return The complete oracle data point including value, timestamp, and operator information + */ +export circuit discloseToAuditor( + dataKey: Bytes<32>, + auditorKey: Bytes<32> +): OracleDataPoint { + // Verify auditor is authorized using Merkle proof + const path = disclose(findAuditor(disclose(auditorKey))); + assert(authorizedAuditors.checkRoot(merkleTreePathRoot<100, Bytes<32>>(path)), + "Unauthorized auditor"); + + // Verify the data exists + assert(oracleFeeds.member(disclose(dataKey)), "Oracle data not found"); + + // Retrieve and return the oracle data + const dataPoint = oracleFeeds.lookup(disclose(dataKey)); + return dataPoint; +} + +/** + * @dev Update oracle value circuit + * @notice Allows a trusted oracle to update the data value with cryptographic signature verification + * @param newValue The new oracle data value to store + * @param signature The oracle's 64-byte signature over the combined data and value + * @param data The 32-byte data context (e.g., data feed identifier) for the update + */ +export circuit updateValue(newValue: Uint<64>, signature: Bytes<64>, data: Bytes<32>): [] { + // Hash both the data context and new value for signature verification + const message = persistentHash<[Bytes<32>, Uint<64>]>([disclose(data), disclose(newValue)]); + assert(verifySignature(disclose(signature), message, oracleAddress), "Invalid signature"); + dataValue = disclose(newValue); +} diff --git a/packages/midnight-contracts-wizard/contracts/staking/staking.compact b/packages/midnight-contracts-wizard/contracts/staking/staking.compact new file mode 100644 index 000000000..ef32d6216 --- /dev/null +++ b/packages/midnight-contracts-wizard/contracts/staking/staking.compact @@ -0,0 +1,332 @@ +pragma language_version >= 0.16.0; + +import CompactStandardLibrary; + +// ======================= +// Enums +// ======================= + +/** + * @dev Staking status for users + * @notice Defines the possible states a user can be in regarding their staking position + * - NotStaked: User has no active stake + * - Staked: User has an active stake that can be unstaked + * - Locked: User's stake is locked and cannot be unstaked until the lock period expires + */ +enum StakingStatus { + NotStaked, + Staked, + Locked +} + +// ======================= +// Ledger State (Public) +// ======================= + +/** + * @dev Total staked supply + * @notice Tracks the total amount of tokens currently staked in the contract + */ +export ledger totalStakedSupply: Uint<64>; + +/** + * @dev Lock period + * @notice Minimum duration (in time units) that tokens must remain staked + */ +export ledger lockPeriod: Uint<64>; + +/** + * @dev Contract owner + * @notice Address of the contract owner who can perform administrative functions + */ +export ledger ownerId: Uint<32>; + +/** + * @dev Transaction counter + * @notice Increments with each state-changing operation to prevent replay attacks + */ +export ledger nonce: Counter; + +/** + * @dev Stake start time + * @notice Stores the timestamp when staking began (public) + */ +export ledger stakeStartTime: Uint<64>; + +/** + * @dev Reward rate value + * @notice Stores the current reward rate for staking calculations + */ +export ledger rewardRateValue: Uint<64>; + +/** + * @dev Staked balances + * @notice Maps each user ID to their total staked token amount + */ +export ledger stakedBalances: Map, Uint<64>>; + +/** + * @dev Reward balances + * @notice Maps each user ID to their accumulated rewards that can be claimed + */ +export ledger rewardBalances: Map, Uint<64>>; + +/** + * @dev User staking status + * @notice Maps each user ID to their current staking status (NotStaked, Staked, or Locked) + */ +export ledger userStatus: Map, StakingStatus>; + + +// ======================= +// Witness State (Private) +// ======================= + +/** + * @dev Private stake start time + * @notice Provides the private stake start time for ZK proof generation + */ +witness getStakeStartTime(): Uint<64>; + +/** + * @dev Private reward rate + * @notice Provides the private reward rate for ZK proof generation + */ +witness getRewardRate(): Uint<64>; + +/** + * @dev Private balance + * @notice Provides the private balance for ZK proof generation + */ +witness getBalance(): Uint<64>; + +// ======================= +// Constructor +// ======================= + +/** + * @dev Constructor + * @notice Initializes the staking contract with the owner ID, lock period, and reward rate + * @param initialOwnerId The address of the contract owner who can perform administrative functions + * @param initialLockPeriod The minimum duration (in time units) that tokens must remain staked + * @param initialRewardRate The initial reward rate for staking calculations + */ +constructor(initialOwnerId: Uint<32>, initialLockPeriod: Uint<64>, initialRewardRate: Uint<64>) { + totalStakedSupply = 0; + lockPeriod = disclose(initialLockPeriod); + ownerId = disclose(initialOwnerId); + rewardRateValue = disclose(initialRewardRate); +} + +// ======================= +// Witness Functions (For ZK Proofs) +// ======================= + +/** + * @dev Private check to ensure lock-up period has passed + * @notice Verifies if the lock-up period has passed for a given user + * @param stakerId The ID of the staker to check + * @param currentTime The current timestamp to compare against + * @return Boolean indicating whether the lock-up period has passed + */ +witness checkLockPeriod(stakerId: Uint<32>, currentTime: Uint<64>): Boolean; + +/** + * @dev Private calculation of accrued rewards + * @notice Calculates the accrued rewards for a given user based on their stake and time + * @param stakerId The ID of the staker + * @param currentTime The current timestamp for reward calculation + * @return The amount of accrued rewards + */ +witness calculateRewards(stakerId: Uint<32>, currentTime: Uint<64>): Uint<64>; + +/** + * @dev Private verification of sufficient funds for staking + * @notice Verifies if the user has sufficient funds to stake the requested amount + * @param stakerId The ID of the staker + * @param amount The amount to be staked + * @return Boolean indicating whether the user has sufficient funds + */ +witness verifyStakeAmount(stakerId: Uint<32>, amount: Uint<64>): Boolean; + +// ======================= +// Circuits (Transition Functions) +// ======================= + +/** + * @dev Stake function + * @notice Allows a user to stake tokens, which are locked for the configured lock period + * @param stakerId The ID of the user staking tokens + * @param amount The amount of tokens to stake + * @param currentTime The current timestamp for recording the stake start time + */ +export circuit stake( + stakerId: Uint<32>, + amount: Uint<64>, + currentTime: Uint<64> +): [] { + // Verify sufficient funds privately + const isValid = verifyStakeAmount(disclose(stakerId), disclose(amount)); + assert(isValid, "Insufficient private token balance"); + + // Update staked balance + const currentStake = stakedBalances.member(disclose(stakerId)) + ? stakedBalances.lookup(disclose(stakerId)) + : 0 as Uint<64>; + + stakedBalances.insert(disclose(stakerId), (currentStake + disclose(amount)) as Uint<64>); + + // Update total supply + totalStakedSupply = (totalStakedSupply + disclose(amount)) as Uint<64>; + + // Update stake start time + stakeStartTime = disclose(currentTime); + + // Update user status to Locked + userStatus.insert(disclose(stakerId), StakingStatus.Locked); + + nonce.increment(1); +} + +/** + * @dev Unstake function + * @notice Allows a user to unstake tokens after the lock period has passed + * @param stakerId The ID of the user unstaking tokens + * @param amount The amount of tokens to unstake + * @param currentTime The current timestamp for verifying the lock period + */ +export circuit unstake( + stakerId: Uint<32>, + amount: Uint<64>, + currentTime: Uint<64> +): [] { + // Check if lock period has passed privately + const isLockPeriodPassed = checkLockPeriod(disclose(stakerId), disclose(currentTime)); + assert(isLockPeriodPassed, "Lock-up period not completed"); + + // Check user has sufficient stake + assert(stakedBalances.member(disclose(stakerId)), "No staked balance found"); + const currentStake = stakedBalances.lookup(disclose(stakerId)); + assert(currentStake >= disclose(amount), "Insufficient staked amount"); + + // Update staked balance + stakedBalances.insert(disclose(stakerId), (currentStake - disclose(amount)) as Uint<64>); + + // Update total supply + totalStakedSupply = (totalStakedSupply - disclose(amount)) as Uint<64>; + + // Update status if balance is zero + if ((currentStake - disclose(amount)) == 0 as Uint<64>) { + userStatus.insert(disclose(stakerId), StakingStatus.NotStaked); + } else { + // Re-lock remaining stake + stakeStartTime = disclose(currentTime); + userStatus.insert(disclose(stakerId), StakingStatus.Locked); + } + + nonce.increment(1); +} + +/** + * @dev Claim rewards function + * @notice Allows a user to claim their accumulated staking rewards + * @param stakerId The ID of the user claiming rewards + * @param currentTime The current timestamp for reward calculation + */ +export circuit claimRewards( + stakerId: Uint<32>, + currentTime: Uint<64> +): [] { + // Calculate rewards privately + const rewardsToClaim = calculateRewards(disclose(stakerId), disclose(currentTime)); + + // Assert that rewards are positive + assert(rewardsToClaim > 0, "No rewards to claim"); + + // Update public reward balance + const currentRewards = rewardBalances.member(disclose(stakerId)) + ? rewardBalances.lookup(disclose(stakerId)) + : 0 as Uint<64>; + + rewardBalances.insert(disclose(stakerId), (currentRewards + disclose(rewardsToClaim)) as Uint<64>); + + nonce.increment(1); +} + +/** + * @dev Update reward rate function + * @notice Updates the global reward rate for all stakers (owner only) + * @param callerId The ID of the caller (must be the contract owner) + * @param newRewardRate The new reward rate to be applied + */ +export circuit updateRewardRate( + callerId: Uint<32>, + newRewardRate: Uint<64> +): [] { + // Access control: Only owner can update the rate + assert(ownerId == disclose(callerId), "Only contract owner can update reward rate"); + + // Update global reward rate + rewardRateValue = disclose(newRewardRate); + + nonce.increment(1); +} + +/** + * @dev Update lock period function + * @notice Updates the global lock period for all stakers (owner only) + * @param callerId The ID of the caller (must be the contract owner) + * @param newLockPeriod The new lock period duration (in time units) + */ +export circuit updateLockPeriod( + callerId: Uint<32>, + newLockPeriod: Uint<64> +): [] { + // Access control: Only owner can update the lock period + assert(ownerId == disclose(callerId), "Only contract owner can update lock period"); + + // Update public lock period + lockPeriod = disclose(newLockPeriod); + + nonce.increment(1); +} + +// ======================= +// Query Functions (Publicly readable ledger state) +// ======================= + +/** + * @dev Query stake function + * @notice Returns the total staked amount for a specified user + * @param stakerId The ID of the user to query + * @return The amount of tokens currently staked by the user, or 0 if no stake exists + */ +export circuit queryStake(stakerId: Uint<32>): Uint<64> { + return stakedBalances.member(disclose(stakerId)) + ? stakedBalances.lookup(disclose(stakerId)) + : 0 as Uint<64>; +} + +/** + * @dev Query rewards function + * @notice Returns the accumulated rewards for a specified user + * @param stakerId The ID of the user to query + * @return The amount of rewards accumulated by the user, or 0 if no rewards exist + */ +export circuit queryRewards(stakerId: Uint<32>): Uint<64> { + return rewardBalances.member(disclose(stakerId)) + ? rewardBalances.lookup(disclose(stakerId)) + : 0 as Uint<64>; +} + +/** + * @dev Query status function + * @notice Returns the current staking status for a specified user + * @param stakerId The ID of the user to query + * @return The user's staking status (NotStaked, Staked, or Locked), or NotStaked if no status exists + */ +export circuit queryStatus(stakerId: Uint<32>): StakingStatus { + return userStatus.member(disclose(stakerId)) + ? userStatus.lookup(disclose(stakerId)) + : StakingStatus.NotStaked; +} diff --git a/packages/midnight-contracts-wizard/contracts/tokenization/TokenizationLibrary.compact b/packages/midnight-contracts-wizard/contracts/tokenization/TokenizationLibrary.compact new file mode 100644 index 000000000..1dd34a7a5 --- /dev/null +++ b/packages/midnight-contracts-wizard/contracts/tokenization/TokenizationLibrary.compact @@ -0,0 +1,23 @@ +module TokenizationLibrary { + export {generateOwnersPK, Investor, generateCommit}; + import CompactStandardLibrary; + + struct Investor { + id: Bytes<32>; + investment: Uint<32>; + coinType: Bytes<32>; + }; + + circuit generateOwnersPK(address: Bytes<32>, sk: Bytes<32>, rand: Bytes<32>): Bytes<32>{ + return persistentHash>>([ + pad(32, "tokenless:user"), + persistentHash>>([ + address, sk, rand, + ]) + ]); + } + circuit generateCommit(data: Investor, rand: Bytes<32>): Bytes<32>{ + return persistentCommit(data, rand); + } + +} \ No newline at end of file diff --git a/packages/midnight-contracts-wizard/contracts/tokenization/tokenization.compact b/packages/midnight-contracts-wizard/contracts/tokenization/tokenization.compact new file mode 100644 index 000000000..ff4c9b974 --- /dev/null +++ b/packages/midnight-contracts-wizard/contracts/tokenization/tokenization.compact @@ -0,0 +1,362 @@ +pragma language_version >= 0.16.0; + +import CompactStandardLibrary; +import TokenizationLibrary; + +/** + * @dev Exported types + * @notice Makes custom project types available to external consumers + * - Project: Represents a crowdfunding project with its details and state + * - ProjectStatus: Enum defining the possible states of a project + */ +export {Project, ProjectStatus}; + +/** + * @dev Project status enumeration + * @notice Defines the possible states a project can be in during its lifecycle + * - Active: Project is currently accepting investments + * - Withdrawn: Project has been withdrawn by the creator + * - Closed: Project has reached its goal or deadline and is no longer accepting investments + */ +enum ProjectStatus { + Active, + Withdrawn, + Closed +} + +/** + * @dev Protocol total value locked + * @notice Maps coin types to their qualified coin information, tracking all coins deposited into the protocol + */ +export ledger protocolTVL: Map, QualifiedCoinInfo>; + +/** + * @dev Projects registry + * @notice Maps project IDs to their project data, storing all projects created on-chain + */ +export ledger projects: Map, Project>; + +/** + * @dev Investor commitments + * @notice Merkle tree storing investor commitment hashes anonymously using zero-knowledge proofs + */ +export ledger investors: MerkleTree<100, Bytes<32>>; + + +/** + * @dev Project structure + * @notice Represents a crowdfunding project with all its details and current state + * @param id Unique identifier for the project + * @param title Project title (opaque string) + * @param desc Project description (opaque string) + * @param owner Address of the project owner/creator + * @param investmentGoal Target funding goal for the project + * @param raised Total amount raised so far + * @param investors Number of investors who have contributed + * @param duration Project duration in time units + * @param creationDate Timestamp when the project was created + * @param status Current status of the project (Active, Withdrawn, or Closed) + * @param coinType Type of coin accepted for investments + */ +struct Project { + id: Bytes<32>; + title: Opaque<"string">; + desc: Opaque<"string">; + owner: Bytes<32>; + investmentGoal: Uint<128>; + raised: Uint<128>; + investors: Uint<128>; + duration: Uint<128>; + creationDate: Uint<128>; + status: ProjectStatus; + coinType: Bytes<32>; +} + +/** + * @dev Local secret key witness + * @notice Provides the user's private secret key for generating commitments and identifiers + * @return The user's 32-byte secret key + */ +witness localSecretKey(): Bytes<32>; + +/** + * @dev Project expiration check witness + * @notice Verifies whether a project has expired based on its duration and start date + * @param duration The project's duration in time units + * @param startDate The timestamp when the project was created + * @return Boolean indicating whether the project is still valid (false if expired) + */ +witness confirmProjectExpiration(duration: Uint<128>, startDate: Uint<128>): Boolean; + +/** + * @dev Investor commitment proof witness + * @notice Finds the Merkle tree path for an investor's commitment hash to prove their investment anonymously + * @param commitment The investor's commitment hash + * @return The Merkle tree path proving the commitment exists in the investors tree + */ +witness findInvestor(commitment: Bytes<32>): MerkleTreePath<100, Bytes<32>>; + + +// ======================= +// Interaction for project creation and management +// ======================= + +/** + * @dev Create project circuit + * @notice Allows users to create a new crowdfunding project on-chain + * @param projectId Unique identifier for the new project + * @param investmentGoal Target funding goal for the project + * @param duration Project duration in time units + * @param coinType Type of coin accepted for investments + * @param currentDate Current timestamp for recording the creation date + * @param title Project title (opaque string) + * @param desc Project description (opaque string) + */ +export circuit createProject( + projectId: Bytes<32>, + investmentGoal: Uint<128>, + duration: Uint<128>, + coinType: Bytes<32>, + currentDate: Uint<128>, + title: Opaque<"string">, + desc: Opaque<"string"> +): [] { + const disclosedId = disclose(projectId); + assert (!projects.member(disclosedId), "Project with same ID already exists"); + + // Generate a unique hash representing the project owner without revealing their public key + const ownersHash = generateOwnersPK(ownPublicKey().bytes, disclose(localSecretKey()), disclosedId); + + const newProject = Project{ + ...default, + title: disclose(title), + desc: disclose(desc), + status: ProjectStatus.Active, + investmentGoal: disclose(investmentGoal), + duration: disclose(duration), + owner: ownersHash, + coinType: disclose(coinType), + creationDate: disclose(currentDate) + }; + + projects.insert(disclosedId, newProject); +} + +/** + * @dev Cancel project circuit + * @notice Allows the project owner to cancel and remove their project from the on-chain registry + * @param projectId The unique identifier of the project to cancel + */ +export circuit cancelProject(projectId: Bytes<32>): [] { + const disclosedId = disclose(projectId); + + assert (projects.member(disclosedId), "Project with specified ID does not exist"); + const projectToEnd = projects.lookup(disclosedId); + const reconstructedOwnersHash = generateOwnersPK(ownPublicKey().bytes, disclose(localSecretKey()), disclosedId); + + assert (reconstructedOwnersHash == projectToEnd.owner, "Can not end this project: You are not the owner"); + + // Remove the project from the on-chain registry + projects.remove(disclosedId); +} + +/** + * @dev Withdraw project funds circuit + * @notice Allows the project owner to withdraw funds after the project reaches its goal or closes + * @param projectId The unique identifier of the project to withdraw funds from + */ +export circuit withdrawProjectFunds(projectId: Bytes<32>): []{ + const disclosedId = disclose(projectId); + assert (projects.member(disclosedId), "Project with the specified ID does not exist"); + + const projectToWithdrawFrom = projects.lookup(disclosedId); + const reconstructedOwnersHash = generateOwnersPK(ownPublicKey().bytes, disclose(localSecretKey()), disclosedId); + + assert (reconstructedOwnersHash == projectToWithdrawFrom.owner, "Can not end this project: You are not the owner"); + assert (projectToWithdrawFrom.raised >= projectToWithdrawFrom.investmentGoal || projectToWithdrawFrom.status == ProjectStatus.Closed, "Project funds is less than the investment goal"); + + const sendResult = send( + protocolTVL.lookup(projectToWithdrawFrom.coinType), + left(ownPublicKey()), + projectToWithdrawFrom.investmentGoal + ); + + sendResult.change.is_some ? + protocolTVL.insertCoin(projectToWithdrawFrom.coinType, sendResult.change.value, left(ownPublicKey())) : + protocolTVL.remove(projectToWithdrawFrom.coinType); + + // Update the project status to Withdrawn + projects.remove(disclosedId); + + const updateProject = Project{ + ...projectToWithdrawFrom, + status: ProjectStatus.Withdrawn + }; + + projects.insert(disclosedId, updateProject); +} + +/** + * @dev End project circuit + * @notice Allows the project owner to close their project at any time and return remaining funds + * @param projectId The unique identifier of the project to close + */ +export circuit endProject(projectId: Bytes<32>): [] { + const disclosedId = disclose(projectId); + + assert (projects.member(disclosedId), "Project with specified ID does not exist"); + const projectToEnd = projects.lookup(disclosedId); + const reconstructedOwnersHash = generateOwnersPK(ownPublicKey().bytes, disclose(localSecretKey()), disclosedId); + + assert (reconstructedOwnersHash == projectToEnd.owner, "Can not end this project: You are not the owner"); + + if(projectToEnd.raised > 0){ + // Send raised funds to the project owner before closing + const sendResult = send( + protocolTVL.lookup(projectToEnd.coinType), + left(ownPublicKey()), + projectToEnd.raised + ); + + // Update protocol balance with any remaining change + sendResult.change.is_some ? + protocolTVL.insertCoin(projectToEnd.coinType, sendResult.change.value, right(kernel.self())) : + protocolTVL.remove(projectToEnd.coinType); + } + + // Update the project status to Closed + projects.insert(disclosedId, Project{ + ...projectToEnd, + status: ProjectStatus.Closed + }); +} + +/** + * @dev Update project circuit + * @notice Allows the project owner to update their project's details while it's still active + * @param projectId The unique identifier of the project to update + * @param title New project title (opaque string) + * @param desc New project description (opaque string) + * @param investmentGoal New target funding goal for the project + * @param duration New project duration in time units + */ +export circuit updateProject( + projectId: Bytes<32>, + title: Opaque<"string">, + desc: Opaque<"string">, + investmentGoal: Uint<128>, + duration: Uint<128> + ): []{ + const disclosedId = disclose(projectId); + assert (projects.member(disclosedId), "Project with the specified ID does not exist"); + const projectToUpdate = projects.lookup(disclosedId); + assert (projectToUpdate.status != ProjectStatus.Withdrawn || projectToUpdate.status != ProjectStatus.Closed, "Can not edit project: This project has ended"); + + const reconstructedOwnersHash = generateOwnersPK(ownPublicKey().bytes, disclose(localSecretKey()), disclosedId); + assert (reconstructedOwnersHash == projectToUpdate.owner, "Can not end this project: You are not the owner"); + + const updateProject = Project{ + ...projectToUpdate, + title: disclose(title), + desc: disclose(desc), + investmentGoal: disclose(investmentGoal), + duration: disclose(duration), + }; + + projects.insert(disclosedId, updateProject); +} + + +/** + * @dev Invest in project circuit + * @notice Allows users to invest in an active project by depositing coins anonymously + * @param coin The coin information containing the investment amount and type + * @param projectId The unique identifier of the project to invest in + */ +export circuit investProject(coin: CoinInfo, projectId: Bytes<32>): []{ + const disclosedCoin = disclose(coin); + const disclosedId = disclose(projectId); + assert (projects.member(disclosedId), "Project with the specified ID does not exist"); + const projectToInvest = projects.lookup(disclosedId); + assert (projectToInvest.raised < projectToInvest.investmentGoal, "Can not invest in this project: the investment objective of the project has been reached"); + const isProjectActive = confirmProjectExpiration(projectToInvest.duration, projectToInvest.creationDate); + assert (isProjectActive, "Project with specified ID is no longer active"); + assert (projectToInvest.status != ProjectStatus.Withdrawn || projectToInvest.status != ProjectStatus.Closed, "Can not invest in the project: this project is finished"); + assert (coin.color == projectToInvest.coinType, "Insufficient funds provided"); + assert (coin.value <= projectToInvest.investmentGoal, "Amount is greater than investment goal"); + receive(disclosedCoin); + + const coinToInsert = protocolTVL.member(disclosedCoin.color) ? + mergeCoinImmediate(protocolTVL.lookup(disclosedCoin.color), disclosedCoin) : + disclosedCoin; + + protocolTVL.insertCoin( + disclosedCoin.color, + coinToInsert, + right(kernel.self()) + ); + + const investor = Investor{ + id: disclose(localSecretKey()), + investment: disclosedCoin.value as Uint<32>, + coinType: disclosedCoin.color + }; + + // Create a zero-knowledge commitment of the investor’s data (amount, currency, secret ID). + // This commitment is stored in the investors Merkle Tree + const investorCommit = generateCommit(investor, disclosedId); + investors.insert(investorCommit); + + const updateProject = Project{ + ...projectToInvest, + investors: (projectToInvest.investors + 1) as Uint<128>, + raised: (projectToInvest.raised + disclosedCoin.value) as Uint<128> + }; + + projects.insert(disclosedId, updateProject); +} + +/** + * @dev Request refund circuit + * @notice Allows an investor to request a refund from an active project using zero-knowledge proof of their investment + * @param projectId The unique identifier of the project to request a refund from + * @param refundAmount The amount the investor wishes to withdraw + * @param amountDeposited The total amount the investor originally deposited + */ +export circuit requestRefund(projectId: Bytes<32>, refundAmount: Uint<32>, amountDeposited: Uint<32>): []{ + const disclosedId = disclose(projectId); + + assert (projects.member(disclosedId), "Project with the specified ID does not exist"); + const project = projects.lookup(disclosedId); + assert (project.status != ProjectStatus.Withdrawn || project.status != ProjectStatus.Closed, "Can not refund: This project has ended"); + + const investor = Investor{ + id: disclose(localSecretKey()), + investment: disclose(amountDeposited), + coinType: project.coinType + }; + + const investorsCommit = generateCommit(investor, disclosedId); + + const path = disclose(findInvestor(investorsCommit)); + + // Verify that the commitment exists in the Merkle tree of investors + assert(investors.checkRoot(merkleTreePathRoot<100, Bytes<32>>(path)), "You are not a valid investor for this project"); + assert (refundAmount <= amountDeposited, "Can not withdraw more than deposited amount"); + + const sendResult = send( + protocolTVL.lookup(project.coinType), + left(ownPublicKey()), + disclose(refundAmount) + ); +sendResult.change.is_some ? + protocolTVL.insertCoin(project.coinType, sendResult.change.value, right(kernel.self())) : + protocolTVL.remove(project.coinType); + + const updateProject = Project { + ...project, + raised: (project.raised - disclose(refundAmount)) as Uint<128> + }; + + projects.insert(disclosedId, updateProject); +} \ No newline at end of file diff --git a/packages/midnight-contracts-wizard/jest.config.ts b/packages/midnight-contracts-wizard/jest.config.ts new file mode 100644 index 000000000..f642dcb1a --- /dev/null +++ b/packages/midnight-contracts-wizard/jest.config.ts @@ -0,0 +1,13 @@ +import type { Config } from "jest"; + +const config: Config = { + displayName: "midnight-contracts-wizard", + preset: "../../jest.preset.js", + transform: { + "^.+\\.[tj]s$": ["ts-jest", { tsconfig: "/tsconfig.spec.json" }], + }, + moduleFileExtensions: ["ts", "js", "html"], + coverageDirectory: "../../coverage/packages/midnight-contracts-wizard", +}; + +export default config; diff --git a/packages/midnight-contracts-wizard/package.json b/packages/midnight-contracts-wizard/package.json new file mode 100644 index 000000000..5384448e0 --- /dev/null +++ b/packages/midnight-contracts-wizard/package.json @@ -0,0 +1,62 @@ +{ + "name": "@meshsdk/midnight-contracts-wizard", + "version": "1.9.0-beta.84", + "description": "Create a new Midnight contracts project with selected smart contracts", + "main": "dist/index.js", + "bin": { + "midnight-contracts-wizard": "./dist/index.js" + }, + "scripts": { + "build": "tsc", + "clean": "rm -rf dist", + "format": "prettier --write \"src/**/*.{ts,js,json}\"", + "dev": "tsc --watch", + "lint": "eslint", + "pack": "npm pack", + "test": "jest", + "start": "node dist/index.js", + "install-cli": "node dist/install.js", + "prepublishOnly": "npm run build" + }, + "keywords": [ + "midnight", + "contracts", + "blockchain", + "privacy", + "zk", + "zero-knowledge", + "cli", + "generator" + ], + "author": "MeshJS Team", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "fs-extra": "^11.1.1", + "inquirer": "^9.2.12", + "ora": "^5.4.1" + }, + "devDependencies": { + "@meshsdk/configs": "*", + "@types/fs-extra": "^11.0.0", + "@types/inquirer": "^9.0.0", + "@types/node": "^20.19.23", + "eslint": "^8.57.0", + "jest": "^29.7.0", + "prettier": "^3.0.0", + "ts-jest": "^29.1.0", + "typescript": "^5.0.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/MeshJS/mesh.git", + "directory": "packages/midnight-contracts-wizard" + }, + "bugs": { + "url": "https://github.com/MeshJS/mesh/issues" + }, + "homepage": "https://meshjs.dev/" +} diff --git a/packages/midnight-contracts-wizard/src/index.ts b/packages/midnight-contracts-wizard/src/index.ts new file mode 100644 index 000000000..67af80764 --- /dev/null +++ b/packages/midnight-contracts-wizard/src/index.ts @@ -0,0 +1,489 @@ +#!/usr/bin/env node +import path from "path"; +import chalk from "chalk"; +import fs from "fs-extra"; +import inquirer from "inquirer"; +import ora from "ora"; + +// Contract interface +interface Contract { + name: string; + description: string; + circuits: number; + files: string[]; +} + +// Contract templates +const contracts: Record = { + tokenization: { + name: "Tokenization Contract", + description: + "Complete project tokenization system with ZK privacy investment", + circuits: 7, + files: [ + "contracts/tokenization/tokenization.compact", + "contracts/tokenization/TokenizationLibrary.compact", + ], + }, + staking: { + name: "Staking Contract", + description: "Privacy-focused staking system with rewards and lock periods", + circuits: 8, + files: ["contracts/staking/staking.compact"], + }, + identity: { + name: "Identity Contracts", + description: + "Complete identity management system with cryptographic libraries", + circuits: 1, + files: [ + "contracts/identity/IdentityLibrary.compact", + "contracts/identity/registry.compact", + "contracts/identity/CryptoLibrary.compact", + ], + }, + oracle: { + name: "Oracle Contract", + description: + "Decentralized oracle system with privacy-preserving data feeds", + circuits: 7, + files: ["contracts/oracle/oracle.compact"], + }, + lendingBorrowing: { + name: "Lending & Borrowing Contract", + description: "Privacy-preserving decentralized lending protocol", + circuits: 7, + files: ["contracts/lending-borrowing/lending-borrowing.compact"], + }, +}; + +async function main(): Promise { + console.log(chalk.blue.bold("\n✨ Midnight Contracts Wizard\n")); + console.log( + chalk.gray( + "Create a new Midnight contracts project with selected smart contracts\n", + ), + ); + console.log( + chalk.yellow( + "💡 Tip: Use SPACE to select contracts, then ENTER to continue\n", + ), + ); + + // Get project name + const { projectName } = await inquirer.prompt<{ projectName: string }>([ + { + type: "input", + name: "projectName", + message: "What is your project name?", + default: "my-midnight-contracts", + validate: (input: string) => { + if (!input.trim()) { + return "Project name is required"; + } + if (!/^[a-z0-9-]+$/.test(input)) { + return "Project name must contain only lowercase letters, numbers, and hyphens"; + } + return true; + }, + }, + ]); + + // Get project directory + const { projectDir } = await inquirer.prompt<{ projectDir: string }>([ + { + type: "input", + name: "projectDir", + message: "Where should we create your project?", + default: `./${projectName}`, + validate: (input: string) => { + if (!input.trim()) { + return "Project directory is required"; + } + return true; + }, + }, + ]); + + // Select contracts + const { selectedContracts } = await inquirer.prompt<{ + selectedContracts: string[]; + }>([ + { + type: "checkbox", + name: "selectedContracts", + message: "Which contracts would you like to include?", + choices: Object.entries(contracts).map(([key, contract]) => ({ + name: `${contract.name} (${contract.circuits} ZK circuits)`, + short: contract.name, + value: key, + checked: false, + })), + validate: (input: string[]) => { + if (!input || input.length === 0) { + return "Please select at least one contract (use SPACE to select, then ENTER to continue)"; + } + return true; + }, + }, + ]); + + // Show summary + console.log(chalk.green("\n📋 Project Summary:")); + console.log(chalk.gray(`Project: ${projectName}`)); + console.log(chalk.gray(`Directory: ${projectDir}`)); + console.log(chalk.gray(`Selected contracts: ${selectedContracts.length}`)); + + selectedContracts.forEach((key) => { + const contract = contracts[key]; + if (contract) { + console.log( + chalk.blue(` • ${contract.name} (${contract.circuits} circuits)`), + ); + console.log(chalk.gray(` ${contract.description}`)); + } + }); + + const { confirm } = await inquirer.prompt<{ confirm: boolean }>([ + { + type: "confirm", + name: "confirm", + message: "Create the project with these settings?", + default: true, + }, + ]); + + if (!confirm) { + console.log(chalk.yellow("Project creation cancelled.")); + return; + } + + // Create project + const spinner = ora("Creating project...").start(); + + try { + await createProject(projectName, projectDir, selectedContracts); + spinner.succeed("Project created successfully!"); + + console.log(chalk.green("\n🎉 Your Midnight contracts project is ready!")); + console.log(chalk.gray("\n📋 Next steps:")); + console.log(chalk.blue("1) Navigate to the project folder:")); + console.log(chalk.white(` cd ${projectDir}`)); + console.log(chalk.blue("\n2) Compile your smart contracts:")); + const compileCommands = generateCompileCommands(selectedContracts); + compileCommands.forEach((command, index) => { + console.log(chalk.white(` ${command}`)); + if (index < compileCommands.length - 1) { + console.log(chalk.white("")); + } + }); + console.log( + chalk.gray("\n💡 Your contracts will be compiled to src/managed/"), + ); + console.log(chalk.gray("💡 Check the README.md for detailed instructions")); + } catch (error) { + spinner.fail("Failed to create project"); + console.error(chalk.red("Error:"), (error as Error).message); + } +} + +async function createProject( + projectName: string, + projectDir: string, + selectedContracts: string[], +): Promise { + // Create project directory + await fs.ensureDir(projectDir); + + // Create package.json + const packageJson = { + name: projectName, + version: "0.1.0", + license: "MIT", + type: "module", + main: "index.js", + module: "./dist/index.js", + types: "./dist/index.d.ts", + packageManager: "yarn@4.9.2", + exports: { + ".": { + default: "./dist/index.js", + import: "./dist/index.js", + types: "./dist/index.d.ts", + require: "./dist/index.js", + }, + }, + scripts: { + compact: generateCompactScript(selectedContracts), + build: generateBuildScript(selectedContracts), + lint: "eslint src", + typecheck: "tsc -p tsconfig.json --noEmit", + prepack: "yarn build", + }, + dependencies: { + "@midnight-ntwrk/compact-runtime": "^0.8.1", + "@midnight-ntwrk/midnight-js-contracts": "2.0.2", + "@midnight-ntwrk/midnight-js-types": "2.0.2", + }, + devDependencies: { + "@midnight-ntwrk/compact": "^0.8.1", + eslint: "^9.27.0", + jest: "^29.7.0", + typescript: "^5.8.2", + }, + }; + + await fs.writeJson(path.join(projectDir, "package.json"), packageJson, { + spaces: 2, + }); + + // Create tsconfig files + await createTsConfig(projectDir); + + // Create src directory structure + await fs.ensureDir(path.join(projectDir, "src")); + await fs.ensureDir(path.join(projectDir, "src/managed")); + + // Copy selected contract files from templates + for (const contractKey of selectedContracts) { + const contract = contracts[contractKey]; + if (!contract) continue; + for (const filePath of contract.files) { + // Get the correct path to contracts directory + const currentDir = path.dirname(process.argv[1] || __filename); + const sourcePath = path.join(currentDir, "..", filePath); + const destPath = path.join(projectDir, filePath); + + if (await fs.pathExists(sourcePath)) { + await fs.ensureDir(path.dirname(destPath)); + await fs.copy(sourcePath, destPath); + } + } + } + + // Create .yarnrc.yml for standalone project + const yarnrcContent = `nodeLinker: node-modules +enableGlobalCache: false +`; + await fs.writeFile(path.join(projectDir, ".yarnrc.yml"), yarnrcContent); + + // Create README + await createReadme(projectDir, projectName, selectedContracts); + + // Create .gitignore + await createGitignore(projectDir); +} + +function generateCompileCommands(selectedContracts: string[]): string[] { + return selectedContracts + .map((contractKey) => { + const contract = contracts[contractKey]; + if (!contract) return []; + return contract.files.map((file) => { + const fileName = path.basename(file, ".compact"); + return `compact compile ${file} ./src/managed/${fileName}`; + }); + }) + .flat(); +} + +function generateCompactScript(selectedContracts: string[]): string { + const commands = generateCompileCommands(selectedContracts); + return commands.join(" && "); +} + +function generateBuildScript(selectedContracts: string[]): string { + const copyCommands = selectedContracts + .map((contractKey) => { + const contract = contracts[contractKey]; + if (!contract) return []; + return contract.files.map((file) => { + const fileName = path.basename(file, ".compact"); + return `test -d ./src/managed/${fileName} && cp -R ./src/managed/${fileName} ./dist/managed/`; + }); + }) + .flat(); + + const copySourceFiles = selectedContracts + .map((contractKey) => { + const contract = contracts[contractKey]; + if (!contract) return []; + return contract.files.map((file) => `cp ${file} dist`); + }) + .flat(); + + return `rm -rf dist && find src/managed -type d -empty -delete && tsc --project tsconfig.build.json && mkdir -p dist/managed && ${copyCommands.join(" && ")} && ${copySourceFiles.join(" && ")}`; +} + +async function createTsConfig(projectDir: string): Promise { + const tsconfig = { + compilerOptions: { + target: "ES2022", + module: "ESNext", + moduleResolution: "node", + allowSyntheticDefaultImports: true, + esModuleInterop: true, + allowJs: true, + strict: true, + skipLibCheck: true, + forceConsistentCasingInFileNames: true, + declaration: true, + outDir: "./dist", + rootDir: "./src", + }, + include: ["src/**/*"], + exclude: ["node_modules", "dist"], + }; + + const tsconfigBuild = { + extends: "./tsconfig.json", + compilerOptions: { + declaration: true, + declarationMap: true, + sourceMap: true, + }, + exclude: ["**/*.test.ts", "**/*.spec.ts"], + }; + + await fs.writeJson(path.join(projectDir, "tsconfig.json"), tsconfig, { + spaces: 2, + }); + await fs.writeJson( + path.join(projectDir, "tsconfig.build.json"), + tsconfigBuild, + { spaces: 2 }, + ); +} + +async function createReadme( + projectDir: string, + projectName: string, + selectedContracts: string[], +): Promise { + const selectedContractNames = selectedContracts + .map((key) => contracts[key]) + .filter((contract): contract is Contract => contract !== undefined) + .map((contract) => contract.name); + + const compileCommands = generateCompileCommands(selectedContracts); + const compileCommandsText = compileCommands.join("\n\n"); + + const readme = `# Midnight Contracts Wizard + +A Midnight contracts project with the following smart contracts: + +${selectedContractNames.map((name) => `- ${name}`).join("\n")} + +## Quick Start + +\`\`\`bash +# Compile smart contracts (IMPORTANT!) +${compileCommandsText} +\`\`\` + +## 🔥 Compiling Smart Contracts + +**This is the most important step!** Your \`.compact\` files need to be compiled before use: + +\`\`\`bash +# Compile each contract individually: +${compileCommandsText} +\`\`\` + +### What gets generated after compilation: + +\`\`\` +src/managed/ +├── tokenization/ # Compiled tokenization contract +│ ├── compiler/ # Compilation artifacts +│ ├── contract/ # Contract bytecode +│ ├── keys/ # Cryptographic keys +│ └── zkir/ # ZK proof system files +└── TokenizationLibrary/ # Compiled library + ├── compiler/ + ├── contract/ + ├── keys/ + └── zkir/ +\`\`\` + +## What's Included + +- **Smart Contracts**: Ready-to-compile \`.compact\` files in \`contracts/\` +- **Dependencies**: All necessary Midnight Network packages +- **Build Scripts**: Automated compilation and build process +- **TypeScript**: Full TypeScript support with type definitions +- **Standalone Project**: Includes \`.yarnrc.yml\` for independent operation + +## Available Commands + +- \`compact compile [source] [output]\` - **Compile individual smart contracts** + +## Project Structure + +\`\`\` +${projectName}/ +├── contracts/ # Source contract files (.compact) +├── src/ +│ ├── managed/ # Compiled contracts (after compact compile) +│ └── index.ts # Your application code +└── package.json # Dependencies and scripts +\`\`\` + +--- + +
+

Powered by MeshJS Team

+

Built with ❤️ on Midnight Network

+
+`; + + await fs.writeFile(path.join(projectDir, "README.md"), readme); +} + +async function createGitignore(projectDir: string): Promise { + const gitignoreContent = `# Compiled contracts (generated by compact compile) +src/managed/ + +# Node modules +node_modules/ + +# Build outputs +dist/ +build/ + +# Environment files +.env +.env.local +.env.production + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# OS files +.DS_Store +Thumbs.db + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Midnight Network compilation artifacts +*.prover +*.verifier +*.zkir +`; + + await fs.writeFile(path.join(projectDir, ".gitignore"), gitignoreContent); +} + +// Run the CLI +if (require.main === module) { + main().catch(console.error); +} + +export { main }; diff --git a/packages/midnight-contracts-wizard/src/install.ts b/packages/midnight-contracts-wizard/src/install.ts new file mode 100644 index 000000000..7233e35dc --- /dev/null +++ b/packages/midnight-contracts-wizard/src/install.ts @@ -0,0 +1,13 @@ +#!/usr/bin/env node +import fs from "fs"; +import path from "path"; + +// Make the main script executable +const indexPath = path.join(__dirname, "index.js"); +fs.chmodSync(indexPath, "755"); + +console.log("✅ midnight-contracts-wizard CLI is ready!"); +console.log("📦 To publish to npm:"); +console.log(" 1. npm login"); +console.log(" 2. npm publish"); +console.log(" 3. Users can then run: npx @meshsdk/midnight-contracts-wizard"); diff --git a/packages/midnight-contracts-wizard/tsconfig.json b/packages/midnight-contracts-wizard/tsconfig.json new file mode 100644 index 000000000..131d426d5 --- /dev/null +++ b/packages/midnight-contracts-wizard/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "module": "CommonJS", + "target": "ES2022", + "lib": ["ES2022"], + "moduleResolution": "node", + "esModuleInterop": true, + "skipLibCheck": true, + "strict": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "types": ["node"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"] +} diff --git a/packages/midnight-setup/package.json b/packages/midnight-setup/package.json index 6bbf4fcb2..18a1adc69 100644 --- a/packages/midnight-setup/package.json +++ b/packages/midnight-setup/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/midnight-setup", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "description": "Midnight Network integration SDK for MeshSDK - https://meshjs.dev/midnight", "main": "./dist/index.cjs", "browser": "./dist/index.js", diff --git a/scripts/mesh-cli/package.json b/scripts/mesh-cli/package.json index bef02038f..72bfdde3c 100644 --- a/scripts/mesh-cli/package.json +++ b/scripts/mesh-cli/package.json @@ -3,7 +3,7 @@ "description": "A quick and easy way to bootstrap your Web3 app using Mesh.", "homepage": "https://meshjs.dev", "author": "MeshJS", - "version": "1.9.0-beta.83", + "version": "1.9.0-beta.84", "license": "Apache-2.0", "type": "module", "main": "./dist/index.cjs", diff --git a/turbo.json b/turbo.json index 1010f53c1..5a73adcd3 100644 --- a/turbo.json +++ b/turbo.json @@ -3,7 +3,12 @@ "globalDependencies": ["**/.env.*local"], "tasks": { "build": { - "dependsOn": ["^build:mesh", "^build:docs", "^build:apps", "^build:scripts"], + "dependsOn": [ + "^build:mesh", + "^build:docs", + "^build:apps", + "^build:scripts" + ], "outputs": ["dist/**", ".next/**", "!.next/cache/**"] }, "build:apps": {