diff --git a/Clarinet.toml b/Clarinet.toml index 9bdfd06..51c345c 100644 --- a/Clarinet.toml +++ b/Clarinet.toml @@ -6,12 +6,12 @@ telemetry = true cache_dir = './.cache' requirements = [] [contracts.bootstrap] -path = 'contracts/bootstrap.clar' +path = 'contracts/proposals/bootstrap.clar' clarity_version = 2 epoch = 2.4 -[contracts.community-vault] -path = 'contracts/community-vault.clar' +[contracts.grants-vault] +path = 'contracts/extensions/grants-vault.clar' clarity_version = 2 epoch = 2.4 @@ -21,52 +21,45 @@ clarity_version = 2 epoch = 2.4 [contracts.extension-trait] -path = 'contracts/extension-trait.clar' +path = 'contracts/traits/extension-trait.clar' clarity_version = 2 epoch = 2.4 [contracts.membership-token] -path = 'contracts/membership-token.clar' +path = 'contracts/extensions/membership-token.clar' clarity_version = 2 epoch = 2.4 [contracts.milestone-disbursement] -path = 'contracts/milestone-disbursement.clar' +path = 'contracts/extensions/milestone-disbursement.clar' clarity_version = 2 epoch = 2.4 [contracts.proposal-submission] -path = 'contracts/proposal-submission.clar' +path = 'contracts/extensions/proposal-submission.clar' clarity_version = 2 epoch = 2.4 [contracts.proposal-trait] -path = 'contracts/proposal-trait.clar' +path = 'contracts/traits/proposal-trait.clar' clarity_version = 2 epoch = 2.4 [contracts.proposal-voting] -path = 'contracts/proposal-voting.clar' +path = 'contracts/extensions/proposal-voting.clar' clarity_version = 2 epoch = 2.4 [contracts.test-grant] -path = 'contracts/test-grant.clar' +path = 'contracts/test_proposals/test-grant.clar' clarity_version = 2 epoch = 2.4 [contracts.vault] -path = 'contracts/vault.clar' +path = 'contracts/extensions/vault.clar' clarity_version = 2 epoch = 2.4 -[contracts.community-vault-proposal] -path = 'contracts/community-vault-proposal.clar' -clarity_version = 2 -epoch = 2.4 -[repl.analysis] -passes = [] - [repl.analysis.check_checker] strict = false trusted_sender = false diff --git a/api/index.js b/api/index.js new file mode 100644 index 0000000..87a4d2e --- /dev/null +++ b/api/index.js @@ -0,0 +1,249 @@ +const express = require('express') +const app = express() + +const port = 3000 +app.use(express.json()); + +app.get('/', (req, res) => { + res.send('Hello, Express.js!'); +}); + +app.listen(port, () => { + console.log(`Listening on port ${port}`) +}) + +app.post("/api/bootstrap", async (req, res) => { + const events = req.body; + console.log(events) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + //Loop through each item in the apply array + events.apply.forEach((item) => { + // Loop through each transaction in the item + console.log(item) + item.transactions.forEach((transaction) => { + // If the transaction has operations, loop through them + if (transaction.operations?.length) { + transaction.operations.forEach((operation) => { + // Log the operation + console.log({ operation }); + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + console.log( + {events: transaction.metadata.receipt.events[0].data}, + {metadata: transaction.metadata}, + {transaction: transaction} + ) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + }); + } else { + console.log( + {events: transaction.metadata.receipt.events[0].data}, + {metadata: transaction.metadata}, + {transaction: transaction} + ) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + } + }); + console.log('/////////////////////////////////////END/////////////////////////////////////') + }); + + // Send a response back to Chainhook to acknowledge receipt of the event + res.status(200).send({ message: "Bootstrap added!" }); + }); + +app.post("/api/proposal-submission", async (req, res) => { + const events = req.body; + console.log(events) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + //Loop through each item in the apply array + events.apply.forEach((item) => { + // Loop through each transaction in the item + item.transactions.forEach((transaction) => { + // If the transaction has operations, loop through them + if (transaction.operations?.length) { + transaction.operations.forEach((operation) => { + // Log the operation + console.log({ operation }); + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + }); + } else { + console.log( + {events: transaction.metadata.receipt.events[0].data}, + {metadata: transaction.metadata}, + {transaction: transaction} + ) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + } + }); + console.log('///////////////////////////////////////// END \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\') + }); + + + // Send a response back to Chainhook to acknowledge receipt of the event + res.status(200).send({ message: "Proposal added!" }); +}); + +app.post("/api/vote", async (req, res) => { + const events = req.body; + console.log(events) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + //Loop through each item in the apply array + events.apply.forEach((item) => { + // Loop through each transaction in the item + item.transactions.forEach((transaction) => { + // If the transaction has operations, loop through them + if (transaction.operations?.length) { + transaction.operations.forEach((operation) => { + // Log the operation + console.log({ operation }); + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + }); + } else { + console.log( + {events: transaction.metadata.receipt.events[0].data}, + {metadata: transaction.metadata}, + {transaction: transaction} + ) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + } + }); + console.log('///////////////////////////////////////// END \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\') + }); + + + // Send a response back to Chainhook to acknowledge receipt of the event + res.status(200).send({ message: "Vote added!" }); +}); + +app.post("/api/bootstrap", async (req, res) => { + const events = req.body; + console.log(events) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + //Loop through each item in the apply array + events.apply.forEach((item) => { + // Loop through each transaction in the item + item.transactions.forEach((transaction) => { + // If the transaction has operations, loop through them + if (transaction.operations?.length) { + transaction.operations.forEach((operation) => { + // Log the operation + console.log({ operation }); + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + }); + } else { + console.log( + {events: transaction.metadata.receipt.events[0].data}, + {metadata: transaction.metadata}, + {transaction: transaction} + ) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + } + }); + console.log('///////////////////////////////////////// END \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\') + }); + + + // Send a response back to Chainhook to acknowledge receipt of the event + res.status(200).send({ message: "Vote added!" }); +}); + +app.post("/api/test", async (req, res) => { + const events = req.body; + console.log(events) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + //Loop through each item in the apply array + events.apply.forEach((item) => { + // Loop through each transaction in the item + item.transactions.forEach((transaction) => { + // If the transaction has operations, loop through them + if (transaction.operations?.length) { + transaction.operations.forEach((operation) => { + // Log the operation + console.log({ operation }); + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + }); + } else { + console.log( + {events: transaction.metadata.receipt.events[0].data}, + {metadata: transaction.metadata}, + {transaction: transaction} + ) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + } + }); + console.log('///////////////////////////////////////// END \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\') + }); + + // Send a response back to Chainhook to acknowledge receipt of the event + res.status(200).send({ message: "Test Success!" }); +}); + + app.post("/api/conclude-proposal", async (req, res) => { + const events = req.body; + console.log(events) + console.log(' ') + console.log('**********************************************************************************************************') + console.log(' ') + //Loop through each item in the apply array + events.apply.forEach((item) => { + // Loop through each transaction in the item + console.log(item) + // item.transactions.forEach((transaction) => { + // // If the transaction has operations, loop through them + // if (transaction.operations?.length) { + // transaction.operations.forEach((operation) => { + // // Log the operation + // console.log({ operation }); + // console.log(' ') + // console.log('**********************************************************************************************************') + // console.log(' ') + // }); + // } else { + // console.log( + // {events: transaction.metadata.receipt.events[0].data}, + // {metadata: transaction.metadata}, + // {transaction: transaction} + // ) + // console.log(' ') + // console.log('**********************************************************************************************************') + // console.log(' ') + // } + // }); + console.log('///////////////////////////////////////// END \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\') + }); + + + // Send a response back to Chainhook to acknowledge receipt of the event + res.status(200).send({ message: "Conclusion Success!" }); +}); diff --git a/api/package-lock.json b/api/package-lock.json new file mode 100644 index 0000000..93497bd --- /dev/null +++ b/api/package-lock.json @@ -0,0 +1,657 @@ +{ + "name": "api", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "api", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "express": "^4.18.2" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + } + } +} diff --git a/api/package.json b/api/package.json new file mode 100644 index 0000000..1671da7 --- /dev/null +++ b/api/package.json @@ -0,0 +1,15 @@ +{ + "name": "api", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node index.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "express": "^4.18.2" + } +} diff --git a/chainhooks/bootstrap-chainhook.json b/chainhooks/bootstrap-chainhook.json new file mode 100644 index 0000000..07619ce --- /dev/null +++ b/chainhooks/bootstrap-chainhook.json @@ -0,0 +1,23 @@ +{ + "chain": "stacks", + "uuid": "1", + "name": "Bootstrap", + "version": 1, + "networks": { + "devnet": { + "if_this": { + "scope": "contract_call", + "contract_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.core", + "method": "construct" + }, + "then_that": { + "http_post": { + "url": "http://localhost:3000/api/bootstrap", + "authorization_header": "1234" + } + }, + "decode_clarity_values": true, + "start_block": 0 + } + } +} diff --git a/chainhooks/conclude-chainhook.json b/chainhooks/conclude-chainhook.json new file mode 100644 index 0000000..d741ea1 --- /dev/null +++ b/chainhooks/conclude-chainhook.json @@ -0,0 +1,23 @@ +{ + "chain": "stacks", + "uuid": "1", + "name": "hello-test chainhook", + "version": 1, + "networks": { + "devnet": { + "start_block": 0, + "end_block": 100, + "if_this": { + "scope": "contract_call", + "contract_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.proposal-voting", + "method": "conclude" + }, + "then_that": { + "http_post": { + "url": "http://localhost:3000/api/conclude-proposal", + "authorization_header": "1234" + } + } + } + } +} \ No newline at end of file diff --git a/chainhooks/proposal-chainhook.json b/chainhooks/proposal-chainhook.json new file mode 100644 index 0000000..ce7ccab --- /dev/null +++ b/chainhooks/proposal-chainhook.json @@ -0,0 +1,23 @@ +{ + "chain": "stacks", + "uuid": "1", + "name": "Bootstrap", + "version": 1, + "networks": { + "devnet": { + "if_this": { + "scope": "contract_call", + "contract_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.proposal-submission", + "method": "propose" + }, + "then_that": { + "http_post": { + "url": "http://localhost:3000/api/proposal-submission", + "authorization_header": "1234" + } + }, + "decode_clarity_values": true, + "start_block": 0 + } + } +} diff --git a/chainhooks/proposal-vote.json b/chainhooks/proposal-vote.json new file mode 100644 index 0000000..4a54575 --- /dev/null +++ b/chainhooks/proposal-vote.json @@ -0,0 +1,23 @@ +{ + "chain": "stacks", + "uuid": "1", + "name": "Bootstrap", + "version": 1, + "networks": { + "devnet": { + "if_this": { + "scope": "contract_call", + "contract_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.proposal-voting", + "method": "vote" + }, + "then_that": { + "http_post": { + "url": "http://localhost:3000/api/vote", + "authorization_header": "1234" + } + }, + "decode_clarity_values": true, + "start_block": 0 + } + } +} \ No newline at end of file diff --git a/chainhooks/test-chainhook.json b/chainhooks/test-chainhook.json new file mode 100644 index 0000000..3babcd6 --- /dev/null +++ b/chainhooks/test-chainhook.json @@ -0,0 +1,24 @@ +{ + "chain": "stacks", + "uuid": "1", + "name": "hello-test chainhook", + "version": 1, + "networks": { + "devnet": { + "decode_clarity_values": true, + "start_block": 0, + "end_block": 100, + "if_this": { + "scope": "contract_call", + "contract_identifier": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.core", + "method": "test" + }, + "then_that": { + "http_post": { + "url": "http://localhost:3000/api/bootstrap", + "authorization_header": "1234" + } + } + } + } +} \ No newline at end of file diff --git a/contracts/community-vault-proposal.clar b/contracts/community-vault-proposal.clar deleted file mode 100644 index 9cee29e..0000000 --- a/contracts/community-vault-proposal.clar +++ /dev/null @@ -1,22 +0,0 @@ -;; title: build community-vault-proposal -;; summary: If this proposal passes, the vault extension will be activated. -;; A community fund of 1000 membership will be minted and transfered to the vault. - -;; traits -(impl-trait .proposal-trait.proposal-trait) - -;; token definitions -;; - -;; constants -(define-constant initial-vault-fund u1000) - -;; public functions -(define-public (execute (sender principal)) - (begin - (try! (contract-call? .core set-extension .community-vault true)) - (try! (contract-call? .membership-token mint initial-vault-fund .vault)) - (ok true) - ) -) - diff --git a/contracts/core.clar b/contracts/core.clar index a6c5088..ad94b1e 100644 --- a/contracts/core.clar +++ b/contracts/core.clar @@ -1,4 +1,3 @@ - ;; title: core ;; version: ;; summary: @@ -25,6 +24,15 @@ (define-map extensions principal bool) ;; public functions + +(define-public (test) + (begin + (print "Test --- Hello world") + (ok u1) + ) +) + + (define-public (set-extension (extension principal) (enabled bool)) (begin (try! (is-self-or-extension)) diff --git a/contracts/community-vault.clar b/contracts/extensions/grants-vault.clar similarity index 63% rename from contracts/community-vault.clar rename to contracts/extensions/grants-vault.clar index 9f2ea35..cf20c54 100644 --- a/contracts/community-vault.clar +++ b/contracts/extensions/grants-vault.clar @@ -1,4 +1,4 @@ -;; title: community-vault +;; title: grant-vault ;; version: ;; summary: ;; description: @@ -8,7 +8,7 @@ ;; constants (define-constant ERR_UNAUTHORIZED (err u4001)) -(define-constant ERR_VAULT_STACKS_BALANCE_INSUFFICIENT (err u4002)) +(define-constant ERR_GRANT_VAULT_STACKS_BALANCE_INSUFFICIENT (err u4002)) ;; data vars ;; @@ -21,17 +21,17 @@ (ok (asserts! (or (is-eq tx-sender .core) (contract-call? .core is-extension contract-caller)) ERR_UNAUTHORIZED)) ) -(define-public (vault-transfer-membership-token (amount uint) (recipient principal)) +(define-public (grant-vault-transfer-membership-token (amount uint) (recipient principal)) (begin (try! (is-dao-or-extension)) (as-contract (contract-call? .membership-token transfer amount tx-sender recipient)) ) ) -(define-public (vault-transfer-stx (amount uint) (recipient principal)) +(define-public (grant-vault-transfer-stx (amount uint) (recipient principal)) (begin (try! (is-dao-or-extension)) - (asserts! (<= (vault-get-stx-balance) amount) ERR_VAULT_STACKS_BALANCE_INSUFFICIENT) + (asserts! (<= (grant-vault-get-stx-balance) amount) ERR_GRANT_VAULT_STACKS_BALANCE_INSUFFICIENT) (as-contract (stx-transfer? amount tx-sender recipient)) ) ) @@ -41,11 +41,11 @@ ) ;; read only functions -(define-read-only (vault-get-membership-token-balance) +(define-read-only (grant-vault-get-membership-token-balance) (as-contract (contract-call? .membership-token get-balance tx-sender)) ) -(define-read-only (vault-get-stx-balance) +(define-read-only (grant-vault-get-stx-balance) (as-contract (stx-get-balance tx-sender)) ) diff --git a/contracts/membership-token.clar b/contracts/extensions/membership-token.clar similarity index 93% rename from contracts/membership-token.clar rename to contracts/extensions/membership-token.clar index cf52648..88c09bb 100644 --- a/contracts/membership-token.clar +++ b/contracts/extensions/membership-token.clar @@ -5,7 +5,7 @@ ;; description: ;; traits -;; +(impl-trait .extension-trait.extension-trait) ;; token definitions (define-fungible-token sGrant) @@ -79,6 +79,9 @@ (ok (var-get tokenUri)) ) +(define-public (callback (sender principal) (memo (buff 34))) + (ok true) +) ;; private functions (define-private (mint-many-iter (item {amount: uint, recipient: principal})) (ft-mint? sGrant (get amount item) (get recipient item)) diff --git a/contracts/milestone-disbursement.clar b/contracts/extensions/milestone-disbursement.clar similarity index 87% rename from contracts/milestone-disbursement.clar rename to contracts/extensions/milestone-disbursement.clar index 9e3d41b..d1225ee 100644 --- a/contracts/milestone-disbursement.clar +++ b/contracts/extensions/milestone-disbursement.clar @@ -30,10 +30,6 @@ (ok (asserts! (or (is-eq tx-sender .core) (contract-call? .core is-extension contract-caller)) ERR_UNAUTHORIZED)) ) -;;Need function here that allows principal of the grant to initiate another proposal that sets -;;grant amount to 0 but adds a withdraw amount. Would not be recorded as a grant, just a proposal to approve -;;if it is judged that a milestone is reached. Hit proposal voting function not proposal submission. - (define-public (add-grant (proposal principal) (data @@ -53,7 +49,7 @@ ) ) -;;mint and disburse function +;;disburse function (define-public (disburse-funds (grant principal) (amount uint)) (let ( diff --git a/contracts/proposal-submission.clar b/contracts/extensions/proposal-submission.clar similarity index 93% rename from contracts/proposal-submission.clar rename to contracts/extensions/proposal-submission.clar index 3a4003e..a6a8d56 100644 --- a/contracts/proposal-submission.clar +++ b/contracts/extensions/proposal-submission.clar @@ -1,4 +1,3 @@ - ;; title: proposal-submission ;; version: ;; summary: @@ -22,14 +21,14 @@ ;; data maps (define-map parameters (string-ascii 34) uint) -(map-set parameters "proposal-duration" u1440) ;; ~10 days based on a ~10 minute block time. +(map-set parameters "proposal-duration" u10) ;; ~10 days based on a ~10 minute block time. ;; public functions (define-public (is-dao-or-extension) (ok (asserts! (or (is-eq tx-sender .core) (contract-call? .core is-extension contract-caller)) ERR_UNAUTHORIZED)) ) -(define-public (propose (proposal ) (title (string-ascii 50)) (description (string-utf8 500)) (grant-amount uint) (withdraw-amount uint)) +(define-public (propose (proposal ) (title (string-ascii 50)) (description (string-utf8 500)) (grant-amount uint)) (let ( (id (var-get proposal-id)) diff --git a/contracts/proposal-voting.clar b/contracts/extensions/proposal-voting.clar similarity index 97% rename from contracts/proposal-voting.clar rename to contracts/extensions/proposal-voting.clar index 4481473..a00848e 100644 --- a/contracts/proposal-voting.clar +++ b/contracts/extensions/proposal-voting.clar @@ -116,7 +116,7 @@ (map-set proposals (contract-of proposal) (merge proposal-data {concluded: true, passed: passed})) (print {event: "conclude", proposal: proposal, passed: passed}) (and passed (try! (contract-call? .core execute proposal tx-sender))) - (try! (contract-call? .milestone-disbursement add-grant (contract-of proposal) data)) + ;; (try! (contract-call? .milestone-disbursement add-grant (contract-of proposal) data)) (ok passed) ) ) diff --git a/contracts/vault.clar b/contracts/extensions/vault.clar similarity index 100% rename from contracts/vault.clar rename to contracts/extensions/vault.clar diff --git a/contracts/bootstrap.clar b/contracts/proposals/bootstrap.clar similarity index 93% rename from contracts/bootstrap.clar rename to contracts/proposals/bootstrap.clar index 4cd2eb5..55abee0 100644 --- a/contracts/bootstrap.clar +++ b/contracts/proposals/bootstrap.clar @@ -1,4 +1,3 @@ - ;; title: bootstrap ;; version: ;; summary: @@ -28,6 +27,8 @@ {extension: .membership-token, enabled: true} {extension: .proposal-voting, enabled: true} {extension: .proposal-submission, enabled: true} + {extension: .milestone-disbursement, enabled: true} + {extension: .grant-vault, enabled: true} {extension: .vault, enabled: true} ) )) diff --git a/contracts/test-grant.clar b/contracts/test_proposals/test-grant.clar similarity index 100% rename from contracts/test-grant.clar rename to contracts/test_proposals/test-grant.clar diff --git a/contracts/extension-trait.clar b/contracts/traits/extension-trait.clar similarity index 100% rename from contracts/extension-trait.clar rename to contracts/traits/extension-trait.clar diff --git a/contracts/proposal-trait.clar b/contracts/traits/proposal-trait.clar similarity index 100% rename from contracts/proposal-trait.clar rename to contracts/traits/proposal-trait.clar diff --git a/deployments/default.devnet-plan.yaml b/deployments/default.devnet-plan.yaml new file mode 100644 index 0000000..d0427f9 --- /dev/null +++ b/deployments/default.devnet-plan.yaml @@ -0,0 +1,88 @@ +--- +id: 0 +name: Devnet deployment +network: devnet +stacks-node: "http://localhost:20443" +bitcoin-node: "http://devnet:devnet@localhost:18443" +plan: + batches: + - id: 0 + transactions: + - contract-publish: + contract-name: extension-trait + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 3340 + path: contracts/traits/extension-trait.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: proposal-trait + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 3190 + path: contracts/traits/proposal-trait.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: core + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 27160 + path: contracts/core.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: membership-token + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 20200 + path: contracts/extensions/membership-token.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: bootstrap + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 15250 + path: contracts/proposals/bootstrap.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: grants-vault + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 13170 + path: contracts/extensions/grants-vault.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: vault + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 12700 + path: contracts/extensions/vault.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: milestone-disbursement + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 23550 + path: contracts/extensions/milestone-disbursement.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: proposal-voting + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 43150 + path: contracts/extensions/proposal-voting.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: proposal-submission + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 17110 + path: contracts/extensions/proposal-submission.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: test-grant + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 6380 + path: contracts/test_proposals/test-grant.clar + anchor-block-only: true + clarity-version: 2 + epoch: "2.4" diff --git a/history.txt b/history.txt index b9025ec..618fe8f 100644 --- a/history.txt +++ b/history.txt @@ -25,3 +25,15 @@ (contract-call? .proposal-voting conclude .vault-proposal) ::get_assets_maps ::reload +(contract-call? .boostrap execute tx-sender) +(contract-call? .bootstrap execute tx-sender) +(contract-call? .core execute tx-sender) +(contract-call? .core execute .bootstrap tx-sender) +(contract-call? .core set-extension .bootstrap true) +(contract-call? .core construct .bootstrap) +(contract-call? .core construct) +(contract-call? .core construct .bootstrap) +(contract-call? .proposal-submission propose test test u100 u100) +(contract-call? .proposal-submission propose .proposal-trait test test u100 u100) +(contract-call? .proposal-submission propose .proposal test test u100 u100) +(contract-call? .proposal-submission propose proposal-trait test test u100 u100) diff --git a/test-grant/.gitignore b/test-grant/.gitignore deleted file mode 100644 index 76c2842..0000000 --- a/test-grant/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ - -**/settings/Mainnet.toml -**/settings/Testnet.toml -.cache/** -history.txt - -logs -*.log -npm-debug.log* -coverage -*.info -costs-reports.json -node_modules diff --git a/test-grant/.vscode/settings.json b/test-grant/.vscode/settings.json deleted file mode 100644 index 3062519..0000000 --- a/test-grant/.vscode/settings.json +++ /dev/null @@ -1,4 +0,0 @@ - -{ - "files.eol": "\n" -} diff --git a/test-grant/.vscode/tasks.json b/test-grant/.vscode/tasks.json deleted file mode 100644 index 7fc3ba9..0000000 --- a/test-grant/.vscode/tasks.json +++ /dev/null @@ -1,19 +0,0 @@ - -{ - "version": "2.0.0", - "tasks": [ - { - "label": "check contracts", - "group": "test", - "type": "shell", - "command": "clarinet check" - }, - {{ - "type": "npm", - "script": "test", - "group": "test", - "problemMatcher": [], - "label": "npm test" - } - ] -} diff --git a/test-grant/Clarinet.toml b/test-grant/Clarinet.toml deleted file mode 100644 index 566935b..0000000 --- a/test-grant/Clarinet.toml +++ /dev/null @@ -1,22 +0,0 @@ - -[project] -name = "test-grant" -description = "" -authors = [] -telemetry = false -cache_dir = "./.cache" - -# [contracts.counter] -# path = "contracts/counter.clar" - -[repl.analysis] -passes = ["check_checker"] -check_checker = { trusted_sender = false, trusted_caller = false, callee_filter = false } - -# Check-checker settings: -# trusted_sender: if true, inputs are trusted after tx_sender has been checked. -# trusted_caller: if true, inputs are trusted after contract-caller has been checked. -# callee_filter: if true, untrusted data may be passed into a private function without a -# warning, if it gets checked inside. This check will also propagate up to the -# caller. -# More informations: https://www.hiro.so/blog/new-safety-checks-in-clarinet diff --git a/test-grant/package.json b/test-grant/package.json deleted file mode 100644 index 66a115b..0000000 --- a/test-grant/package.json +++ /dev/null @@ -1,23 +0,0 @@ - -{ - "name": "test-grant-tests", - "version": "1.0.0", - "description": "Run unit tests on this project.", - "private": true, - "scripts": { - "test": "vitest run", - "test:report": "vitest run -- --coverage --costs", - "test:watch": "chokidar \"tests/**/*.ts\" \"contracts/**/*.clar\" -c \"npm run test:report\"" - }, - "author": "", - "license": "ISC", - "dependencies": { - "@hirosystems/clarinet-sdk": "^1.0.0", - "@stacks/transactions": "^6.9.0", - "chokidar-cli": "^3.0.0", - "typescript": "^5.2.2", - "vite": "^4.4.9", - "vitest": "^0.34.4", - "vitest-environment-clarinet": "^1.0.0" - } -} diff --git a/test-grant/settings/Devnet.toml b/test-grant/settings/Devnet.toml deleted file mode 100644 index 68f53cc..0000000 --- a/test-grant/settings/Devnet.toml +++ /dev/null @@ -1,150 +0,0 @@ -[network] -name = "devnet" -deployment_fee_rate = 10 - -[accounts.deployer] -mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw" -balance = 100_000_000_000_000 -# secret_key: 753b7cc01a1a2e86221266a154af739463fce51219d97e4f856cd7200c3bd2a601 -# stx_address: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM -# btc_address: mqVnk6NPRdhntvfm4hh9vvjiRkFDUuSYsH - -[accounts.wallet_1] -mnemonic = "sell invite acquire kitten bamboo drastic jelly vivid peace spawn twice guilt pave pen trash pretty park cube fragile unaware remain midnight betray rebuild" -balance = 100_000_000_000_000 -# secret_key: 7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801 -# stx_address: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5 -# btc_address: mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC - -[accounts.wallet_2] -mnemonic = "hold excess usual excess ring elephant install account glad dry fragile donkey gaze humble truck breeze nation gasp vacuum limb head keep delay hospital" -balance = 100_000_000_000_000 -# secret_key: 530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101 -# stx_address: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG -# btc_address: muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG - -[accounts.wallet_3] -mnemonic = "cycle puppy glare enroll cost improve round trend wrist mushroom scorpion tower claim oppose clever elephant dinosaur eight problem before frozen dune wagon high" -balance = 100_000_000_000_000 -# secret_key: d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901 -# stx_address: ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC -# btc_address: mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7 - -[accounts.wallet_4] -mnemonic = "board list obtain sugar hour worth raven scout denial thunder horse logic fury scorpion fold genuine phrase wealth news aim below celery when cabin" -balance = 100_000_000_000_000 -# secret_key: f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701 -# stx_address: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND -# btc_address: mg1C76bNTutiCDV3t9nWhZs3Dc8LzUufj8 - -[accounts.wallet_5] -mnemonic = "hurry aunt blame peanut heavy update captain human rice crime juice adult scale device promote vast project quiz unit note reform update climb purchase" -balance = 100_000_000_000_000 -# secret_key: 3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801 -# stx_address: ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB -# btc_address: mweN5WVqadScHdA81aATSdcVr4B6dNokqx - -[accounts.wallet_6] -mnemonic = "area desk dutch sign gold cricket dawn toward giggle vibrant indoor bench warfare wagon number tiny universe sand talk dilemma pottery bone trap buddy" -balance = 100_000_000_000_000 -# secret_key: 7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01 -# stx_address: ST3AM1A56AK2C1XAFJ4115ZSV26EB49BVQ10MGCS0 -# btc_address: mzxXgV6e4BZSsz8zVHm3TmqbECt7mbuErt - -[accounts.wallet_7] -mnemonic = "prevent gallery kind limb income control noise together echo rival record wedding sense uncover school version force bleak nuclear include danger skirt enact arrow" -balance = 100_000_000_000_000 -# secret_key: b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401 -# stx_address: ST3PF13W7Z0RRM42A8VZRVFQ75SV1K26RXEP8YGKJ -# btc_address: n37mwmru2oaVosgfuvzBwgV2ysCQRrLko7 - -[accounts.wallet_8] -mnemonic = "female adjust gallery certain visit token during great side clown fitness like hurt clip knife warm bench start reunion globe detail dream depend fortune" -balance = 100_000_000_000_000 -# secret_key: 6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01 -# stx_address: ST3NBRSFKX28FQ2ZJ1MAKX58HKHSDGNV5N7R21XCP -# btc_address: n2v875jbJ4RjBnTjgbfikDfnwsDV5iUByw - -[accounts.faucet] -mnemonic = "shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform" -balance = 100_000_000_000_000 -# secret_key: de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801 -# stx_address: STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 -# btc_address: mjSrB3wS4xab3kYqFktwBzfTdPg367ZJ2d - -[devnet] -disable_stacks_explorer = false -disable_stacks_api = false -# disable_subnet_api = false -# disable_bitcoin_explorer = true -# working_dir = "tmp/devnet" -# stacks_node_events_observers = ["host.docker.internal:8002"] -# miner_mnemonic = "fragile loan twenty basic net assault jazz absorb diet talk art shock innocent float punch travel gadget embrace caught blossom hockey surround initial reduce" -# miner_derivation_path = "m/44'/5757'/0'/0/0" -# faucet_mnemonic = "shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform" -# faucet_derivation_path = "m/44'/5757'/0'/0/0" -# orchestrator_port = 20445 -# bitcoin_node_p2p_port = 18444 -# bitcoin_node_rpc_port = 18443 -# bitcoin_node_username = "devnet" -# bitcoin_node_password = "devnet" -# bitcoin_controller_block_time = 30_000 -# stacks_node_rpc_port = 20443 -# stacks_node_p2p_port = 20444 -# stacks_api_port = 3999 -# stacks_api_events_port = 3700 -# bitcoin_explorer_port = 8001 -# stacks_explorer_port = 8000 -# postgres_port = 5432 -# postgres_username = "postgres" -# postgres_password = "postgres" -# postgres_database = "postgres" -# bitcoin_node_image_url = "quay.io/hirosystems/bitcoind:devnet-v3" -# stacks_node_image_url = "quay.io/hirosystems/stacks-node:devnet-2.4.0.0.0" -# stacks_api_image_url = "hirosystems/stacks-blockchain-api:latest" -# stacks_explorer_image_url = "hirosystems/explorer:latest" -# bitcoin_explorer_image_url = "quay.io/hirosystems/bitcoin-explorer:devnet" -# postgres_image_url = "postgres:14" -# enable_subnet_node = true -# subnet_node_image_url = "hirosystems/stacks-subnets:0.8.1" -# subnet_leader_mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw" -# subnet_leader_derivation_path = "m/44'/5757'/0'/0/0" -# subnet_contract_id = "ST173JK7NZBA4BS05ZRATQH1K89YJMTGEH1Z5J52E.subnet-v3-0-1" -# subnet_node_rpc_port = 30443 -# subnet_node_p2p_port = 30444 -# subnet_events_ingestion_port = 30445 -# subnet_node_events_observers = ["host.docker.internal:8002"] -# subnet_api_image_url = "hirosystems/stacks-blockchain-api:latest" -# subnet_api_postgres_database = "subnet_api" - -# For testing in epoch 2.1 / using Clarity2 -# epoch_2_0 = 100 -# epoch_2_05 = 100 -# epoch_2_1 = 101 -# pox_2_activation = 102 -# epoch_2_2 = 103 -# epoch_2_3 = 104 -# epoch_2_4 = 105 - - -# Send some stacking orders -[[devnet.pox_stacking_orders]] -start_at_cycle = 3 -duration = 12 -wallet = "wallet_1" -slots = 2 -btc_address = "mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC" - -[[devnet.pox_stacking_orders]] -start_at_cycle = 3 -duration = 12 -wallet = "wallet_2" -slots = 1 -btc_address = "muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG" - -[[devnet.pox_stacking_orders]] -start_at_cycle = 3 -duration = 12 -wallet = "wallet_3" -slots = 1 -btc_address = "mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7" diff --git a/test-grant/tsconfig.json b/test-grant/tsconfig.json deleted file mode 100644 index 1bdaf36..0000000 --- a/test-grant/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ - -{ - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ESNext"], - "skipLibCheck": true, - - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - - "strict": true, - "noImplicitAny": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": [ - "node_modules/@hirosystems/clarinet-sdk/vitest-helpers/src", - "tests" - ] -} diff --git a/test-grant/vitest.config.js b/test-grant/vitest.config.js deleted file mode 100644 index 36a2261..0000000 --- a/test-grant/vitest.config.js +++ /dev/null @@ -1,37 +0,0 @@ - -/// - -import { defineConfig } from "vite"; -import { vitestSetupFilePath, getClarinetVitestsArgv } from "@hirosystems/clarinet-sdk/vitest"; - -/* - In this file, Vitest is configured so that it works seamlessly with Clarinet and the Simnet. - - The `vitest-environment-clarinet` will initialise the clarinet-sdk - and make the `simnet` object available globally in the test files. - - `vitestSetupFilePath` points to a file in the `@hirosystems/clarinet-sdk` package that does two things: - - run `before` hooks to initialize the simnet and `after` hooks to collect costs and coverage reports. - - load custom vitest matchers to work with Clarity values (such as `expect(...).toBeUint()`) - - The `getClarinetVitestsArgv()` will parse options passed to the command `vitest run --` - - vitest run -- --manifest ./Clarinet.toml # pass a custom path - - vitest run -- --coverage --costs # collect coverage and cost reports -*/ - -export default defineConfig({ - test: { - environment: "clarinet", // use vitest-environment-clarinet - singleThread: true, - setupFiles: [ - vitestSetupFilePath, - // custom setup files can be added here - ], - environmentOptions: { - clarinet: { - ...getClarinetVitestsArgv(), - // add or override options - }, - }, - }, -}); diff --git a/web b/web new file mode 160000 index 0000000..5572663 --- /dev/null +++ b/web @@ -0,0 +1 @@ +Subproject commit 5572663145e93a26215f1afe777928dee8db1b03