├── .DS_Store ├── .gitignore ├── LICENSE ├── Labs ├── .DS_Store └── UCA │ ├── .DS_Store │ ├── Definitions │ ├── .DS_Store │ ├── LearningToken1 │ │ └── latest │ │ │ ├── LearningToken1.json │ │ │ ├── LearningToken1.md │ │ │ └── LearningToken1.proto │ └── LearningToken2 │ │ └── latest │ │ ├── LearningToken2.json │ │ ├── LearningToken2.md │ │ └── LearningToken2.proto │ ├── Formulas │ ├── .DS_Store │ ├── tF{~d,m,a,r,b,t,q}+phDR+phGL │ │ └── latest │ │ │ ├── tF{~d,m,a,r,b,t,q}+phDR+phGL.json │ │ │ ├── tF{~d,m,a,r,b,t,q}+phDR+phGL.md │ │ │ └── tF{~d,m,a,r,b,t,q}+phDR+phGL.proto │ └── tN{~d,~t,m,a,r}+phDR+phGL │ │ └── latest │ │ ├── tN{~d,~t,m,a,r}+phDR+phGL.json │ │ ├── tN{~d,~t,m,a,r}+phDR+phGL.md │ │ └── tN{~d,~t,m,a,r}+phDR+phGL.proto │ └── Specifications │ ├── .DS_Store │ ├── LearningToken1 │ ├── .DS_Store │ └── latest │ │ ├── .DS_Store │ │ ├── LearningToken1-spec.docx │ │ └── LearningToken1-spec.pdf │ └── LearningToken2 │ ├── .DS_Store │ └── latest │ ├── LearningToken2-spec.docx │ └── LearningToken2-spec.pdf ├── Practices └── community-reward-token │ ├── README.md │ └── artifacts │ ├── indivisible │ ├── indivisible.json │ └── indivisible.proto │ ├── roles │ ├── roles.json │ └── roles.proto │ ├── supply-control │ ├── supply-control.json │ └── supply-control.proto │ ├── transferable │ ├── transferable.json │ └── transferable.proto │ └── whole_fungible │ ├── whole-fungible.json │ └── whole-fungible.proto ├── README.md ├── npm_package ltsdk ├── .gitignore ├── README.md ├── dist │ ├── src │ │ ├── index.d.ts │ │ ├── index.js │ │ ├── zoomprocessor.d.ts │ │ └── zoomprocessor.js │ └── tests │ │ ├── zoomprocessor.test.d.ts │ │ └── zoomprocessor.test.js ├── jest.config.js ├── package-lock.json ├── package.json ├── src │ ├── index.ts │ └── zoomprocessor.ts ├── tests │ └── zoomprocessor.test.ts ├── tsconfig.json └── types │ └── index.d.ts └── src ├── .DS_Store ├── README.md ├── learning-token-backend ├── .env.example ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── .vscode │ └── settings.json ├── Dockerfile ├── LICENSE ├── README.md ├── docker-compose.yml ├── nest-cli.json ├── package.json ├── src │ ├── app.controller.ts │ ├── app.module.ts │ ├── app.service.ts │ ├── cache │ │ ├── cache.keys.ts │ │ └── cache.module.ts │ ├── common │ │ ├── decorators │ │ │ └── roles.decorator.ts │ │ ├── filters │ │ │ ├── http-exception.filter.ts │ │ │ └── models │ │ │ │ └── http-exception-response.interface.ts │ │ ├── guards │ │ │ ├── access-control.guard.ts │ │ │ ├── jwt-auth.guard.ts │ │ │ └── sdk.guard.ts │ │ ├── helpers │ │ │ └── utils.helper.ts │ │ └── pipes │ │ │ ├── response.interceptor.ts │ │ │ └── validation.pipe.ts │ ├── config │ │ ├── env.validation.ts │ │ ├── jwt.config.ts │ │ ├── smtp.config.ts │ │ ├── typeorm.config-migrations.ts │ │ └── typeorm.config.ts │ ├── contract-abi │ │ └── learning-token-abi.json │ ├── main.ts │ ├── modules │ │ ├── admins │ │ │ ├── dto │ │ │ │ └── create-user.dto.ts │ │ │ ├── entities │ │ │ │ └── user.entity.ts │ │ │ ├── enums │ │ │ │ └── user.enum.ts │ │ │ ├── users.controller.ts │ │ │ ├── users.module.ts │ │ │ └── users.service.ts │ │ ├── auth │ │ │ ├── auth.controller.ts │ │ │ ├── auth.module.ts │ │ │ ├── dto │ │ │ │ └── auth.dto.ts │ │ │ ├── service │ │ │ │ ├── auth.service.ts │ │ │ │ └── jwt.service.ts │ │ │ └── strategy │ │ │ │ └── jwt.strategy.ts │ │ ├── event │ │ │ ├── dto │ │ │ │ ├── create-event.dto.ts │ │ │ │ ├── create-scoring-guide.dto.ts │ │ │ │ └── update-event.dto.ts │ │ │ ├── entities │ │ │ │ ├── event.entity.ts │ │ │ │ └── scoring-guide.entity.ts │ │ │ ├── event.controller.spec.ts │ │ │ ├── event.controller.ts │ │ │ ├── event.module.ts │ │ │ ├── event.service.spec.ts │ │ │ └── event.service.ts │ │ ├── institutions │ │ │ ├── dto │ │ │ │ ├── create-institution.dto.ts │ │ │ │ └── update-institution.dto.ts │ │ │ ├── entities │ │ │ │ └── institution.entity.ts │ │ │ ├── institutions.controller.spec.ts │ │ │ ├── institutions.controller.ts │ │ │ ├── institutions.module.ts │ │ │ ├── institutions.service.spec.ts │ │ │ └── institutions.service.ts │ │ ├── instructors │ │ │ ├── dto │ │ │ │ ├── create-instructor.dto.ts │ │ │ │ └── update-instructor.dto.ts │ │ │ ├── entities │ │ │ │ └── instructor.entity.ts │ │ │ ├── instructors.controller.spec.ts │ │ │ ├── instructors.controller.ts │ │ │ ├── instructors.module.ts │ │ │ ├── instructors.service.spec.ts │ │ │ └── instructors.service.ts │ │ ├── learners │ │ │ ├── dto │ │ │ │ ├── create-learner.dto.ts │ │ │ │ └── update-learner.dto.ts │ │ │ ├── entities │ │ │ │ └── learner.entity.ts │ │ │ ├── learners.controller.spec.ts │ │ │ ├── learners.controller.ts │ │ │ ├── learners.module.ts │ │ │ ├── learners.service.spec.ts │ │ │ └── learners.service.ts │ │ ├── postevent │ │ │ ├── dto │ │ │ │ ├── create-postevent.dto.ts │ │ │ │ └── update-postevent.dto.ts │ │ │ ├── entities │ │ │ │ └── postevent.entity.ts │ │ │ ├── postevent.controller.spec.ts │ │ │ ├── postevent.controller.ts │ │ │ ├── postevent.module.ts │ │ │ ├── postevent.service.spec.ts │ │ │ └── postevent.service.ts │ │ ├── preevent │ │ │ ├── dto │ │ │ │ ├── create-preevent.dto.ts │ │ │ │ └── update-preevent.dto.ts │ │ │ ├── entities │ │ │ │ └── preevent.entity.ts │ │ │ ├── preevent.controller.spec.ts │ │ │ ├── preevent.controller.ts │ │ │ ├── preevent.module.ts │ │ │ ├── preevent.service.spec.ts │ │ │ └── preevent.service.ts │ │ ├── role │ │ │ ├── dto │ │ │ │ ├── create-role.dto.ts │ │ │ │ └── update-role.dto.ts │ │ │ ├── entities │ │ │ │ └── role.entity.ts │ │ │ ├── role.controller.ts │ │ │ ├── role.module.ts │ │ │ ├── role.service.ts │ │ │ └── seeder │ │ │ │ ├── seeder.module.ts │ │ │ │ └── user-role.seed.ts │ │ ├── sdk-keys │ │ │ ├── sdk-keys.controller.spec.ts │ │ │ ├── sdk-keys.controller.ts │ │ │ ├── sdk-keys.module.ts │ │ │ ├── sdk-keys.service.spec.ts │ │ │ └── sdk-keys.service.ts │ │ ├── secret-key │ │ │ ├── secret-key.guard.spec.ts │ │ │ └── secret-key.guard.ts │ │ └── smartcontract │ │ │ ├── dto │ │ │ ├── create-course.dto.ts │ │ │ ├── create-smartcontract.dto.ts │ │ │ ├── distrbute-token.dto.ts │ │ │ └── update-smartcontract.dto.ts │ │ │ ├── entities │ │ │ └── smartcontract.entity.ts │ │ │ ├── enums │ │ │ └── smartcontract-functions.enum.ts │ │ │ ├── smartcontract.controller.spec.ts │ │ │ ├── smartcontract.controller.ts │ │ │ ├── smartcontract.module.ts │ │ │ ├── smartcontract.service.spec.ts │ │ │ └── smartcontract.service.ts │ └── utils │ │ └── kaledio.ts ├── test │ ├── app.e2e-spec.ts │ └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json ├── learning-token-dashboard ├── .eslintrc.cjs ├── .example.env ├── .gitignore ├── Dockerfile ├── README.md ├── docker-compose.yaml ├── index.html ├── package.json ├── postcss.config.js ├── public │ └── L.png ├── src │ ├── components │ │ ├── Accordion │ │ │ └── index.tsx │ │ ├── Button │ │ │ └── index.tsx │ │ ├── Modal │ │ │ └── SuccessModal.tsx │ │ ├── Pagination │ │ │ └── index.tsx │ │ ├── SelectInput │ │ │ └── index.tsx │ │ ├── Sidebar │ │ │ ├── NewSidebar.tsx │ │ │ ├── ProtectedSidebar.tsx │ │ │ ├── SidebarMenuItems.tsx │ │ │ └── index.tsx │ │ ├── TextInput │ │ │ └── index.tsx │ │ ├── Topbar │ │ │ └── index.tsx │ │ └── nft │ │ │ └── Token.tsx │ ├── config │ │ ├── data │ │ │ └── index.ts │ │ └── menu │ │ │ └── index.ts │ ├── contexts │ │ └── EventContext.tsx │ ├── contracts │ │ └── LearningToken.json │ ├── css │ │ └── EventsAdd.css │ ├── enums │ │ ├── roles.enum.ts │ │ └── smartcontract-functions.enum.ts │ ├── hooks │ │ └── usePagination.tsx │ ├── index.css │ ├── main.tsx │ ├── pages │ │ ├── Dashboard.tsx │ │ ├── Login.tsx │ │ ├── Register.tsx │ │ ├── course │ │ │ ├── Attendance.tsx │ │ │ ├── CourseNew.tsx │ │ │ ├── SetToken.tsx │ │ │ └── index.tsx │ │ ├── events │ │ │ ├── CreateCourse.tsx │ │ │ ├── DistributeToken.tsx │ │ │ ├── Events.tsx │ │ │ ├── EventsAdd.tsx │ │ │ └── ScoringGuide.tsx │ │ ├── index.tsx │ │ ├── institution │ │ │ ├── GenerateKey.tsx │ │ │ └── index.tsx │ │ ├── instructor │ │ │ └── index.tsx │ │ ├── layouts │ │ │ ├── MasterLayout.tsx │ │ │ └── ProtectedLayout.tsx │ │ └── learner │ │ │ └── index.tsx │ ├── routes │ │ └── index.tsx │ ├── store │ │ ├── features │ │ │ ├── admin │ │ │ │ └── adminApi.ts │ │ │ ├── api │ │ │ │ └── apiSlice.ts │ │ │ ├── auth │ │ │ │ └── authSlice.ts │ │ │ ├── institution │ │ │ │ └── institutionApi.ts │ │ │ ├── instructor │ │ │ │ └── instructorApi.ts │ │ │ └── learner │ │ │ │ └── learnerApi.ts │ │ └── index.tsx │ ├── utils │ │ └── index.ts │ └── vite-env.d.ts ├── tailwind.config.js ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts └── yarn.lock ├── learning-token ├── .DS_Store ├── .env.example ├── .gitignore ├── README.md ├── arguments.d.ts ├── arguments.js ├── contracts │ ├── .DS_Store │ └── LearningToken.sol ├── hardhat.config.ts ├── package.json ├── scripts │ ├── DeployForTest.ts │ ├── DeployLive.ts │ ├── DeployLocalHardhat.ts │ └── DeployLocalHyperledgerBesu.ts ├── test.sh ├── test │ └── LearningToken.ts ├── tsconfig.json ├── yarn-error.log └── yarn.lock └── quorum-test-network ├── .common.sh ├── .env ├── README.md ├── attach.sh ├── chainlens ├── 5xx.html └── nginx.conf ├── config ├── besu │ ├── .env │ ├── CLIQUEgenesis.json │ ├── IBFTgenesis.json │ ├── QBFTgenesis.json │ ├── config.toml │ ├── genesis.json │ ├── log-config-splunk.xml │ ├── log-config.xml │ ├── permissions_config.toml │ └── static-nodes.json ├── ethsigner │ ├── createKey.js │ ├── key │ └── password ├── grafana │ └── provisioning │ │ ├── dashboards │ │ ├── besu.json │ │ ├── dashboard.yml │ │ ├── loki.json │ │ └── quorum.json │ │ └── datasources │ │ ├── loki.yml │ │ └── prometheus.yml ├── kibana │ └── besu_overview_dashboard.ndjson ├── nodes │ ├── member1 │ │ ├── accountKeystore │ │ ├── accountPassword │ │ ├── accountPrivateKey │ │ ├── address │ │ ├── nodekey │ │ ├── nodekey.pub │ │ ├── tm.key │ │ ├── tm.pub │ │ ├── tma.key │ │ └── tma.pub │ ├── member2 │ │ ├── accountKeystore │ │ ├── accountPassword │ │ ├── accountPrivateKey │ │ ├── address │ │ ├── nodekey │ │ ├── nodekey.pub │ │ ├── tm.key │ │ ├── tm.pub │ │ ├── tma.key │ │ └── tma.pub │ ├── member3 │ │ ├── accountKeystore │ │ ├── accountPassword │ │ ├── accountPrivateKey │ │ ├── address │ │ ├── nodekey │ │ ├── nodekey.pub │ │ ├── tm.key │ │ ├── tm.pub │ │ ├── tma.key │ │ └── tma.pub │ ├── rpcnode │ │ ├── accountKeystore │ │ ├── accountPassword │ │ ├── accountPrivateKey │ │ ├── address │ │ ├── nodekey │ │ └── nodekey.pub │ ├── validator1 │ │ ├── accountKeystore │ │ ├── accountPassword │ │ ├── accountPrivateKey │ │ ├── address │ │ ├── nodekey │ │ └── nodekey.pub │ ├── validator2 │ │ ├── accountKeystore │ │ ├── accountPassword │ │ ├── accountPrivateKey │ │ ├── address │ │ ├── nodekey │ │ └── nodekey.pub │ ├── validator3 │ │ ├── accountKeystore │ │ ├── accountPassword │ │ ├── accountPrivateKey │ │ ├── address │ │ ├── nodekey │ │ └── nodekey.pub │ └── validator4 │ │ ├── accountKeystore │ │ ├── accountPassword │ │ ├── accountPrivateKey │ │ ├── address │ │ ├── nodekey │ │ └── nodekey.pub ├── prometheus │ └── prometheus.yml └── tessera │ ├── Dockerfile │ ├── data │ ├── logback.xml │ └── tessera-config-template.json │ └── docker-entrypoint.sh ├── dapps └── quorumToken │ ├── README.md │ ├── contracts │ └── QuorumToken.sol │ ├── frontend │ ├── .eslintrc.json │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.svg │ │ └── next.svg │ ├── src │ │ ├── components │ │ │ ├── Layout.tsx │ │ │ ├── MMAccount.tsx │ │ │ └── quorumToken │ │ │ │ ├── QuorumTokenABI.tsx │ │ │ │ ├── ReadQuorumToken.tsx │ │ │ │ └── TransferQuorumToken.tsx │ │ └── pages │ │ │ ├── _app.tsx │ │ │ ├── _document.js │ │ │ └── index.tsx │ ├── styles │ │ └── globals.css │ └── tsconfig.json │ ├── hardhat.config.ts │ ├── package-lock.json │ ├── package.json │ ├── scripts │ └── deploy_quorumtoken.ts │ ├── test │ └── QuorumToken.test.ts │ └── tsconfig.json ├── docker-compose.yml ├── extra ├── generate_node_details.js └── package.json ├── filebeat ├── Dockerfile └── filebeat.yml ├── list.sh ├── logstash ├── Dockerfile ├── config │ ├── log4j2.properties │ └── logstash.yml └── pipeline │ ├── 10_filebeat_redis.conf │ ├── 10_metricbeat_redis.conf │ ├── 20_besu.conf │ ├── 20_logstash.conf │ ├── 20_quorum.conf │ ├── 20_tessera.conf │ └── 30_elasticsearch.conf ├── loki └── loki.yml ├── metricbeat ├── Dockerfile └── metricbeat.yml ├── promtail └── promtail.yml ├── quorum-explorer ├── config.json └── env ├── remove.sh ├── restart.sh ├── resume.sh ├── run.sh ├── smart_contracts ├── contracts │ ├── Counter.json │ ├── Counter.sol │ ├── SimpleStorage.json │ └── SimpleStorage.sol ├── package.json └── scripts │ ├── compile.js │ ├── keys.js │ ├── privacy │ ├── concurrent_private_txs.js │ ├── private_tx.js │ └── private_tx_privacy_group.js │ └── public │ ├── hre_1559_public_tx.js │ ├── hre_eth_tx.js │ ├── hre_public_tx.js │ └── web3_eth_tx.js ├── splunk ├── log4j2.xml ├── otel-collector-config.yml └── splunk.yml ├── static ├── blockchain-network.png ├── metamask-faucet-transfer.png ├── npm-send-private-tx.png └── qs-dapp.png └── stop.sh /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | Labs/.DS_Store 4 | src/.DS_Store 5 | *.cjs 6 | *.mjs 7 | /src/learning-token-backend/.yarn 8 | -------------------------------------------------------------------------------- /Labs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/.DS_Store -------------------------------------------------------------------------------- /Labs/UCA/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/.DS_Store -------------------------------------------------------------------------------- /Labs/UCA/Definitions/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Definitions/.DS_Store -------------------------------------------------------------------------------- /Labs/UCA/Definitions/LearningToken1/latest/LearningToken1.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Definitions/LearningToken1/latest/LearningToken1.md -------------------------------------------------------------------------------- /Labs/UCA/Definitions/LearningToken1/latest/LearningToken1.proto: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Definitions/LearningToken1/latest/LearningToken1.proto -------------------------------------------------------------------------------- /Labs/UCA/Definitions/LearningToken2/latest/LearningToken2.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Definitions/LearningToken2/latest/LearningToken2.md -------------------------------------------------------------------------------- /Labs/UCA/Definitions/LearningToken2/latest/LearningToken2.proto: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Definitions/LearningToken2/latest/LearningToken2.proto -------------------------------------------------------------------------------- /Labs/UCA/Formulas/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Formulas/.DS_Store -------------------------------------------------------------------------------- /Labs/UCA/Formulas/tF{~d,m,a,r,b,t,q}+phDR+phGL/latest/tF{~d,m,a,r,b,t,q}+phDR+phGL.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Formulas/tF{~d,m,a,r,b,t,q}+phDR+phGL/latest/tF{~d,m,a,r,b,t,q}+phDR+phGL.md -------------------------------------------------------------------------------- /Labs/UCA/Formulas/tF{~d,m,a,r,b,t,q}+phDR+phGL/latest/tF{~d,m,a,r,b,t,q}+phDR+phGL.proto: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Formulas/tF{~d,m,a,r,b,t,q}+phDR+phGL/latest/tF{~d,m,a,r,b,t,q}+phDR+phGL.proto -------------------------------------------------------------------------------- /Labs/UCA/Formulas/tN{~d,~t,m,a,r}+phDR+phGL/latest/tN{~d,~t,m,a,r}+phDR+phGL.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Formulas/tN{~d,~t,m,a,r}+phDR+phGL/latest/tN{~d,~t,m,a,r}+phDR+phGL.md -------------------------------------------------------------------------------- /Labs/UCA/Formulas/tN{~d,~t,m,a,r}+phDR+phGL/latest/tN{~d,~t,m,a,r}+phDR+phGL.proto: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Formulas/tN{~d,~t,m,a,r}+phDR+phGL/latest/tN{~d,~t,m,a,r}+phDR+phGL.proto -------------------------------------------------------------------------------- /Labs/UCA/Specifications/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Specifications/.DS_Store -------------------------------------------------------------------------------- /Labs/UCA/Specifications/LearningToken1/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Specifications/LearningToken1/.DS_Store -------------------------------------------------------------------------------- /Labs/UCA/Specifications/LearningToken1/latest/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Specifications/LearningToken1/latest/.DS_Store -------------------------------------------------------------------------------- /Labs/UCA/Specifications/LearningToken1/latest/LearningToken1-spec.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Specifications/LearningToken1/latest/LearningToken1-spec.docx -------------------------------------------------------------------------------- /Labs/UCA/Specifications/LearningToken1/latest/LearningToken1-spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Specifications/LearningToken1/latest/LearningToken1-spec.pdf -------------------------------------------------------------------------------- /Labs/UCA/Specifications/LearningToken2/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Specifications/LearningToken2/.DS_Store -------------------------------------------------------------------------------- /Labs/UCA/Specifications/LearningToken2/latest/LearningToken2-spec.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Specifications/LearningToken2/latest/LearningToken2-spec.docx -------------------------------------------------------------------------------- /Labs/UCA/Specifications/LearningToken2/latest/LearningToken2-spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/Labs/UCA/Specifications/LearningToken2/latest/LearningToken2-spec.pdf -------------------------------------------------------------------------------- /Practices/community-reward-token/artifacts/indivisible/indivisible.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package indivisible; 4 | 5 | import "tokens.proto"; 6 | import "google/protobuf/any.proto"; 7 | 8 | option csharp_namespace = "IWA.TTF.Behaviors.Indivisible"; 9 | option java_package = "org.iwa.ttf.behaviors.indivisible"; 10 | option java_multiple_files = true; -------------------------------------------------------------------------------- /Practices/community-reward-token/artifacts/roles/roles.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package roles; 4 | 5 | import "tokens.proto"; 6 | import "google/protobuf/any.proto"; 7 | import "google/protobuf/timestamp.proto"; 8 | option csharp_namespace = "IWA.TTF.Behaviors.Roles"; 9 | option java_package = "org.iwa.ttf.behaviors.roles"; 10 | option java_multiple_files = true; 11 | 12 | //Specifies what roles to create when creating the token class. 13 | message Constructor{ 14 | repeated Role roles = 1; 15 | } 16 | 17 | message Role{ 18 | string name = 1; 19 | repeated string behavior_symbols_for_role = 2; //these are the symbols that the role should apply this role check to. 20 | } -------------------------------------------------------------------------------- /Practices/community-reward-token/artifacts/supply-control/supply-control.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package supplycontrol; 4 | 5 | import "tokens.proto"; 6 | import "google/protobuf/any.proto"; 7 | 8 | option csharp_namespace = "IWA.TTF.BehaviorGroups.SupplyControl"; 9 | option java_package = "org.iwa.ttf.behaviorGroups.supplyControl"; 10 | option java_multiple_files = true; -------------------------------------------------------------------------------- /Practices/community-reward-token/artifacts/transferable/transferable.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package transferable; 4 | 5 | import "tokens.proto"; 6 | import "google/protobuf/any.proto"; 7 | import "google/protobuf/timestamp.proto"; 8 | option csharp_namespace = "IWA.TTF.Behaviors.Transferable"; 9 | option java_package = "org.iwa.ttf.behaviors.transferable"; 10 | option java_multiple_files = true; 11 | 12 | message Constructor{ 13 | bool delegable = 1; 14 | } 15 | 16 | message TransferRequest { 17 | tokens.MessageHeader header = 1; 18 | string token_id = 2; 19 | string to_account_id = 3; 20 | bytes quantity = 4; 21 | } 22 | 23 | message TransferResponse { 24 | tokens.MessageHeader header = 1; 25 | tokens.TransactionConfirmation confirmation = 2; 26 | } 27 | 28 | //if Delegable present 29 | message TransferFromRequest { 30 | tokens.MessageHeader header = 1; 31 | string token_id = 2; 32 | string from_account_id = 3; 33 | string to_account_id = 4; 34 | bytes quantity = 5; 35 | } 36 | 37 | //if Delegable present 38 | message TransferFromResponse { 39 | tokens.MessageHeader header = 1; 40 | tokens.TransactionConfirmation confirmation = 2; 41 | } -------------------------------------------------------------------------------- /Practices/community-reward-token/artifacts/whole_fungible/whole-fungible.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package wholeFungible; 4 | 5 | import "tokens.proto"; 6 | import "google/protobuf/any.proto"; 7 | 8 | option csharp_namespace = "IWA.TTF.Base"; 9 | option java_package = "org.iwa.ttf.base"; 10 | option java_multiple_files = true; -------------------------------------------------------------------------------- /npm_package ltsdk/.gitignore: -------------------------------------------------------------------------------- 1 | ./node_modules 2 | node_modules/ 3 | ./package-lock.json/ 4 | package-lock.json/ -------------------------------------------------------------------------------- /npm_package ltsdk/README.md: -------------------------------------------------------------------------------- 1 | # [ltsdk](https://www.npmjs.com/package/ltsdk) 2 | 3 | This package provides functions to interact with the Zoom API, fetch participant and poll data, process this data, and return the processed results. 4 | 5 | ## Installation 6 | 7 | To install the package, use the following command: 8 | 9 | ```sh 10 | npm install ltsdk 11 | ``` 12 | 13 | ## Usage 14 | Here is an example of how to use the run function from the ltsdk package: 15 | 16 | ```typescript 17 | import { run } from 'ltsdk'; 18 | import * as fs from 'fs'; 19 | import * as path from 'path'; 20 | 21 | (async () => { 22 | const accountId = "YOUR_ACCOUNT_ID"; 23 | const clientId = "YOUR_CLIENT_ID"; 24 | const clientSecret = "YOUR_CLIENT_SECRET"; 25 | const meetingId = "YOUR_MEETING_ID"; 26 | try { 27 | const processedData = await run(accountId, clientId, clientSecret, meetingId); 28 | console.log(processedData); 29 | } catch (error) { 30 | console.error('Error:', error); 31 | } 32 | })(); 33 | ``` 34 | 35 | Run the script: 36 | 37 | ```bash 38 | tsc .\index.ts 39 | node .\index.js 40 | ``` 41 | 42 | ## Parameters 43 | accountId (string): The Zoom account ID. 44 | clientId (string): The Zoom client ID. 45 | clientSecret (string): The Zoom client secret. 46 | meetingId (string): The ID of the Zoom meeting. 47 | 48 | ## Returns 49 | A promise that resolves to the processed data. 50 | 51 | ## License 52 | Linux Foundation -------------------------------------------------------------------------------- /npm_package ltsdk/dist/src/index.d.ts: -------------------------------------------------------------------------------- 1 | export { run } from './zoomprocessor'; 2 | -------------------------------------------------------------------------------- /npm_package ltsdk/dist/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // index.ts 3 | Object.defineProperty(exports, "__esModule", { value: true }); 4 | exports.run = void 0; 5 | var zoomprocessor_1 = require("./zoomprocessor"); 6 | Object.defineProperty(exports, "run", { enumerable: true, get: function () { return zoomprocessor_1.run; } }); 7 | -------------------------------------------------------------------------------- /npm_package ltsdk/dist/src/zoomprocessor.d.ts: -------------------------------------------------------------------------------- 1 | export declare function run(accountId: string, clientId: string, clientSecret: string, meetingId: string): Promise; 2 | -------------------------------------------------------------------------------- /npm_package ltsdk/dist/tests/zoomprocessor.test.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /npm_package ltsdk/dist/tests/zoomprocessor.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | const zoomprocessor_1 = require("../src/zoomprocessor"); 13 | test('fetch and process Zoom data', () => __awaiter(void 0, void 0, void 0, function* () { 14 | const accountId = "YOUR_ACCOUNT_ID"; 15 | const clientId = "YOUR_CLIENT_ID"; 16 | const clientSecret = "YOUR_CLIENT_SECRET"; 17 | const meetingId = 'YOUR_MEETING_ID'; 18 | const processedData = yield (0, zoomprocessor_1.run)(accountId, clientId, clientSecret, meetingId); 19 | expect(processedData).toMatchSnapshot(); 20 | })); 21 | -------------------------------------------------------------------------------- /npm_package ltsdk/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | testMatch: ['**/tests/**/*.test.ts'], 5 | }; -------------------------------------------------------------------------------- /npm_package ltsdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ltsdk", 3 | "version": "1.0.5", 4 | "description": "Learning Tokens SDK", 5 | "main": "dist/src/index.js", 6 | "types": "types/index.d.ts", 7 | "scripts": { 8 | "build": "tsc", 9 | "test": "jest" 10 | }, 11 | "keywords": [], 12 | "author": "Harsh Jain", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "@types/jest": "^29.5.14", 16 | "@types/node": "^22.9.0", 17 | "jest": "^29.7.0", 18 | "ts-jest": "^29.2.5", 19 | "typescript": "^5.6.3" 20 | }, 21 | "dependencies": { 22 | "axios": "^1.7.7" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /npm_package ltsdk/src/index.ts: -------------------------------------------------------------------------------- 1 | // index.ts 2 | 3 | export { run } from './zoomprocessor'; -------------------------------------------------------------------------------- /npm_package ltsdk/tests/zoomprocessor.test.ts: -------------------------------------------------------------------------------- 1 | import { run } from '../src/zoomprocessor'; 2 | 3 | test('fetch and process Zoom data', async () => { 4 | const accountId = "YOUR_ACCOUNT_ID"; 5 | const clientId = "YOUR_CLIENT_ID"; 6 | const clientSecret = "YOUR_CLIENT_SECRET"; 7 | const meetingId = 'YOUR_MEETING_ID'; 8 | 9 | const processedData = await run(accountId, clientId, clientSecret, meetingId); 10 | expect(processedData).toMatchSnapshot(); 11 | }); -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/.DS_Store -------------------------------------------------------------------------------- /src/learning-token-backend/.env.example: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | 3 | APP_URL=http://localhost:3000/api 4 | APP_PORT=3000 5 | APP_SECRET=3QANyH2zMoHrfxqfRWTLbPM 6 | APP_EXPIRES=3600 7 | 8 | POSTGRES_HOST=localhost 9 | POSTGRES_PORT=5432 10 | 11 | DB_TYPE=postgres 12 | DB_USERNAME=postgres 13 | DB_PASSWORD=password 14 | DB_NAME=learning-token 15 | 16 | REDIS_HOST=127.0.0.1 17 | REDIS_PORT=6379 18 | REDIS_TTL=600 19 | ADMIN_PRIVATE_KEY= 0602541929cebf44af78d448cd1855f3ed6c3232e7e5b5a56002af1d092be8c1 20 | ADMIN_PUBLIC_KEY= 0xC9ed1AF4ABd6Ea37D0e6920A44901bEAE0d297E1 21 | KALEIDO_HD_WALLET_RPC_URL=https://u0zv22iwne:edIzBiLbP73Y9tj4a0Ar7wLDgwTi2DNLGaE8vMRCCtg@u0jtyl6s8p-u0gt6e2xu2-hdwallet.us0-aws.kaleido.io 22 | 23 | CONTRACT_ADDRESS=0x44aE8F9Ee70c0a5D5CFfbB3A4049A128DE2EF3B3 24 | 25 | JSON_RPC_URL=https://u0k1dk029t:NUZ9OPvJg8T9qBef_bZQgw5pV5HoFJuhYRMHYWSJd_A@u0jtyl6s8p-u0trhblsbk-rpc.us0-aws.kaleido.io 26 | 27 | USERPASS =#Skiller1371 28 | FROMEMAIL =tanjin.alam@zohomail.com 29 | 30 | ADMIN_HD_WALLET_ID=kuitpud2 31 | INSTITUTION_HD_WALLET_ID=4jde4ddy 32 | INSTRUCTOR_HD_WALLET_ID=oz438t3o 33 | LEARNER_HD_WALLET_ID=ovjhrfvp 34 | -------------------------------------------------------------------------------- /src/learning-token-backend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | tsconfigRootDir: __dirname, 6 | sourceType: 'module' 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin'], 9 | extends: [ 10 | 'plugin:@typescript-eslint/recommended', 11 | 'plugin:prettier/recommended' 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true 17 | }, 18 | ignorePatterns: ['.eslintrc.js'], 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | 'prettier/prettier': ['error', { endOfLine: 'auto' }] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/learning-token-backend/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | pnpm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # OS 15 | .DS_Store 16 | 17 | # Tests 18 | /coverage 19 | /.nyc_output 20 | 21 | # IDEs and editors 22 | /.idea 23 | .project 24 | .classpath 25 | .c9/ 26 | *.launch 27 | .settings/ 28 | *.sublime-workspace 29 | 30 | # IDE - VSCode 31 | .vscode/* 32 | !.vscode/settings.json 33 | !.vscode/tasks.json 34 | !.vscode/launch.json 35 | !.vscode/extensions.json 36 | 37 | # ENV 38 | .env 39 | 40 | # Compiled package-lock.json 41 | package-lock.json 42 | yarn.lock -------------------------------------------------------------------------------- /src/learning-token-backend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "none", 3 | "tabWidth": 4, 4 | "semi": false, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /src/learning-token-backend/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[javascript]": { 3 | "editor.defaultFormatter": "esbenp.prettier-vscode" 4 | }, 5 | "[typescript]": { 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | }, 8 | "[scss]": { 9 | "editor.defaultFormatter": "esbenp.prettier-vscode" 10 | }, 11 | "[json]": { 12 | "editor.defaultFormatter": "esbenp.prettier-vscode" 13 | }, 14 | "[jsonc]": { 15 | "editor.defaultFormatter": "esbenp.prettier-vscode" 16 | }, 17 | "editor.formatOnSave": true, 18 | "eslint.alwaysShowStatus": true, 19 | "editor.codeActionsOnSave": { 20 | "source.fixAll.eslint": "explicit", 21 | "source.fixAll.tslint": "explicit", 22 | "source.organizeImports": "explicit" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/learning-token-backend/Dockerfile: -------------------------------------------------------------------------------- 1 | # Image source 2 | FROM node:alpine 3 | 4 | # Docker working directory 5 | WORKDIR /app 6 | 7 | # Copying file into APP directory of docker 8 | COPY ./package.json /app/ 9 | 10 | # Then install the NPM module 11 | RUN npm install 12 | 13 | # Copy current directory to APP folder 14 | COPY . /app/ 15 | 16 | # Then build 17 | RUN npm run build 18 | 19 | EXPOSE 3000 20 | # CMD ["npm", "run", "start:prod"] 21 | CMD ["npm", "run", "start:dev"] 22 | -------------------------------------------------------------------------------- /src/learning-token-backend/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 anchorblock 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/learning-token-backend/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | learning-token-backend: 4 | image: learning-token-backend 5 | ports: 6 | - '3000:3000' 7 | container_name: learning-token-backend 8 | environment: 9 | - APP_URL=http://localhost:3000/api 10 | - APP_PORT=3000 11 | - APP_SECRET=3QANyH2zMoHrfxqfRWTLbPM 12 | - APP_EXPIRES=3600 13 | - POSTGRES_HOST=postgres 14 | - POSTGRES_PORT=5432 15 | - DB_TYPE=postgres 16 | - DB_USERNAME=postgres 17 | - DB_PASSWORD=password 18 | - DB_NAME=learning-token 19 | - REDIS_HOST=redis 20 | - REDIS_PORT=6379 21 | - REDIS_TTL=600 22 | build: 23 | context: . 24 | dockerfile: ./Dockerfile 25 | volumes: 26 | - .:/app # Mount the current directory to /app in the container 27 | - /app/node_modules # Keep node_modules separate 28 | 29 | postgres: 30 | image: postgres:latest 31 | container_name: postgres 32 | environment: 33 | - POSTGRES_USER=postgres 34 | - POSTGRES_PASSWORD=password 35 | - POSTGRES_DB=learning-token 36 | ports: 37 | - '5432:5432' 38 | 39 | redis: 40 | image: redis:latest 41 | container_name: redis 42 | ports: 43 | - '6379:6379' 44 | -------------------------------------------------------------------------------- /src/learning-token-backend/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src" 5 | } 6 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, HttpStatus } from '@nestjs/common' 2 | import { response } from 'src/common/helpers/utils.helper' 3 | import { AppService } from './app.service' 4 | 5 | @Controller() 6 | export class AppController { 7 | constructor(private readonly appService: AppService) {} 8 | 9 | @Get() 10 | getHello() { 11 | return response(HttpStatus.OK, 'Congratulations, You are hooked!!!', []) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { ConfigModule } from '@nestjs/config' 3 | import { TypeOrmModule } from '@nestjs/typeorm' 4 | import { typeOrmAsyncConfig } from 'src/config/typeorm.config' 5 | import { UsersModule } from 'src/modules/admins/users.module' 6 | import { AppController } from './app.controller' 7 | import { AppService } from './app.service' 8 | import { AuthModule } from './modules/auth/auth.module' 9 | import { InstitutionsModule } from './modules/institutions/institutions.module' 10 | import { InstructorsModule } from './modules/instructors/instructors.module' 11 | import { LearnersModule } from './modules/learners/learners.module' 12 | import { RoleModule } from './modules/role/role.module' 13 | import { SdkKeysModule } from './modules/sdk-keys/sdk-keys.module' 14 | import { PreeventModule } from './modules/preevent/preevent.module' 15 | import { PosteventModule } from './modules/postevent/postevent.module' 16 | import { SmartcontractModule } from './modules/smartcontract/smartcontract.module' 17 | import { EventModule } from './modules/event/event.module' 18 | import { SeederModule } from './modules/role/seeder/seeder.module' 19 | @Module({ 20 | imports: [ 21 | ConfigModule.forRoot({ 22 | envFilePath: ['.env'], 23 | isGlobal: true, 24 | cache: true 25 | }), 26 | TypeOrmModule.forRootAsync(typeOrmAsyncConfig), 27 | AuthModule, 28 | UsersModule, 29 | RoleModule, 30 | LearnersModule, 31 | InstructorsModule, 32 | InstitutionsModule, 33 | SdkKeysModule, 34 | PreeventModule, 35 | PosteventModule, 36 | SmartcontractModule, 37 | EventModule, 38 | SeederModule 39 | ], 40 | controllers: [AppController], 41 | providers: [AppService], 42 | exports: [TypeOrmModule] 43 | }) 44 | export class AppModule {} 45 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common' 2 | 3 | @Injectable() 4 | export class AppService {} 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/cache/cache.keys.ts: -------------------------------------------------------------------------------- 1 | export const CacheKeys = { 2 | INVALIDATE_ACCESS_TOKEN: { 3 | KEY: 'invalidate_access_tokens', 4 | TTL: null 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/common/decorators/roles.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common' 2 | import { RoleEnum } from 'src/modules/admins/enums/user.enum' 3 | 4 | export const ALLOWED_USER_TYPES = 'allowedUserTypes' 5 | export const AllowUserTypes = (...allowedUserTypes: RoleEnum[]) => 6 | SetMetadata(ALLOWED_USER_TYPES, allowedUserTypes) 7 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/common/filters/models/http-exception-response.interface.ts: -------------------------------------------------------------------------------- 1 | export interface HttpExceptionResponse { 2 | statusCode: number 3 | error: string 4 | } 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/common/guards/access-control.guard.ts: -------------------------------------------------------------------------------- 1 | import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common' 2 | import { Reflector } from '@nestjs/core' 3 | import { AllowUserTypes } from 'src/common/decorators/roles.decorator' 4 | import { RoleEnum } from 'src/modules/admins/enums/user.enum' 5 | 6 | @Injectable() 7 | export class AccessControlGuard implements CanActivate { 8 | constructor(private reflector: Reflector) {} 9 | 10 | canActivate(context: ExecutionContext): boolean { 11 | const allowedUserTypes = this.reflector.get( 12 | 'allowedUserTypes', 13 | context.getHandler() 14 | ) 15 | const request = context.switchToHttp().getRequest() 16 | 17 | console.log('request', request.user) 18 | if (request.user?.role) { 19 | // if (request.user.role.isAdmin) { 20 | // return requiredRoles.indexOf(RoleEnum.ADMIN) > -1 ? true : false 21 | // } 22 | 23 | return allowedUserTypes.indexOf(request.user['role'].name) > -1 24 | ? true 25 | : false 26 | } 27 | 28 | return false 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/common/guards/jwt-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common' 2 | import { AuthGuard } from '@nestjs/passport' 3 | 4 | @Injectable() 5 | export class JwtAuthGuard extends AuthGuard('jwt') {} 6 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/common/guards/sdk.guard.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CanActivate, 3 | ExecutionContext, 4 | Injectable, 5 | UnauthorizedException 6 | } from '@nestjs/common' 7 | import { SdkKeysService } from '../../modules/sdk-keys/sdk-keys.service' 8 | 9 | @Injectable() 10 | export class SDKGuard implements CanActivate { 11 | constructor(private readonly sdkKeysService: SdkKeysService) {} 12 | 13 | async canActivate(context: ExecutionContext): Promise { 14 | const request = context.switchToHttp().getRequest() 15 | const sdkKey = request.headers['sdk-key'] 16 | 17 | if (!sdkKey) { 18 | throw new UnauthorizedException('SDK key is missing') 19 | } 20 | 21 | const isValid = await this.sdkKeysService.validateSdkKeyForInstitution( 22 | sdkKey 23 | ) 24 | if (!isValid) { 25 | throw new UnauthorizedException('Invalid SDK key') 26 | } 27 | 28 | return true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/common/pipes/response.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CallHandler, 3 | ExecutionContext, 4 | Injectable, 5 | NestInterceptor 6 | } from '@nestjs/common' 7 | import { Observable } from 'rxjs' 8 | import { map } from 'rxjs/operators' 9 | 10 | export interface Response { 11 | message: string 12 | data: T 13 | } 14 | 15 | @Injectable() 16 | export class TransformInterceptor 17 | implements NestInterceptor> 18 | { 19 | intercept( 20 | context: ExecutionContext, 21 | next: CallHandler 22 | ): Observable> { 23 | return next.handle().pipe( 24 | map((data) => ({ 25 | statusCode: data.statusCode, 26 | message: data.message, 27 | data: { 28 | result: data.result 29 | } 30 | })) 31 | ) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/common/pipes/validation.pipe.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ArgumentMetadata, 3 | BadRequestException, 4 | Injectable, 5 | PipeTransform 6 | } from '@nestjs/common' 7 | import { plainToClass } from 'class-transformer' 8 | import { validate } from 'class-validator' 9 | import e from 'express' 10 | 11 | @Injectable() 12 | export class ValidationPipe implements PipeTransform { 13 | async transform(value: any, { metatype }: ArgumentMetadata) { 14 | if (!metatype || !this.toValidate(metatype)) { 15 | return value 16 | } 17 | const object = plainToClass(metatype, value) 18 | const errors = await validate(object) 19 | if (errors.length > 0) { 20 | throw new BadRequestException({ 21 | statusCode: 400, 22 | message: 'Validation Error', 23 | missingProperty: `${errors[0].property} is missing or it should be ${errors[0].constraints}` 24 | }) 25 | } 26 | return value 27 | } 28 | 29 | private toValidate(metatype: any): boolean { 30 | const types: any[] = [String, Boolean, Number, Array, Object] 31 | return !types.includes(metatype) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/config/env.validation.ts: -------------------------------------------------------------------------------- 1 | import { plainToClass } from 'class-transformer' 2 | import { IsEnum, IsNumber, IsString, validateSync } from 'class-validator' 3 | 4 | enum Environment { 5 | Development = 'development', 6 | Production = 'production', 7 | Test = 'test', 8 | Provision = 'provision' 9 | } 10 | 11 | class EnvironmentVariables { 12 | @IsEnum(Environment) 13 | NODE_ENV: Environment 14 | 15 | @IsNumber() 16 | APP_PORT: number 17 | 18 | @IsString() 19 | APP_SECRET: string 20 | 21 | @IsNumber() 22 | APP_EXPIRES: number 23 | 24 | @IsString() 25 | POSTGRES_HOST: string 26 | 27 | @IsNumber() 28 | POSTGRES_PORT: number 29 | 30 | @IsString() 31 | DB_USERNAME: string 32 | 33 | @IsString() 34 | DB_PASSWORD: string 35 | 36 | @IsString() 37 | DB_NAME: string 38 | 39 | @IsString() 40 | AWS_S3_BUCKET_NAME: string 41 | 42 | @IsString() 43 | AWS_ACCESS_KEY_ID: string 44 | 45 | @IsString() 46 | AWS_SECRET_ACCESS_KEY: string 47 | 48 | @IsString() 49 | REDIS_HOST: string 50 | 51 | @IsNumber() 52 | REDIS_PORT: number 53 | 54 | @IsNumber() 55 | REDIS_TTL: number 56 | } 57 | 58 | export function validate(config: Record) { 59 | const validatedConfig = plainToClass(EnvironmentVariables, config, { 60 | enableImplicitConversion: true 61 | }) 62 | const errors = validateSync(validatedConfig, { 63 | skipMissingProperties: false 64 | }) 65 | 66 | if (errors.length > 0) { 67 | throw new Error(errors.toString()) 68 | } 69 | return validatedConfig 70 | } 71 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/config/jwt.config.ts: -------------------------------------------------------------------------------- 1 | import { ConfigService } from '@nestjs/config' 2 | import { JwtModuleAsyncOptions } from '@nestjs/jwt' 3 | 4 | export const jwtConfig: JwtModuleAsyncOptions = { 5 | useFactory: async (configService: ConfigService) => { 6 | const obj = { 7 | secret: configService.get('APP_SECRET'), 8 | signOptions: { 9 | expiresIn: Number(configService.get('APP_EXPIRES')) 10 | } 11 | } 12 | return obj 13 | }, 14 | inject: [ConfigService] 15 | } 16 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/config/smtp.config.ts: -------------------------------------------------------------------------------- 1 | import { ConfigModule, ConfigService } from '@nestjs/config' 2 | 3 | const smtpConfig = { 4 | imports: [ConfigModule], 5 | inject: [ConfigService], 6 | useFactory: async (configService: ConfigService): Promise => { 7 | return { 8 | transport: { 9 | host: configService.get('SMTP_HOST'), 10 | auth: { 11 | user: configService.get('SMTP_USER'), 12 | pass: configService.get('SMTP_PASSWORD') 13 | } 14 | } 15 | } 16 | } 17 | } 18 | 19 | export default smtpConfig 20 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/config/typeorm.config-migrations.ts: -------------------------------------------------------------------------------- 1 | const typeOrmConfig = { 2 | type: 'postgres', 3 | host: process.env.POSTGRES_HOST, 4 | port: +process.env.POSTGRES_PORT, 5 | username: process.env.DB_USERNAME, 6 | password: process.env.DB_PASSWORD, 7 | database: process.env.DB_NAME, 8 | entities: ['dist/**/*.entity.js'], 9 | migrations: [__dirname + '/../database/migrations/*{.ts,.js}'], 10 | cli: { 11 | migrationsDir: __dirname + '/../database/migrations' 12 | }, 13 | extra: { 14 | charset: 'utf8mb4_unicode_ci' 15 | }, 16 | synchronize: false, 17 | logging: true, 18 | factories: ['dist/**/database/factories/**/*.js'], 19 | seeds: ['dist/**/database/seeds/**/*.js'] 20 | } 21 | 22 | export default typeOrmConfig 23 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/config/typeorm.config.ts: -------------------------------------------------------------------------------- 1 | import { ConfigModule, ConfigService } from '@nestjs/config' 2 | import { 3 | TypeOrmModuleAsyncOptions, 4 | TypeOrmModuleOptions 5 | } from '@nestjs/typeorm' 6 | 7 | export const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = { 8 | imports: [ConfigModule], 9 | inject: [ConfigService], 10 | useFactory: async ( 11 | configService: ConfigService 12 | ): Promise => { 13 | return { 14 | type: 'postgres', 15 | host: configService.get('POSTGRES_HOST', 'localhost'), 16 | port: configService.get('POSTGRES_PORT', 5432), 17 | username: configService.get('DB_USERNAME', 'postgres'), 18 | password: configService.get('DB_PASSWORD', 'password'), 19 | database: configService.get('DB_NAME', 'nestjs-starter-kit'), 20 | entities: [__dirname + '/../**/*.entity.{js,ts}'], 21 | migrations: [__dirname + '/../database/migrations/*{.ts,.js}'], 22 | 23 | extra: { 24 | charset: 'utf8mb4_unicode_ci' 25 | }, 26 | synchronize: true 27 | // logging: true 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HttpStatus, 3 | UnprocessableEntityException, 4 | ValidationPipe 5 | } from '@nestjs/common' 6 | import { ConfigService } from '@nestjs/config' 7 | import { NestFactory } from '@nestjs/core' 8 | import { ValidationPipe as VP } from 'src/common/pipes/validation.pipe' 9 | import { AppModule } from './app.module' 10 | async function bootstrap() { 11 | const app = await NestFactory.create(AppModule) 12 | const configService = app.get(ConfigService) 13 | app.setGlobalPrefix('api') 14 | app.useGlobalPipes(new VP()) 15 | app.useGlobalPipes( 16 | new ValidationPipe({ 17 | whitelist: true, 18 | errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY, 19 | transform: true, 20 | dismissDefaultMessages: true, 21 | exceptionFactory: (errors) => 22 | new UnprocessableEntityException(errors) 23 | }) 24 | ) 25 | const options = { 26 | origin: '*', 27 | methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS', 28 | preflightContinue: false, 29 | optionsSuccessStatus: 204, 30 | credentials: true 31 | } 32 | 33 | app.enableCors(options) 34 | await app.listen(configService.get('APP_PORT', 3000)) 35 | } 36 | bootstrap() 37 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/admins/dto/create-user.dto.ts: -------------------------------------------------------------------------------- 1 | import { 2 | IsEmail, 3 | IsInt, 4 | IsNotEmpty, 5 | IsOptional, 6 | IsString, 7 | IsUrl, 8 | Min 9 | } from 'class-validator' 10 | 11 | export class CreateUserDto { 12 | @IsString() 13 | @IsNotEmpty() 14 | name: string 15 | 16 | @IsNotEmpty() 17 | @IsEmail() 18 | email: string 19 | 20 | @IsString() 21 | @IsOptional() 22 | password: string 23 | 24 | @IsString() 25 | @IsUrl() 26 | avatarUrl: string 27 | } 28 | 29 | export class PaginationQueryDto { 30 | @IsOptional() 31 | @IsInt() 32 | @Min(1) 33 | page: number 34 | 35 | @IsOptional() 36 | @IsInt() 37 | @Min(1) 38 | limit: number 39 | } 40 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/admins/entities/user.entity.ts: -------------------------------------------------------------------------------- 1 | import { Exclude } from 'class-transformer' 2 | import { IsEmail, IsString } from 'class-validator' 3 | import { Role } from 'src/modules/role/entities/role.entity' 4 | import { 5 | BaseEntity, 6 | Column, 7 | CreateDateColumn, 8 | DeleteDateColumn, 9 | Entity, 10 | ManyToOne, 11 | PrimaryGeneratedColumn, 12 | UpdateDateColumn 13 | } from 'typeorm' 14 | @Entity() 15 | export class User extends BaseEntity { 16 | @PrimaryGeneratedColumn('increment') 17 | id: number 18 | 19 | @Column({ type: 'varchar', length: 30, nullable: true }) 20 | name: string 21 | 22 | @Column({ 23 | type: 'varchar', 24 | length: 50, 25 | unique: true, 26 | nullable: false 27 | }) 28 | @IsEmail() 29 | email: string 30 | 31 | @Exclude() 32 | @Column({ type: 'varchar', length: 255, nullable: false }) 33 | @IsString() 34 | password: string 35 | 36 | @Column({ type: 'varchar', length: 30, nullable: true }) 37 | avatarUrl: string 38 | 39 | @Column({ type: 'varchar', length: 50, nullable: true, unique: true }) 40 | publicAddress: string 41 | 42 | // @Column({ 43 | // type: 'int' 44 | // }) 45 | // roleId: number 46 | 47 | @ManyToOne(() => Role) 48 | role: Role 49 | 50 | @CreateDateColumn() 51 | createdAt: Date 52 | 53 | @UpdateDateColumn() 54 | updatedAt: Date 55 | 56 | @DeleteDateColumn() 57 | deletedAt: Date 58 | } 59 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/admins/enums/user.enum.ts: -------------------------------------------------------------------------------- 1 | export enum RoleEnum { 2 | ADMIN = 'admin', 3 | INSTITUTION = 'institution', 4 | INSTRUCTOR = 'instructor', 5 | LEARNER = 'learner' 6 | } 7 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/admins/users.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { TypeOrmModule } from '@nestjs/typeorm' 3 | import { AdminService } from 'src/modules/admins/users.service' 4 | import { Institution } from '../institutions/entities/institution.entity' 5 | import { Instructor } from '../instructors/entities/instructor.entity' 6 | import { Learner } from '../learners/entities/learner.entity' 7 | import { AdminController } from './users.controller' 8 | import { User } from './entities/user.entity' 9 | 10 | @Module({ 11 | imports: [ 12 | TypeOrmModule.forFeature([User, Institution, Learner, Instructor]) 13 | ], 14 | controllers: [AdminController], 15 | providers: [AdminService], 16 | exports: [AdminService] 17 | }) 18 | export class UsersModule {} 19 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/auth/auth.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { ConfigService } from '@nestjs/config' 3 | import { JwtModule } from '@nestjs/jwt' 4 | import { TypeOrmModule } from '@nestjs/typeorm' 5 | import { jwtConfig } from 'src/config/jwt.config' 6 | import { Institution } from '../institutions/entities/institution.entity' 7 | import { Instructor } from '../instructors/entities/instructor.entity' 8 | import { Learner } from '../learners/entities/learner.entity' 9 | import { AuthController } from './auth.controller' 10 | import { AuthService } from './service/auth.service' 11 | import { JwtService } from './service/jwt.service' 12 | import { JwtStrategy } from './strategy/jwt.strategy' 13 | import { User } from '../admins/entities/user.entity' 14 | import { Role } from '../role/entities/role.entity' 15 | @Module({ 16 | imports: [ 17 | JwtModule.registerAsync(jwtConfig), 18 | TypeOrmModule.forFeature([User, Institution, Learner, Instructor, Role]) 19 | ], 20 | controllers: [AuthController], 21 | providers: [AuthService, JwtService, JwtStrategy, ConfigService], 22 | exports: [AuthService, JwtService] 23 | }) 24 | export class AuthModule {} 25 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/auth/strategy/jwt.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable } from '@nestjs/common' 2 | import { PassportStrategy } from '@nestjs/passport' 3 | import { ExtractJwt, Strategy } from 'passport-jwt' 4 | import { JwtService } from '../service/jwt.service' 5 | @Injectable() 6 | export class JwtStrategy extends PassportStrategy(Strategy) { 7 | @Inject(JwtService) 8 | private readonly jwtService: JwtService 9 | 10 | constructor() { 11 | super({ 12 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 13 | secretOrKey: process.env.APP_SECRET, 14 | ignoreExpiration: true 15 | }) 16 | } 17 | 18 | private validate(token: string) { 19 | return this.jwtService.validateUser(token) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/event/dto/create-event.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsNumber, IsOptional, IsString } from 'class-validator' 2 | 3 | export class CreateScoringGuideDTO { 4 | @IsNumber() 5 | preEventId: number 6 | 7 | @IsString() 8 | meetingEventId: string 9 | 10 | @IsOptional() 11 | @IsString() 12 | fieldOfKnowledge: string 13 | 14 | @IsOptional() 15 | @IsString() 16 | taxonomyOfSkill: string 17 | 18 | @IsNumber() 19 | attendanceToken: number 20 | 21 | @IsNumber() 22 | scoreTokenAmount: number 23 | 24 | @IsNumber() 25 | helpTokenAmount: number 26 | 27 | @IsNumber() 28 | instructorScoreToken: number 29 | 30 | @IsOptional() 31 | @IsString() 32 | ipfsHash: string 33 | } 34 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/event/dto/create-scoring-guide.dto.ts: -------------------------------------------------------------------------------- 1 | export class CreateEventDto {} 2 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/event/dto/update-event.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types' 2 | import { CreateEventDto } from './create-scoring-guide.dto' 3 | 4 | export class UpdateEventDto extends PartialType(CreateEventDto) {} 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/event/entities/event.entity.ts: -------------------------------------------------------------------------------- 1 | import { Preevent } from 'src/modules/preevent/entities/preevent.entity' 2 | import { 3 | Entity, 4 | PrimaryGeneratedColumn, 5 | Column, 6 | CreateDateColumn, 7 | UpdateDateColumn, 8 | BaseEntity, 9 | OneToOne, 10 | JoinColumn, 11 | DeleteDateColumn, 12 | ManyToOne 13 | } from 'typeorm' 14 | import { ScoringGuide } from './scoring-guide.entity' 15 | import { Instructor } from 'src/modules/instructors/entities/instructor.entity' 16 | 17 | @Entity() 18 | export class OnlineEvent extends BaseEntity { 19 | @PrimaryGeneratedColumn('increment') 20 | id: number 21 | 22 | @ManyToOne(() => Instructor) 23 | instructor: Instructor 24 | 25 | @OneToOne(() => ScoringGuide) 26 | @JoinColumn() 27 | scoringGuide: ScoringGuide 28 | 29 | @Column({ type: 'boolean', default: false }) 30 | courseCreateStatus: boolean 31 | 32 | @Column({ type: 'boolean', default: false }) 33 | attendanceTokenMintStatus: boolean 34 | 35 | @Column({ type: 'boolean', default: false }) 36 | scoreTokenMintStatus: boolean 37 | 38 | @Column({ type: 'boolean', default: false }) 39 | helpTokenMintStatus: boolean 40 | 41 | @Column({ type: 'boolean', default: false }) 42 | mintInstructorScoreTokenStatus: boolean 43 | 44 | @CreateDateColumn() 45 | createdAt: Date 46 | 47 | @UpdateDateColumn() 48 | updatedAt: Date 49 | 50 | @DeleteDateColumn() 51 | deletedAt: Date 52 | 53 | constructor(partial: Partial, scoringGuide: ScoringGuide) { 54 | super() 55 | this.scoringGuide = scoringGuide 56 | Object.assign(this, partial) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/event/entities/scoring-guide.entity.ts: -------------------------------------------------------------------------------- 1 | import { Institution } from 'src/modules/institutions/entities/institution.entity' 2 | import { Postevent } from 'src/modules/postevent/entities/postevent.entity' 3 | import { 4 | BaseEntity, 5 | Entity, 6 | PrimaryGeneratedColumn, 7 | Column, 8 | CreateDateColumn, 9 | UpdateDateColumn, 10 | DeleteDateColumn 11 | } from 'typeorm' 12 | 13 | // make an enum 14 | 15 | @Entity() 16 | export class ScoringGuide extends BaseEntity { 17 | @PrimaryGeneratedColumn('increment') 18 | id: number 19 | 20 | @Column({ type: 'int', nullable: true }) 21 | courseId: number 22 | 23 | @Column({ type: 'varchar', length: 255, nullable: true }) 24 | courseName: string 25 | 26 | @Column({ type: 'varchar', length: 255, nullable: true }) 27 | fieldOfKnowledge: string 28 | 29 | @Column({ type: 'varchar', length: 255, nullable: true }) 30 | taxonomyOfSkill: string 31 | 32 | @Column({ type: 'int', nullable: true }) 33 | attendanceToken: number 34 | 35 | @Column({ type: 'int', nullable: true }) 36 | scoreTokenAmount: number 37 | 38 | @Column({ type: 'int', nullable: true }) 39 | helpTokenAmount: number 40 | 41 | @Column({ type: 'int', nullable: true }) 42 | instructorScoreToken: number 43 | 44 | @Column({ type: 'varchar', length: 255, nullable: true }) 45 | ipfsHash: string 46 | 47 | //simple json column to hold all dynamic value of the scoring guide 48 | @Column({ type: 'simple-json', nullable: true }) 49 | scoringGuide: JSON 50 | 51 | @CreateDateColumn() 52 | createdAt: Date 53 | 54 | @UpdateDateColumn() 55 | updatedAt: Date 56 | 57 | @DeleteDateColumn() 58 | deletedAt: Date 59 | } 60 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/event/event.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing' 2 | import { EventController } from './event.controller' 3 | import { EventService } from './event.service' 4 | 5 | describe('EventController', () => { 6 | let controller: EventController 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [EventController], 11 | providers: [EventService] 12 | }).compile() 13 | 14 | controller = module.get(EventController) 15 | }) 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined() 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/event/event.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Controller, 3 | Get, 4 | Post, 5 | Body, 6 | Patch, 7 | Param, 8 | Delete 9 | } from '@nestjs/common' 10 | import { EventService } from './event.service' 11 | import { UpdateEventDto } from './dto/update-event.dto' 12 | import { CreateScoringGuideDTO } from './dto/create-event.dto' 13 | import { CreateEventDto } from './dto/create-scoring-guide.dto' 14 | 15 | @Controller('event') 16 | export class EventController { 17 | constructor(private readonly eventService: EventService) {} 18 | 19 | @Post() 20 | create(@Body() createEventDto: CreateEventDto) { 21 | return this.eventService.create(createEventDto) 22 | } 23 | 24 | @Post('create-scoring-guide') 25 | createScoringGuide(@Body() createScoringGuideDTO: CreateScoringGuideDTO) { 26 | return this.eventService.createScoringGuide(createScoringGuideDTO) 27 | } 28 | 29 | @Get() 30 | findAll() { 31 | return this.eventService.findAll() 32 | } 33 | 34 | @Get(':id') 35 | findOne(@Param('id') id: string) { 36 | return this.eventService.findOne(+id) 37 | } 38 | 39 | @Patch(':id') 40 | update(@Param('id') id: string, @Body() updateEventDto: UpdateEventDto) { 41 | return this.eventService.update(+id, updateEventDto) 42 | } 43 | 44 | @Delete(':id') 45 | remove(@Param('id') id: string) { 46 | return this.eventService.remove(+id) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/event/event.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { EventService } from './event.service' 3 | import { EventController } from './event.controller' 4 | import { Type } from 'class-transformer' 5 | import { TypeOrmModule } from '@nestjs/typeorm' 6 | import { ScoringGuide } from './entities/scoring-guide.entity' 7 | import { OnlineEvent } from './entities/event.entity' 8 | import { Preevent } from '../preevent/entities/preevent.entity' 9 | 10 | @Module({ 11 | imports: [TypeOrmModule.forFeature([OnlineEvent, ScoringGuide, Preevent])], 12 | controllers: [EventController], 13 | providers: [EventService] 14 | }) 15 | export class EventModule {} 16 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/event/event.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing' 2 | import { EventService } from './event.service' 3 | 4 | describe('EventService', () => { 5 | let service: EventService 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [EventService] 10 | }).compile() 11 | 12 | service = module.get(EventService) 13 | }) 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined() 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/institutions/dto/create-institution.dto.ts: -------------------------------------------------------------------------------- 1 | export class CreateInstitutionDto {} 2 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/institutions/dto/update-institution.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateInstitutionDto } from './create-institution.dto'; 3 | 4 | export class UpdateInstitutionDto extends PartialType(CreateInstitutionDto) {} 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/institutions/institutions.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { InstitutionsController } from './institutions.controller'; 3 | import { InstitutionsService } from './institutions.service'; 4 | 5 | describe('InstitutionsController', () => { 6 | let controller: InstitutionsController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [InstitutionsController], 11 | providers: [InstitutionsService], 12 | }).compile(); 13 | 14 | controller = module.get(InstitutionsController); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/institutions/institutions.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Body, 3 | Controller, 4 | Delete, 5 | Get, 6 | Param, 7 | Patch, 8 | Post, 9 | UseGuards 10 | } from '@nestjs/common' 11 | import { CreateInstitutionDto } from './dto/create-institution.dto' 12 | import { UpdateInstitutionDto } from './dto/update-institution.dto' 13 | import { InstitutionsService } from './institutions.service' 14 | import { SecretKeyGuard } from '../secret-key/secret-key.guard' 15 | 16 | @Controller('institutions') 17 | export class InstitutionsController { 18 | constructor(private readonly institutionsService: InstitutionsService) {} 19 | 20 | @Post() 21 | create(@Body() createInstitutionDto: CreateInstitutionDto) { 22 | return this.institutionsService.create(createInstitutionDto) 23 | } 24 | 25 | @Get() 26 | findAll() { 27 | return this.institutionsService.findAll() 28 | } 29 | 30 | @UseGuards(SecretKeyGuard) 31 | @Get('test') 32 | async testingSdk() { 33 | try { 34 | return { result: await this.institutionsService.findAll() } 35 | } catch (error) { 36 | return { error: error.message } 37 | } 38 | } 39 | 40 | @Get(':id') 41 | findOne(@Param('id') id: string) { 42 | return this.institutionsService.findOne(+id) 43 | } 44 | 45 | @Patch(':id') 46 | update( 47 | @Param('id') id: string, 48 | @Body() updateInstitutionDto: UpdateInstitutionDto 49 | ) { 50 | return this.institutionsService.update(+id, updateInstitutionDto) 51 | } 52 | 53 | @Delete(':id') 54 | remove(@Param('id') id: string) { 55 | return this.institutionsService.remove(+id) 56 | } 57 | } 58 | // make new module for sdk keys 59 | // together with test cases 60 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/institutions/institutions.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { TypeOrmModule } from '@nestjs/typeorm' 3 | import { Institution } from './entities/institution.entity' 4 | import { InstitutionsController } from './institutions.controller' 5 | import { InstitutionsService } from './institutions.service' 6 | import { SdkKeysModule } from '../sdk-keys/sdk-keys.module' 7 | 8 | @Module({ 9 | controllers: [InstitutionsController], 10 | providers: [InstitutionsService], 11 | imports: [TypeOrmModule.forFeature([Institution]), SdkKeysModule] 12 | }) 13 | export class InstitutionsModule {} 14 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/institutions/institutions.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { InstitutionsService } from './institutions.service'; 3 | 4 | describe('InstitutionsService', () => { 5 | let service: InstitutionsService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [InstitutionsService], 10 | }).compile(); 11 | 12 | service = module.get(InstitutionsService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/instructors/dto/create-instructor.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsEmail, IsOptional, IsString, IsUrl, IsBoolean, IsNumber } from 'class-validator' 2 | 3 | export class CreateInstructorDto { 4 | @IsString() 5 | name: string 6 | 7 | @IsEmail() 8 | email: string 9 | 10 | @IsString() 11 | @IsOptional() 12 | password: string 13 | 14 | @IsString() 15 | @IsUrl() 16 | @IsOptional() 17 | avatarUrl: string 18 | 19 | @IsBoolean() 20 | @IsOptional() 21 | status: boolean 22 | 23 | @IsString() 24 | @IsOptional() 25 | publicAddress: string 26 | 27 | @IsNumber() 28 | @IsOptional() 29 | roleId: number 30 | 31 | constructor(partial: Partial) { 32 | Object.assign(this, partial) 33 | } 34 | } -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/instructors/dto/update-instructor.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateInstructorDto } from './create-instructor.dto'; 3 | 4 | export class UpdateInstructorDto extends PartialType(CreateInstructorDto) {} 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/instructors/entities/instructor.entity.ts: -------------------------------------------------------------------------------- 1 | import { Exclude } from 'class-transformer' 2 | import { IsEmail, IsString } from 'class-validator' 3 | import { Preevent } from 'src/modules/preevent/entities/preevent.entity' 4 | import { 5 | BaseEntity, 6 | Column, 7 | CreateDateColumn, 8 | DeleteDateColumn, 9 | Entity, 10 | OneToMany, 11 | PrimaryGeneratedColumn, 12 | UpdateDateColumn, 13 | ManyToOne 14 | } from 'typeorm' 15 | import { Role } from 'src/modules/role/entities/role.entity' 16 | 17 | @Entity() 18 | export class Instructor extends BaseEntity { 19 | @PrimaryGeneratedColumn('increment') 20 | id: number 21 | 22 | @Column({ type: 'varchar', length: 30, nullable: true }) 23 | name: string 24 | 25 | @Column({ 26 | type: 'varchar', 27 | length: 50, 28 | unique: true, 29 | nullable: false 30 | }) 31 | @IsEmail() 32 | email: string 33 | 34 | @Exclude() 35 | @Column({ type: 'varchar', length: 255, nullable: false }) 36 | @IsString() 37 | password: string 38 | 39 | @Column({ type: 'varchar', length: 30, nullable: true }) 40 | avatarUrl: string 41 | 42 | @Column({ type: 'boolean', default: false }) 43 | status: boolean 44 | 45 | @Column({ type: 'varchar', length: 50, nullable: true, unique: true }) 46 | publicAddress: string 47 | 48 | @OneToMany(() => Preevent, (preevent) => preevent.instructor) 49 | preevent: Preevent[] 50 | 51 | @CreateDateColumn() 52 | createdAt: Date 53 | 54 | @UpdateDateColumn() 55 | updatedAt: Date 56 | 57 | @DeleteDateColumn() 58 | deletedAt: Date 59 | 60 | @ManyToOne(() => Role) 61 | role: Role 62 | 63 | @Column({ type: 'int', nullable: false }) 64 | roleId: number; 65 | } 66 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/instructors/instructors.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { InstructorsController } from './instructors.controller'; 3 | import { InstructorsService } from './instructors.service'; 4 | 5 | describe('InstructorsController', () => { 6 | let controller: InstructorsController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [InstructorsController], 11 | providers: [InstructorsService], 12 | }).compile(); 13 | 14 | controller = module.get(InstructorsController); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/instructors/instructors.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; 2 | import { InstructorsService } from './instructors.service'; 3 | import { CreateInstructorDto } from './dto/create-instructor.dto'; 4 | import { UpdateInstructorDto } from './dto/update-instructor.dto'; 5 | 6 | @Controller('instructors') 7 | export class InstructorsController { 8 | constructor(private readonly instructorsService: InstructorsService) {} 9 | 10 | @Post() 11 | create(@Body() createInstructorDto: CreateInstructorDto) { 12 | return this.instructorsService.create(createInstructorDto); 13 | } 14 | 15 | @Post('register-instructor') 16 | registerInstructor(@Body() createInstructorDto: CreateInstructorDto) { 17 | return this.instructorsService.onboardingInstructor(createInstructorDto); 18 | } 19 | 20 | @Get() 21 | findAll() { 22 | return this.instructorsService.findAll(); 23 | } 24 | 25 | @Get(':id') 26 | findOne(@Param('id') id: string) { 27 | return this.instructorsService.findOne(+id); 28 | } 29 | 30 | @Patch(':id') 31 | update(@Param('id') id: string, @Body() updateInstructorDto: UpdateInstructorDto) { 32 | return this.instructorsService.update(+id, updateInstructorDto); 33 | } 34 | 35 | @Delete(':id') 36 | remove(@Param('id') id: string) { 37 | return this.instructorsService.remove(+id); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/instructors/instructors.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { InstructorsService } from './instructors.service'; 3 | import { InstructorsController } from './instructors.controller'; 4 | import { TypeOrmModule } from '@nestjs/typeorm'; 5 | import { Instructor } from './entities/instructor.entity'; 6 | import { AuthModule } from '../auth/auth.module'; 7 | 8 | @Module({ 9 | controllers: [InstructorsController], 10 | providers: [InstructorsService], 11 | imports: [TypeOrmModule.forFeature([Instructor]), AuthModule], 12 | }) 13 | export class InstructorsModule {} 14 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/instructors/instructors.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { InstructorsService } from './instructors.service'; 3 | 4 | describe('InstructorsService', () => { 5 | let service: InstructorsService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [InstructorsService], 10 | }).compile(); 11 | 12 | service = module.get(InstructorsService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/instructors/instructors.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpException, Injectable, Inject } from '@nestjs/common'; 2 | import { CreateInstructorDto } from './dto/create-instructor.dto'; 3 | import { UpdateInstructorDto } from './dto/update-instructor.dto'; 4 | import { Instructor } from './entities/instructor.entity'; 5 | import { Repository } from 'typeorm'; 6 | import { InjectRepository } from '@nestjs/typeorm'; 7 | import { JwtService } from 'src/modules/auth/service/jwt.service'; 8 | 9 | @Injectable() 10 | export class InstructorsService { 11 | constructor( 12 | @InjectRepository(Instructor) 13 | private readonly instructorRepository: Repository, 14 | @Inject(JwtService) 15 | private readonly jwtService: JwtService, 16 | ) { } 17 | 18 | onboardingInstructor(createInstructorDto: CreateInstructorDto) { 19 | try { 20 | createInstructorDto.password = this.jwtService.encodePassword(createInstructorDto.password) 21 | createInstructorDto.roleId = 2; // default to instructor 22 | const instructor = this.instructorRepository.create(createInstructorDto); 23 | return this.instructorRepository.save(instructor); 24 | } catch (error) { 25 | throw new HttpException('Error in creating instructor', 400, { cause: new Error(error) }); 26 | } 27 | } 28 | 29 | create(createInstructorDto: CreateInstructorDto) { 30 | return 'This action adds a new instructor'; 31 | } 32 | 33 | findAll() { 34 | return `This action returns all instructors`; 35 | } 36 | 37 | findOne(id: number) { 38 | return `This action returns a #${id} instructor`; 39 | } 40 | 41 | update(id: number, updateInstructorDto: UpdateInstructorDto) { 42 | return `This action updates a #${id} instructor`; 43 | } 44 | 45 | remove(id: number) { 46 | return `This action removes a #${id} instructor`; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/learners/dto/create-learner.dto.ts: -------------------------------------------------------------------------------- 1 | export class CreateLearnerDto {} 2 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/learners/dto/update-learner.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateLearnerDto } from './create-learner.dto'; 3 | 4 | export class UpdateLearnerDto extends PartialType(CreateLearnerDto) {} 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/learners/entities/learner.entity.ts: -------------------------------------------------------------------------------- 1 | import { Exclude } from 'class-transformer' 2 | import { IsEmail, IsString } from 'class-validator' 3 | import { Role } from 'src/modules/role/entities/role.entity' 4 | import { 5 | BaseEntity, 6 | Column, 7 | CreateDateColumn, 8 | DeleteDateColumn, 9 | Entity, 10 | ManyToOne, 11 | PrimaryGeneratedColumn, 12 | UpdateDateColumn 13 | } from 'typeorm' 14 | @Entity() 15 | export class Learner extends BaseEntity { 16 | @PrimaryGeneratedColumn('increment') 17 | id: number 18 | 19 | @Column({ type: 'varchar', length: 30, nullable: true }) 20 | name: string 21 | 22 | @Column({ 23 | type: 'varchar', 24 | length: 50, 25 | unique: true, 26 | nullable: false 27 | }) 28 | @IsEmail() 29 | email: string 30 | 31 | @Exclude() 32 | @Column({ type: 'varchar', length: 255, nullable: false }) 33 | @IsString() 34 | @Exclude() 35 | password: string 36 | 37 | @Column({ type: 'varchar', length: 30, nullable: true }) 38 | avatarUrl: string 39 | 40 | @Column({ type: 'boolean', default: false }) 41 | status: boolean 42 | 43 | @Column({ type: 'varchar', length: 50, nullable: true, unique: true }) 44 | publicAddress: string 45 | 46 | @Column({ type: 'varchar', length: 50, nullable: true }) 47 | latitude: string 48 | 49 | @Column({ type: 'varchar', length: 50, nullable: true }) 50 | longitude: string 51 | 52 | @ManyToOne(() => Role) 53 | role: Role 54 | 55 | @CreateDateColumn() 56 | createdAt: Date 57 | 58 | @UpdateDateColumn() 59 | updatedAt: Date 60 | 61 | @DeleteDateColumn() 62 | deletedAt: Date 63 | } 64 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/learners/learners.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { LearnersController } from './learners.controller'; 3 | import { LearnersService } from './learners.service'; 4 | 5 | describe('LearnersController', () => { 6 | let controller: LearnersController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [LearnersController], 11 | providers: [LearnersService], 12 | }).compile(); 13 | 14 | controller = module.get(LearnersController); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/learners/learners.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Controller, 3 | Get, 4 | Post, 5 | Body, 6 | Patch, 7 | Param, 8 | Delete 9 | } from '@nestjs/common' 10 | import { LearnersService } from './learners.service' 11 | import { CreateLearnerDto } from './dto/create-learner.dto' 12 | import { UpdateLearnerDto } from './dto/update-learner.dto' 13 | 14 | @Controller('learners') 15 | export class LearnersController { 16 | constructor(private readonly learnersService: LearnersService) {} 17 | 18 | @Post() 19 | create(@Body() createLearnerDto: CreateLearnerDto) { 20 | return this.learnersService.create(createLearnerDto) 21 | } 22 | 23 | @Get() 24 | findAll() { 25 | return this.learnersService.findAll() 26 | } 27 | 28 | @Get(':id') 29 | findOne(@Param('id') id: string) { 30 | return this.learnersService.findOne(+id) 31 | } 32 | 33 | @Patch(':id') 34 | update( 35 | @Param('id') id: string, 36 | @Body() updateLearnerDto: UpdateLearnerDto 37 | ) { 38 | return this.learnersService.update(+id, updateLearnerDto) 39 | } 40 | 41 | @Delete(':id') 42 | remove(@Param('id') id: string) { 43 | return this.learnersService.remove(+id) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/learners/learners.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { LearnersController } from './learners.controller' 3 | import { LearnersService } from './learners.service' 4 | 5 | @Module({ 6 | controllers: [LearnersController], 7 | providers: [LearnersService] 8 | }) 9 | export class LearnersModule {} 10 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/learners/learners.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { LearnersService } from './learners.service'; 3 | 4 | describe('LearnersService', () => { 5 | let service: LearnersService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [LearnersService], 10 | }).compile(); 11 | 12 | service = module.get(LearnersService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/learners/learners.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common' 2 | import { CreateLearnerDto } from './dto/create-learner.dto' 3 | import { UpdateLearnerDto } from './dto/update-learner.dto' 4 | 5 | @Injectable() 6 | export class LearnersService { 7 | create(createLearnerDto: CreateLearnerDto) { 8 | return 'This action adds a new learner' 9 | } 10 | 11 | findAll() { 12 | return `This action returns all learners` 13 | } 14 | 15 | findOne(id: number) { 16 | return `This action returns a #${id} learner` 17 | } 18 | 19 | update(id: number, updateLearnerDto: UpdateLearnerDto) { 20 | return `This action updates a #${id} learner` 21 | } 22 | 23 | remove(id: number) { 24 | return `This action removes a #${id} learner` 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/postevent/dto/create-postevent.dto.ts: -------------------------------------------------------------------------------- 1 | import { 2 | IsString, 3 | IsArray, 4 | ValidateNested, 5 | IsEmail, 6 | IsISO8601, 7 | IsNumber 8 | } from 'class-validator' 9 | import { Type } from 'class-transformer' // Needed for nested validation 10 | import { Preevent } from 'src/modules/preevent/entities/preevent.entity' 11 | 12 | export class AttendeeDto { 13 | @IsString() 14 | LTId: string 15 | 16 | @IsString() 17 | name: string 18 | 19 | @IsEmail() // Validate as email 20 | email: string 21 | 22 | @IsISO8601() // Validate ISO 8601 date format 23 | joinTime: string // Keep it as string since it's a date string in ISO format 24 | 25 | @IsISO8601() // Validate ISO 8601 date format 26 | leaveTime: string // Keep it as string since it's a date string in ISO format 27 | 28 | @IsNumber() 29 | totalTime: number 30 | 31 | @IsNumber() 32 | attempted: number 33 | 34 | @IsNumber() 35 | total_questions: number 36 | 37 | @IsNumber() 38 | total_score: number 39 | 40 | preevent: Preevent 41 | } 42 | 43 | export class CreatePosteventDto { 44 | @IsString() 45 | meetingEventId: string 46 | 47 | @IsArray() // Validate the array 48 | @ValidateNested({ each: true }) // Validate each object in the array 49 | @Type(() => AttendeeDto) // Specify the type of objects in the array 50 | attendees: AttendeeDto[] 51 | } 52 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/postevent/dto/update-postevent.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreatePosteventDto } from './create-postevent.dto'; 3 | 4 | export class UpdatePosteventDto extends PartialType(CreatePosteventDto) {} 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/postevent/entities/postevent.entity.ts: -------------------------------------------------------------------------------- 1 | import { Preevent } from 'src/modules/preevent/entities/preevent.entity' 2 | import { 3 | Column, 4 | CreateDateColumn, 5 | Entity, 6 | JoinColumn, 7 | ManyToOne, 8 | PrimaryGeneratedColumn 9 | } from 'typeorm' 10 | 11 | @Entity() 12 | export class Postevent { 13 | @PrimaryGeneratedColumn('increment') 14 | id: number 15 | 16 | @Column({ type: 'varchar', length: 30, nullable: true }) 17 | name: string 18 | 19 | @Column({ type: 'varchar', length: 30, nullable: true, unique: false }) 20 | email: string 21 | 22 | @CreateDateColumn({ type: 'varchar', length: 30, nullable: true }) 23 | joinTime: Date 24 | 25 | @CreateDateColumn({ type: 'varchar', length: 30, nullable: true }) 26 | leaveTime: Date 27 | 28 | @ManyToOne(() => Preevent, (preevent) => preevent.postevents) 29 | preevent: Preevent 30 | } 31 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/postevent/postevent.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { PosteventController } from './postevent.controller'; 3 | import { PosteventService } from './postevent.service'; 4 | 5 | describe('PosteventController', () => { 6 | let controller: PosteventController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [PosteventController], 11 | providers: [PosteventService], 12 | }).compile(); 13 | 14 | controller = module.get(PosteventController); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/postevent/postevent.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { PosteventService } from './postevent.service' 3 | import { PosteventController } from './postevent.controller' 4 | import { TypeOrmModule } from '@nestjs/typeorm' 5 | import { Preevent } from '../preevent/entities/preevent.entity' 6 | import { Institution } from '../institutions/entities/institution.entity' 7 | import { SdkKeysModule } from '../sdk-keys/sdk-keys.module' 8 | import { Postevent } from './entities/postevent.entity' 9 | import { Learner } from '../learners/entities/learner.entity' 10 | import { Role } from '../role/entities/role.entity' 11 | import { SmartcontractModule } from '../smartcontract/smartcontract.module' 12 | 13 | @Module({ 14 | controllers: [PosteventController], 15 | providers: [PosteventService], 16 | imports: [ 17 | TypeOrmModule.forFeature([ 18 | Preevent, 19 | Institution, 20 | Postevent, 21 | Learner, 22 | Role 23 | ]), 24 | SdkKeysModule, 25 | SmartcontractModule 26 | ] 27 | }) 28 | export class PosteventModule {} 29 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/postevent/postevent.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { PosteventService } from './postevent.service'; 3 | 4 | describe('PosteventService', () => { 5 | let service: PosteventService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [PosteventService], 10 | }).compile(); 11 | 12 | service = module.get(PosteventService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/preevent/dto/create-preevent.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsArray, IsOptional, IsString } from 'class-validator' 2 | 3 | export class CreatePreeventDto { 4 | @IsString() 5 | meetingEventId: string 6 | 7 | @IsString() 8 | eventName: string 9 | 10 | @IsString() 11 | organizerName: string 12 | 13 | @IsString() 14 | organizerEmail: string 15 | 16 | @IsString() 17 | eventType: string 18 | 19 | @IsString() 20 | description: string 21 | 22 | @IsString() 23 | eventDate: Date 24 | 25 | @IsArray() 26 | speakersName: string[] 27 | 28 | @IsArray() 29 | speakersEmail: string[] 30 | 31 | @IsOptional() 32 | @IsString() 33 | organization: string 34 | 35 | @IsOptional() 36 | @IsString() 37 | community: string 38 | 39 | @IsOptional() 40 | @IsString() 41 | fieldsOfKnowledge: string 42 | 43 | @IsOptional() 44 | @IsString() 45 | taxonomyOfSkills: string 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/preevent/dto/update-preevent.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreatePreeventDto } from './create-preevent.dto'; 3 | 4 | export class UpdatePreeventDto extends PartialType(CreatePreeventDto) {} 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/preevent/preevent.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { PreeventController } from './preevent.controller'; 3 | import { PreeventService } from './preevent.service'; 4 | 5 | describe('PreeventController', () => { 6 | let controller: PreeventController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [PreeventController], 11 | providers: [PreeventService], 12 | }).compile(); 13 | 14 | controller = module.get(PreeventController); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/preevent/preevent.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { PreeventService } from './preevent.service' 3 | import { PreeventController } from './preevent.controller' 4 | import { SdkKeysModule } from '../sdk-keys/sdk-keys.module' 5 | import { Institution } from '../institutions/entities/institution.entity' 6 | import { TypeOrmModule } from '@nestjs/typeorm' 7 | import { Preevent } from './entities/preevent.entity' 8 | import { Instructor } from '../instructors/entities/instructor.entity' 9 | import { JwtService } from '../auth/service/jwt.service' 10 | import { OnlineEvent } from '../event/entities/event.entity' 11 | import { ScoringGuide } from '../event/entities/scoring-guide.entity' 12 | import { Role } from '../role/entities/role.entity' 13 | import { SmartcontractModule } from '../smartcontract/smartcontract.module' 14 | 15 | @Module({ 16 | controllers: [PreeventController], 17 | providers: [PreeventService], 18 | imports: [ 19 | TypeOrmModule.forFeature([ 20 | Preevent, 21 | Institution, 22 | Instructor, 23 | JwtService, 24 | OnlineEvent, 25 | ScoringGuide, 26 | Role 27 | ]), 28 | SdkKeysModule, 29 | SmartcontractModule 30 | ] 31 | }) 32 | export class PreeventModule {} 33 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/preevent/preevent.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { PreeventService } from './preevent.service'; 3 | 4 | describe('PreeventService', () => { 5 | let service: PreeventService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [PreeventService], 10 | }).compile(); 11 | 12 | service = module.get(PreeventService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/role/dto/create-role.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsNotEmpty, IsNumber, IsString } from 'class-validator' 2 | 3 | export class CreateRoleDto { 4 | @IsNotEmpty() 5 | @IsString() 6 | name: string 7 | 8 | @IsNotEmpty() 9 | @IsNumber() 10 | userId: number 11 | } 12 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/role/dto/update-role.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types' 2 | import { CreateRoleDto } from './create-role.dto' 3 | 4 | export class UpdateRoleDto extends PartialType(CreateRoleDto) {} 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/role/entities/role.entity.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BaseEntity, 3 | Column, 4 | CreateDateColumn, 5 | DeleteDateColumn, 6 | Entity, 7 | PrimaryGeneratedColumn, 8 | UpdateDateColumn 9 | } from 'typeorm' 10 | 11 | @Entity() 12 | export class Role extends BaseEntity { 13 | @PrimaryGeneratedColumn('increment') 14 | id: number 15 | 16 | @Column({ type: 'varchar', length: 30, nullable: true }) 17 | name: string 18 | 19 | @Column({ type: 'boolean', nullable: false, default: false }) 20 | isAdmin: boolean 21 | 22 | @CreateDateColumn() 23 | createdAt: Date 24 | 25 | @UpdateDateColumn() 26 | updatedAt: Date 27 | 28 | @DeleteDateColumn() 29 | deletedAt: Date 30 | } 31 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/role/role.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common' 2 | import { RoleService } from 'src/modules/role/role.service' 3 | 4 | @Controller() 5 | export class RoleController { 6 | constructor(private readonly roleService: RoleService) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/role/role.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { TypeOrmModule } from '@nestjs/typeorm' 3 | import { Role } from 'src/modules/role/entities/role.entity' 4 | import { RoleController } from 'src/modules/role/role.controller' 5 | import { RoleService } from 'src/modules/role/role.service' 6 | 7 | @Module({ 8 | imports: [TypeOrmModule.forFeature([Role])], 9 | controllers: [RoleController], 10 | providers: [RoleService] 11 | }) 12 | export class RoleModule {} 13 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/role/role.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common' 2 | import { InjectRepository } from '@nestjs/typeorm' 3 | import { Repository } from 'typeorm' 4 | import { CreateRoleDto } from './dto/create-role.dto' 5 | import { UpdateRoleDto } from './dto/update-role.dto' 6 | import { Role } from './entities/role.entity' 7 | 8 | @Injectable() 9 | export class RoleService { 10 | constructor( 11 | @InjectRepository(Role) 12 | private readonly roleRepository: Repository 13 | ) {} 14 | 15 | async create(createRoleDto: CreateRoleDto) { 16 | const insertionData = this.roleRepository.create(createRoleDto) 17 | return await this.roleRepository.save(insertionData) 18 | } 19 | 20 | async update(id: number, updateRoleDto: UpdateRoleDto) { 21 | const previousData = await this.roleRepository.findOne({ 22 | where: { id: id } 23 | }) 24 | if (!previousData) { 25 | return 26 | } 27 | 28 | return await this.roleRepository.save(updateRoleDto) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/role/seeder/seeder.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { TypeOrmModule } from '@nestjs/typeorm' 3 | import { Role } from '../entities/role.entity' 4 | import { User } from 'src/modules/admins/entities/user.entity' 5 | import { UserSeed } from './user-role.seed' 6 | 7 | @Module({ 8 | imports: [TypeOrmModule.forFeature([Role, User])], 9 | providers: [UserSeed], 10 | exports: [UserSeed] // Optional: Export if you want to use it elsewhere 11 | }) 12 | export class SeederModule {} 13 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/sdk-keys/sdk-keys.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { TypeOrmModule } from '@nestjs/typeorm' 3 | import { Institution } from '../institutions/entities/institution.entity' 4 | import { SdkKeysController } from './sdk-keys.controller' 5 | import { SdkKeysService } from './sdk-keys.service' 6 | 7 | @Module({ 8 | controllers: [SdkKeysController], 9 | providers: [SdkKeysService], 10 | imports: [TypeOrmModule.forFeature([Institution])], 11 | exports: [SdkKeysService] 12 | }) 13 | export class SdkKeysModule {} 14 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/secret-key/secret-key.guard.spec.ts: -------------------------------------------------------------------------------- 1 | import { SecretKeyGuard } from './secret-key.guard'; 2 | 3 | describe('SecretKeyGuard', () => { 4 | it('should be defined', () => { 5 | expect(new SecretKeyGuard()).toBeDefined(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/secret-key/secret-key.guard.ts: -------------------------------------------------------------------------------- 1 | import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common' 2 | import { SdkKeysService } from 'src/modules/sdk-keys/sdk-keys.service' 3 | 4 | @Injectable() 5 | export class SecretKeyGuard implements CanActivate { 6 | constructor(private readonly sdkKeysService: SdkKeysService) {} 7 | async canActivate(context: ExecutionContext) { 8 | const request: Request = context.switchToHttp().getRequest() 9 | const secretKey = request.headers['secretkey'] 10 | 11 | if (!secretKey) { 12 | return false 13 | } 14 | 15 | const isValid = await this.sdkKeysService.validateSecretKey(secretKey) 16 | if (!isValid) { 17 | return false 18 | } 19 | 20 | return true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/smartcontract/dto/create-course.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsEnum, IsNumber, IsString } from 'class-validator' 2 | import { RoleEnum } from 'src/modules/admins/enums/user.enum' 3 | 4 | export class CreateCourseDto { 5 | @IsString() 6 | courseName: string 7 | 8 | @IsNumber() 9 | preEventId: number 10 | } 11 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/smartcontract/dto/create-smartcontract.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsEnum, IsString } from 'class-validator' 2 | import { RoleEnum } from 'src/modules/admins/enums/user.enum' 3 | 4 | export class CreateSmartcontractDto {} 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/smartcontract/dto/distrbute-token.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsEnum, IsNumber, IsOptional, IsString } from 'class-validator' 2 | import { RoleEnum } from 'src/modules/admins/enums/user.enum' 3 | 4 | export class DistributeTokenDto { 5 | @IsNumber() 6 | preEventId: number 7 | 8 | @IsString() 9 | functionName: string 10 | 11 | @IsOptional() 12 | userIds: [] 13 | } 14 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/smartcontract/dto/update-smartcontract.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types' 2 | import { CreateSmartcontractDto } from './create-smartcontract.dto' 3 | 4 | export class UpdateSmartcontractDto extends PartialType( 5 | CreateSmartcontractDto 6 | ) {} 7 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/smartcontract/entities/smartcontract.entity.ts: -------------------------------------------------------------------------------- 1 | export class Smartcontract {} 2 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/smartcontract/enums/smartcontract-functions.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SmartcontractFunctionsEnum { 2 | REGISTER_INSTITUTION = 'registerInstitution', 3 | REGISTER_INSTRUCTOR = 'registerInstructor', 4 | REGISTER_LEARNER = 'registerLearner', 5 | ADD_INSTRUCTOR_TO_INSTITUTION = 'addInstructorToInstitution', 6 | CHECK_INSTRUCTOR_IN_INSTITUTION = 'isInstructorInInstitution', 7 | LEARNER_TOKEN_METADATA = 'getLearnerTokenMetadata', 8 | TOKEN_BALANCE = 'balanceOf' 9 | } 10 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/smartcontract/smartcontract.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing' 2 | import { SmartcontractController } from './smartcontract.controller' 3 | import { SmartcontractService } from './smartcontract.service' 4 | 5 | describe('SmartcontractController', () => { 6 | let controller: SmartcontractController 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [SmartcontractController], 11 | providers: [SmartcontractService] 12 | }).compile() 13 | 14 | controller = module.get( 15 | SmartcontractController 16 | ) 17 | }) 18 | 19 | it('should be defined', () => { 20 | expect(controller).toBeDefined() 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/smartcontract/smartcontract.module.ts: -------------------------------------------------------------------------------- 1 | import { Module, Post } from '@nestjs/common' 2 | import { SmartcontractService } from './smartcontract.service' 3 | import { SmartcontractController } from './smartcontract.controller' 4 | import { ConfigService } from '@nestjs/config' 5 | import { TypeOrmModule } from '@nestjs/typeorm' 6 | import { Postevent } from '../postevent/entities/postevent.entity' 7 | import { Preevent } from '../preevent/entities/preevent.entity' 8 | import { Learner } from '../learners/entities/learner.entity' 9 | import { Institution } from '../institutions/entities/institution.entity' 10 | import { Instructor } from '../instructors/entities/instructor.entity' 11 | import { OnlineEvent } from '../event/entities/event.entity' 12 | import { ScoringGuide } from '../event/entities/scoring-guide.entity' 13 | 14 | @Module({ 15 | imports: [ 16 | TypeOrmModule.forFeature([ 17 | Preevent, 18 | Learner, 19 | Institution, 20 | Instructor, 21 | Postevent, 22 | ScoringGuide, 23 | OnlineEvent 24 | ]) 25 | ], 26 | controllers: [SmartcontractController], 27 | providers: [SmartcontractService, ConfigService], 28 | exports: [SmartcontractService] 29 | }) 30 | export class SmartcontractModule {} 31 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/modules/smartcontract/smartcontract.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { SmartcontractService } from './smartcontract.service'; 3 | 4 | describe('SmartcontractService', () => { 5 | let service: SmartcontractService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [SmartcontractService], 10 | }).compile(); 11 | 12 | service = module.get(SmartcontractService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/learning-token-backend/src/utils/kaledio.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import * as dotenv from 'dotenv' 3 | dotenv.config() 4 | const kaledio = 5 | process.env.KALEIDO_HD_WALLET_RPC_URL + 6 | 'api/v1/wallets/:walletId/accounts/:accountIndex' 7 | // ;('https://u0k1dk029t:hU5ERoJz_xLvmQzr8h1jmLr6a3Afn4Oa6T4NHjKJ2ro@u0jtyl6s8p-u0gt6e2xu2-hdwallet.us0-aws.kaleido.io/api/v1/wallets/:walletId/accounts/:accountIndex') 8 | export const getWallet = async (type: string, id: number) => { 9 | //decrement id by 1 since the index starts from 0 10 | id = id - 1 11 | let url = '' 12 | if (type === 'admin') { 13 | const _id = process.env.ADMIN_HD_WALLET_ID 14 | url = kaledio 15 | .replace(':walletId', _id) 16 | .replace(':accountIndex', id.toString()) 17 | } 18 | if (type === 'institution') { 19 | const _id = process.env.INSTITUTION_HD_WALLET_ID 20 | url = kaledio 21 | .replace(':walletId', _id) 22 | .replace(':accountIndex', id.toString()) 23 | } 24 | if (type === 'instructor') { 25 | const _id = process.env.INSTRUCTOR_HD_WALLET_ID 26 | url = kaledio 27 | .replace(':walletId', _id) 28 | .replace(':accountIndex', id.toString()) 29 | } 30 | if (type === 'learner') { 31 | const _id = process.env.LEARNER_HD_WALLET_ID 32 | url = kaledio 33 | .replace(':walletId', _id) 34 | .replace(':accountIndex', id.toString()) 35 | } 36 | 37 | const result = await axios.get(url) 38 | console.log(type, id, result.data) 39 | return result.data 40 | } 41 | -------------------------------------------------------------------------------- /src/learning-token-backend/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/learning-token-backend/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/learning-token-backend/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /src/learning-token-backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "resolveJsonModule": true, 11 | "sourceMap": true, 12 | "outDir": "./dist", 13 | "baseUrl": "./", 14 | "incremental": true, 15 | "skipLibCheck": true, 16 | "strictNullChecks": false, 17 | "noImplicitAny": false, 18 | "strictBindCallApply": false, 19 | "forceConsistentCasingInFileNames": false, 20 | "noFallthroughCasesInSwitch": false 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | ignorePatterns: ['dist', '.eslintrc.cjs'], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': [ 14 | 'warn', 15 | { allowConstantExport: true }, 16 | ], 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/.example.env: -------------------------------------------------------------------------------- 1 | VITE_API_URL=http://localhost:3000/api 2 | VITE_SMART_CONTRACT=0x71C95911E9a5D330f4D621842EC243EE1343292e 3 | VITE_PINATA_API_KEY= 4 | VITE_PINATA_URL= -------------------------------------------------------------------------------- /src/learning-token-dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | .env 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | pnpm-debug.log* 9 | lerna-debug.log* 10 | 11 | node_modules 12 | dist 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/Dockerfile: -------------------------------------------------------------------------------- 1 | # Set the base image 2 | FROM node:16.18-alpine AS builder 3 | 4 | # Set the working directory 5 | WORKDIR /app 6 | 7 | 8 | # Copy the package.json and yarn.lock files to the container 9 | COPY package.json /app 10 | 11 | # Install dependencies 12 | RUN yarn 13 | 14 | # Copy the rest of the app files to the container 15 | COPY . /app 16 | 17 | # # Build the app 18 | # RUN yarn dev 19 | 20 | # # Set the base image for the production build 21 | # FROM nginx:alpine 22 | 23 | # # Copy the build files to the container 24 | # COPY --from=builder /app/build /usr/share/nginx/html 25 | 26 | # # Copy the nginx configuration file to the container 27 | # COPY /client/web-app/nginx.conf /etc/nginx/conf.d/default.conf 28 | 29 | # Expose port 8080 30 | EXPOSE 5173 31 | 32 | # Start the nginx server 33 | # CMD ["nginx", "-g", "daemon off;"] 34 | CMD ["yarn", "dev"] 35 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 13 | 14 | - Configure the top-level `parserOptions` property like this: 15 | 16 | ```js 17 | parserOptions: { 18 | ecmaVersion: 'latest', 19 | sourceType: 'module', 20 | project: ['./tsconfig.json', './tsconfig.node.json'], 21 | tsconfigRootDir: __dirname, 22 | }, 23 | ``` 24 | 25 | - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` 26 | - Optionally add `plugin:@typescript-eslint/stylistic-type-checked` 27 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list 28 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | learning-token-fronted: 4 | build: 5 | context: . 6 | dockerfile: ./Dockerfile 7 | 8 | # args: 9 | # - VITE_API_URL=http://192.168.9.228:3000/api 10 | # - VITE_SOCKET_URL=http://192.168.9.228:3000 11 | # - VITE_AI_URL=http://dune.anchorblock.vc:3050 12 | 13 | # - VITE_ZOHO_CLIENT_ID=1000.NGLFO7A6NQZTEILTTJPWLOGPHB0Z8D 14 | # - VITE_ZOHO_CLIENT_SECRET=9169c3bdb23d34d799a4e368de41eb24e7faf8b09a 15 | # - VITE_ZOHO_REDIRECT_URI=http://localhost:3001/integrations/zoho 16 | 17 | # - VITE_GOOGLE_CLIENT_ID=972106470134-lnu97g80nebp29c1r9905ngbh076hvvl.apps.googleusercontent.com 18 | # - VITE_GOOGLE_REDIRECT_URL=https://app.anchorbooks.ai/auth 19 | 20 | image: learning-token-fronted 21 | ports: 22 | - "5173:5173" 23 | container_name: learning-token-fronted 24 | environment: 25 | - VITE_API_URL=http://localhost:3000/api 26 | - VITE_SMART_CONTRACT=0x5FbDB2315678afecb367f032d93F642f64180aa3 27 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | Learning-Token 14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperledger-dashboard", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@metismenu/react": "^0.0.3", 14 | "@pinata/sdk": "^2.1.0", 15 | "@reduxjs/toolkit": "^1.9.6", 16 | "axios": "^1.6.2", 17 | "bootstrap": "^5.3.3", 18 | "ethers": "^6.7.1", 19 | "formik": "^2.4.5", 20 | "react": "^18.2.0", 21 | "react-bootstrap": "^2.10.5", 22 | "react-dom": "^18.2.0", 23 | "react-hot-toast": "^2.4.1", 24 | "react-icons": "^4.11.0", 25 | "react-redux": "^8.1.2", 26 | "react-router-dom": "^6.16.0", 27 | "react-select": "^5.7.5", 28 | "rsuite": "^5.40.0", 29 | "sass": "^1.79.5", 30 | "xlsx": "^0.18.5", 31 | "yup": "^1.3.2" 32 | }, 33 | "devDependencies": { 34 | "@types/react": "^18.2.15", 35 | "@types/react-dom": "^18.2.7", 36 | "@typescript-eslint/eslint-plugin": "^6.0.0", 37 | "@typescript-eslint/parser": "^6.0.0", 38 | "@vitejs/plugin-react": "^4.0.3", 39 | "autoprefixer": "^10.4.16", 40 | "eslint": "^8.45.0", 41 | "eslint-plugin-react-hooks": "^4.6.0", 42 | "eslint-plugin-react-refresh": "^0.4.3", 43 | "postcss": "^8.4.31", 44 | "tailwindcss": "^3.3.3", 45 | "typescript": "^5.0.2", 46 | "vite": "^4.4.5" 47 | }, 48 | "packageManager": "yarn@4.1.0+sha512.5b7bc055cad63273dda27df1570a5d2eb4a9f03b35b394d3d55393c2a5560a17f5cef30944b11d6a48bcbcfc1c3a26d618aae77044774c529ba36cb771ad5b0f" 49 | } 50 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/public/L.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/learning-token-dashboard/public/L.png -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/components/Accordion/index.tsx: -------------------------------------------------------------------------------- 1 | import {FC, useRef} from 'react' 2 | import {BiChevronDown} from 'react-icons/bi' 3 | type Props = { 4 | data: { 5 | id: number 6 | name: String 7 | } 8 | active: number 9 | handleToggle: (index: number) => void 10 | children?: JSX.Element 11 | } 12 | const AccordionItem: FC = ({data, active, handleToggle, children}) => { 13 | const detailsRef = useRef(null) 14 | const {id, name} = data 15 | return ( 16 |
17 |
handleToggle(data.id)} 20 | > 21 | {name} 22 | 27 | 28 | 29 |
30 |
37 | {children} 38 |
39 |
40 | ) 41 | } 42 | 43 | export default AccordionItem 44 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/components/Modal/SuccessModal.tsx: -------------------------------------------------------------------------------- 1 | import { Modal, Button } from "react-bootstrap"; 2 | 3 | export const SuccessModal = ({ show, message, onClose }) => ( 4 | 5 | 6 | Success 7 | 8 | {message} 9 | 10 | 13 | 14 | 15 | ); 16 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/components/Pagination/index.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef } from "react"; 2 | import { Pagination as RsuitePagination } from "rsuite"; 3 | import { PaginationGroupProps } from "rsuite/esm/Pagination/PaginationGroup"; 4 | 5 | interface Props extends PaginationGroupProps {} 6 | 7 | const Pagination = forwardRef(({ ...props }: Props) => { 8 | if (props.total <= 1) return <>; 9 | 10 | return ( 11 |
12 | 25 |
26 | ); 27 | }); 28 | 29 | export default Pagination; 30 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/components/Sidebar/NewSidebar.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | const NewSidebar = () => { 4 | return ( 5 |
NewSidebar
6 | ) 7 | } 8 | 9 | export default NewSidebar -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/components/Sidebar/ProtectedSidebar.tsx: -------------------------------------------------------------------------------- 1 | import { FC } from "react"; 2 | import { useSelector } from "react-redux"; 3 | import { RootState } from "../../store"; 4 | 5 | interface Props { 6 | children: React.ReactNode; 7 | permissions?: string[]; 8 | item?: any; 9 | } 10 | const ProtectedSidebar: FC = ({ children, permissions = [], item }) => { 11 | const { user } = useSelector((state: RootState) => state.auth); 12 | 13 | const hasRequiredPermissions = [user.type].some((i: any) => 14 | permissions.includes(i) 15 | ); 16 | 17 | if (item && item.subMenu) { 18 | const subPermissions = item.subMenu 19 | .map((i: any) => i.requiredPermissions) 20 | .flat(); 21 | 22 | const hasSubPermissions = [user.type].some((i) => 23 | subPermissions.includes(i) 24 | ); 25 | 26 | if (user.type === "admin" || hasSubPermissions) { 27 | return <>{children}; 28 | } else { 29 | return null; 30 | } 31 | } else if (user.type === "admin" || hasRequiredPermissions) { 32 | return <>{children}; 33 | } else { 34 | return null; 35 | } 36 | }; 37 | 38 | export default ProtectedSidebar; 39 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/components/Topbar/index.tsx: -------------------------------------------------------------------------------- 1 | import toast from "react-hot-toast"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | import { useNavigate } from "react-router-dom"; 4 | import { userLoggedOut } from "../../store/features/auth/authSlice"; 5 | import { RootState } from "../../store"; 6 | 7 | const Topbar = () => { 8 | const auth = useSelector((state: RootState) => state.auth); 9 | const dispatch = useDispatch(); 10 | const navigate = useNavigate(); 11 | const logout = () => { 12 | dispatch(userLoggedOut()); 13 | toast.success("Logged Out"); 14 | navigate("/login"); 15 | }; 16 | return ( 17 |
18 |
19 |
Hello, {auth.user.name}
20 |
|
21 | 22 |
23 |
24 | ); 25 | }; 26 | 27 | export default Topbar; 28 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/contexts/EventContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useContext, useState, ReactNode } from 'react'; 2 | 3 | interface EventContextType { 4 | eventData: any; 5 | setEventData: React.Dispatch>; 6 | } 7 | 8 | const EventContext = createContext(null); 9 | 10 | interface EventProviderProps { 11 | children: ReactNode; 12 | } 13 | 14 | // EventProvider component 15 | export const EventProvider: React.FC = ({ children }) => { 16 | const [eventData, setEventData] = useState(null); 17 | 18 | return ( 19 | 20 | {children} 21 | 22 | ); 23 | }; 24 | 25 | // Custom hook for easy context consumption 26 | export const useEventContext = () => { 27 | const context = useContext(EventContext); 28 | if (!context) { 29 | throw new Error('useEventContext must be used within an EventProvider'); 30 | } 31 | return context; 32 | }; -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/css/EventsAdd.css: -------------------------------------------------------------------------------- 1 | .arrow-right { 2 | display: inline-block; 3 | width: 0; 4 | height: 0; 5 | margin-left: 8px; /* Space between text and arrow */ 6 | border-top: 6px solid transparent; 7 | border-bottom: 6px solid transparent; 8 | border-left: 6px solid currentColor; /* Color of the arrow */ 9 | position: relative; 10 | top: 1px; /* Adjust to center vertically */ 11 | } -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/enums/roles.enum.ts: -------------------------------------------------------------------------------- 1 | export enum RoleEnum { 2 | ADMIN = 'admin', 3 | INSTITUTION = 'institution', 4 | INSTRUCTOR = 'instructor', 5 | LEARNER = 'learner' 6 | } -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/enums/smartcontract-functions.enum.ts: -------------------------------------------------------------------------------- 1 | export enum SmartcontractFunctionsEnum { 2 | REGISTER_INSTITUTION = 'registerInstitution', 3 | BATCH_MINT_ATTENDANCE_TOKEN = 'batchMintAttendanceToken', 4 | BATCH_MINT_SCORE_TOKEN = 'batchMintScoreToken', 5 | BATCH_MINT_INSTRUCTOR_SCORE_TOKEN = 'batchMintInstructorScoreToken', 6 | BATCH_MINT_HELPING_TOKEN = 'batchMintHelpingToken', 7 | GET_LEARNER_TOKEN_METADATA = 'getLearnerTokenMetadata', 8 | BALANCE_OF = 'balanceOf', 9 | } -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/hooks/usePagination.tsx: -------------------------------------------------------------------------------- 1 | import {useEffect, useState} from 'react' 2 | import {useLocation, useNavigate} from 'react-router-dom' 3 | 4 | const usePagination = (pageValue = 1, limitValue = 12) => { 5 | const navigate = useNavigate() 6 | const location = useLocation() 7 | const searchParams = new URLSearchParams(location.search) 8 | 9 | const [page, setPage] = useState(Number(searchParams.get('page')) || pageValue) 10 | const [limit, setLimit] = useState(Number(searchParams.get('limit')) || limitValue) 11 | 12 | useEffect(() => { 13 | if (searchParams.has('page')) { 14 | setPage(Number(searchParams.get('page'))) 15 | } 16 | if (searchParams.has('limit')) { 17 | setLimit(Number(searchParams.get('limit'))) 18 | } 19 | // eslint-disable-next-line react-hooks/exhaustive-deps 20 | }, [location.search]) 21 | 22 | const handleChangeLimit = (limit: number) => { 23 | setLimit(limit) 24 | searchParams.set('limit', limit.toString()) 25 | navigate({ 26 | search: searchParams.toString(), 27 | }) 28 | } 29 | 30 | const handleChangePage = (page: number) => { 31 | setPage(page) 32 | searchParams.set('page', page.toString()) 33 | navigate({ 34 | search: searchParams.toString(), 35 | }) 36 | } 37 | 38 | const handleNext = () => { 39 | handleChangePage(page + 1) 40 | } 41 | 42 | const handlePrev = () => { 43 | handleChangePage(page - 1) 44 | } 45 | 46 | return {page, limit, handlePrev, handleNext, handleChangePage, handleChangeLimit} 47 | } 48 | 49 | export default usePagination 50 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/index.css: -------------------------------------------------------------------------------- 1 | @import "rsuite/dist/rsuite.css"; 2 | @tailwind base; 3 | @tailwind components; 4 | @tailwind utilities; 5 | @layer base { 6 | body { 7 | @apply font-poppins; 8 | } 9 | a{ 10 | text-decoration: none !important; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { Toaster } from "react-hot-toast"; 4 | import { Provider } from "react-redux"; 5 | import "./index.css"; 6 | import AllRoutes from "./routes/index.tsx"; 7 | import { store } from "./store/index.tsx"; 8 | import 'bootstrap/dist/css/bootstrap.min.css'; 9 | 10 | ReactDOM.createRoot(document.getElementById("root")!).render( 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/pages/course/index.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { initWeb3Method } from "../../utils"; 3 | import { Table } from "rsuite"; 4 | import { useSelector } from "react-redux"; 5 | import { RootState } from "../../store"; 6 | const { Column, HeaderCell, Cell } = Table; 7 | const Course = () => { 8 | const [courseIdOptions, setCourseIdOptions] = useState([]); 9 | const auth = useSelector((state: RootState) => state.auth); 10 | 11 | const getCourse = async () => { 12 | const contract = await initWeb3Method(); 13 | const courseLength = await contract!.courseId(); 14 | 15 | let temp: any = []; 16 | if (Number(courseLength) > 0) { 17 | for (let index = 0; index < Number(courseLength); index++) { 18 | const tx = await contract!.courses(index); 19 | let obj = { value: 0, label: "" }; 20 | for (let key in tx) { 21 | if (+key === 3 && auth.user.publicAddress) { 22 | obj.value = index + 1; 23 | } 24 | if (+key === 5) { 25 | obj.label = tx[key]; 26 | } 27 | } 28 | if (obj.value !== 0) { 29 | temp.push(obj); 30 | } 31 | } 32 | } 33 | setCourseIdOptions(temp); 34 | }; 35 | 36 | useEffect(() => { 37 | getCourse(); 38 | }, []); 39 | 40 | return ( 41 |
42 | 43 | 44 | Id 45 | 46 | 47 | 48 | 49 | Course Name 50 | 51 | 52 |
53 |
54 | ); 55 | }; 56 | 57 | export default Course; 58 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/pages/events/EventsAdd.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import ScoringGuide from "./ScoringGuide"; 3 | import CreateCourse from "./CreateCourse"; 4 | import DistributeToken from "./DistributeToken"; 5 | import { Nav, Container } from "react-bootstrap"; 6 | import "../../css/EventsAdd.css"; 7 | import { useLocation } from "react-router-dom"; 8 | 9 | const EventsAdd = () => { 10 | const [step, setStep] = useState(1); 11 | const handleStep = (step: number) => setStep(step); 12 | const location = useLocation(); 13 | 14 | const steps = [ 15 | { label: "Scoring Guide", id: 1 }, 16 | { label: "Review Wallets", id: 2 }, 17 | { label: "Distribute Token", id: 3 }, 18 | ]; 19 | 20 | useEffect(() => { 21 | const params = new URLSearchParams(location.search); 22 | const stepParam = params.get("step"); 23 | if(stepParam) { 24 | setStep(parseInt(stepParam, 10)); 25 | } 26 | }, [location]); 27 | 28 | return ( 29 | 30 | 45 | 46 |
47 | {step === 1 && } 48 | {step === 2 && } 49 | {step === 3 && } 50 |
51 |
52 | ); 53 | }; 54 | 55 | export default EventsAdd; 56 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as Dashboard } from "./Dashboard"; 2 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/pages/layouts/MasterLayout.tsx: -------------------------------------------------------------------------------- 1 | import { FC, Suspense } from "react"; 2 | import { Outlet } from "react-router-dom"; 3 | import Sidebar from "../../components/Sidebar"; 4 | import Topbar from "../../components/Topbar"; 5 | import ProtectedLayout from "./ProtectedLayout"; 6 | 7 | const MasterLayout: FC = () => { 8 | return ( 9 | <> 10 | 11 | 12 | 13 |
14 | Loading...
}> 15 | 16 | 17 | 18 |
19 | 20 | ); 21 | }; 22 | 23 | export default MasterLayout; 24 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/pages/layouts/ProtectedLayout.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useSelector } from "react-redux"; 3 | import { useNavigate } from "react-router-dom"; 4 | import { RootState } from "../../store"; 5 | 6 | const ProtectedLayout = ({ children }: { children: React.ReactNode }) => { 7 | const { accessToken } = useSelector((state: RootState) => state.auth); 8 | 9 | const navigate = useNavigate(); 10 | useEffect(() => { 11 | if (!accessToken) { 12 | navigate("/login"); 13 | return; 14 | } 15 | }, [accessToken]); 16 | 17 | return <>{children}; 18 | }; 19 | 20 | export default ProtectedLayout; 21 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/pages/learner/index.tsx: -------------------------------------------------------------------------------- 1 | import { Table } from "rsuite"; 2 | 3 | import { 4 | useLazyGetLearnerListQuery, 5 | } from "../../store/features/admin/adminApi"; 6 | import usePagination from "../../hooks/usePagination"; 7 | import { useEffect } from "react"; 8 | import Pagination from "../../components/Pagination"; 9 | const { Column, HeaderCell, Cell } = Table; 10 | const Learner = () => { 11 | const [getLearnerList, { data, isLoading }] = useLazyGetLearnerListQuery(); 12 | 13 | const pagination = usePagination(); 14 | 15 | useEffect(() => { 16 | getLearnerList({ 17 | page: pagination.page, 18 | limit: pagination.limit, 19 | }); 20 | }, [pagination.page, pagination.limit]); 21 | 22 | if (isLoading) { 23 | return <>Loading...; 24 | } 25 | 26 | return ( 27 |
28 | 29 | 30 | Id 31 | 32 | 33 | 34 | 35 | Name 36 | 37 | 38 | 39 | 40 | Email 41 | 42 | 43 | 44 | 45 | Public Address 46 | 47 | 48 |
49 | 50 | 57 |
58 | ); 59 | }; 60 | 61 | export default Learner; 62 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/store/features/api/apiSlice.ts: -------------------------------------------------------------------------------- 1 | import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; 2 | import { authEnum } from "../auth/authSlice"; 3 | 4 | const baseQuery = fetchBaseQuery({ 5 | baseUrl: import.meta.env.VITE_API_URL, 6 | prepareHeaders: (headers) => { 7 | const accessToken = localStorage.getItem(authEnum.AUTH_LOCAL_STORAGE_KEY); 8 | if (accessToken) { 9 | headers.set("Authorization", `Bearer ${accessToken}`); 10 | } 11 | return headers; 12 | }, 13 | }); 14 | 15 | export const apiSlice = createApi({ 16 | baseQuery: async (args, api, extraOptions) => { 17 | let result = await baseQuery(args, api, extraOptions); 18 | return result; 19 | }, 20 | tagTypes: [], 21 | // @ts-ignore 22 | endpoints: (builder) => ({}), 23 | }); 24 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/store/features/institution/institutionApi.ts: -------------------------------------------------------------------------------- 1 | import { apiSlice } from "../api/apiSlice"; 2 | 3 | export const institutionApi = apiSlice 4 | .enhanceEndpoints({ addTagTypes: ["InstitutionAuth", "InstitutionKey"] }) 5 | .injectEndpoints({ 6 | endpoints: (builder) => ({ 7 | loginInstitution: builder.mutation({ 8 | query: (body) => ({ 9 | url: "/auth/institution-login", 10 | method: "POST", 11 | body, 12 | }), 13 | invalidatesTags: ["InstitutionAuth"], 14 | }), 15 | registerInstitution: builder.mutation({ 16 | query: (body) => ({ 17 | url: "/auth/institution-register", 18 | method: "POST", 19 | body, 20 | }), 21 | invalidatesTags: ["InstitutionAuth"], 22 | }), 23 | generateSdkKeyInstitution: builder.query({ 24 | query: (id) => `sdk-keys/gen/${id}`, 25 | providesTags: ["InstitutionKey"], 26 | }), 27 | getSdkKeyInstitution: builder.query({ 28 | query: (id) => `sdk-keys/get/${id}`, 29 | providesTags: ["InstitutionKey"], 30 | }), 31 | }), 32 | }); 33 | 34 | export const { 35 | useGetSdkKeyInstitutionQuery, 36 | useLazyGetSdkKeyInstitutionQuery, 37 | useGenerateSdkKeyInstitutionQuery, 38 | useLazyGenerateSdkKeyInstitutionQuery, 39 | useLoginInstitutionMutation, 40 | useRegisterInstitutionMutation, 41 | } = institutionApi; 42 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/store/features/instructor/instructorApi.ts: -------------------------------------------------------------------------------- 1 | import { apiSlice } from "../api/apiSlice"; 2 | 3 | export const instructorApi = apiSlice 4 | .enhanceEndpoints({ addTagTypes: ["instructorAuth"] }) 5 | .injectEndpoints({ 6 | endpoints: (builder) => ({ 7 | loginInstructor: builder.mutation({ 8 | query: (body) => ({ 9 | url: "/auth/instructor-login", 10 | method: "POST", 11 | body, 12 | }), 13 | invalidatesTags: ["instructorAuth"], 14 | }), 15 | registerInstructor: builder.mutation({ 16 | query: (body) => ({ 17 | url: "/auth/instructor-register", 18 | method: "POST", 19 | body, 20 | }), 21 | invalidatesTags: ["instructorAuth"], 22 | }), 23 | }), 24 | }); 25 | 26 | export const { useLoginInstructorMutation, useRegisterInstructorMutation } = 27 | instructorApi; 28 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/store/features/learner/learnerApi.ts: -------------------------------------------------------------------------------- 1 | import { apiSlice } from "../api/apiSlice"; 2 | 3 | export const learnerApi = apiSlice 4 | .enhanceEndpoints({ addTagTypes: ["learnerAuth"] }) 5 | .injectEndpoints({ 6 | endpoints: (builder) => ({ 7 | loginLearner: builder.mutation({ 8 | query: (body) => ({ 9 | url: "/auth/learner-login", 10 | method: "POST", 11 | body, 12 | }), 13 | invalidatesTags: ["learnerAuth"], 14 | }), 15 | registerLearner: builder.mutation({ 16 | query: (body) => ({ 17 | url: "/auth/learner-register", 18 | method: "POST", 19 | body, 20 | }), 21 | invalidatesTags: ["learnerAuth"], 22 | }), 23 | }), 24 | }); 25 | 26 | export const { useLoginLearnerMutation, useRegisterLearnerMutation } = 27 | learnerApi; 28 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/store/index.tsx: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import authSlice from "./features/auth/authSlice"; 3 | import { apiSlice } from "./features/api/apiSlice"; 4 | 5 | export const store = configureStore({ 6 | reducer: { 7 | api: apiSlice.reducer, 8 | auth: authSlice, 9 | }, 10 | middleware: (getDefaultMiddleware) => 11 | getDefaultMiddleware().concat(apiSlice.middleware), 12 | }); 13 | 14 | // Infer the `RootState` and `AppDispatch` types from the store itself 15 | export type RootState = ReturnType; 16 | // Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState} 17 | export type AppDispatch = typeof store.dispatch; 18 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "ethers"; 2 | import abi from "../contracts/LearningToken.json"; 3 | const SMART_CONTRACT = import.meta.env.VITE_SMART_CONTRACT; 4 | export const initWeb3 = async () => { 5 | if ((window as any).ethereum) { 6 | const provider = new ethers.BrowserProvider((window as any).ethereum); 7 | const signer = await provider.getSigner(); 8 | const contract = new ethers.Contract(SMART_CONTRACT!, abi, signer); 9 | return contract; 10 | } 11 | }; 12 | 13 | export const initWeb3Method = async () => { 14 | if ((window as any).ethereum) { 15 | const provider = new ethers.BrowserProvider((window as any).ethereum); 16 | // const accounts = await window.ethereum.request({ 17 | // method: "eth_requestAccounts", 18 | // }); 19 | 20 | const signer = await provider.getSigner(); 21 | 22 | const contract = new ethers.Contract(SMART_CONTRACT!, abi, signer); 23 | return contract; 24 | } 25 | }; 26 | 27 | export const formatDate = (timestamp: number) => { 28 | const date = new Date(timestamp); 29 | 30 | return date.getDate() + "/" + date.getMonth() + "/" + date.getFullYear(); 31 | }; 32 | 33 | export const formatDateTime = (utc: number) => { 34 | const date = new Date(utc); 35 | const options = { 36 | year: "numeric", 37 | month: "long", 38 | day: "numeric", 39 | hour: "2-digit", 40 | minute: "2-digit", 41 | timezone: "UTC", 42 | }; 43 | 44 | return date.toLocaleString('en-US', options); 45 | }; 46 | 47 | export const getRandomFileName = () => { 48 | return Math.random().toString(36).substring(2, 15) + Math.random().toString(23).substring(2, 5); 49 | }; 50 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], 4 | theme: { 5 | extend: { 6 | fontFamily: { 7 | poppins: ["Poppins", " sans-serif"], 8 | }, 9 | }, 10 | }, 11 | plugins: [], 12 | }; 13 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /src/learning-token-dashboard/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from "@vitejs/plugin-react"; 2 | import { defineConfig } from "vite"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | optimizeDeps: { 8 | exclude: ["ethers"], 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /src/learning-token/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/learning-token/.DS_Store -------------------------------------------------------------------------------- /src/learning-token/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | typechain-types 7 | 8 | # Hardhat files 9 | cache 10 | artifacts 11 | 12 | -------------------------------------------------------------------------------- /src/learning-token/arguments.d.ts: -------------------------------------------------------------------------------- 1 | declare module "./arguments" { 2 | export const owners: string[]; 3 | export const numConfirmationsRequired: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/learning-token/arguments.js: -------------------------------------------------------------------------------- 1 | const owners = [ 2 | "0x8F1f90DCf24b532e3580998E78fdc5224f94307E", 3 | "0xac11e7EBd7fbE14955c11Be20f2ddd67a037DB48", 4 | "0x38F910aCecf89B19F661a906d537A2e13b279E3d", 5 | ]; 6 | const numConfirmationsRequired = 2; 7 | const testUSDT = "0x62BaA3121879159AaAed2ca8EbB60A2933d9Ad36"; 8 | const testUSDC = "0xFa134E4FB126d143336A4852eFe16CEB8d62270e"; 9 | const testDai = "0x44d2d8C3b8CcCAC5B5d88393B380Fde02eCE2b0b"; 10 | 11 | module.exports = [ 12 | owners, 13 | numConfirmationsRequired, 14 | testUSDT, 15 | testUSDC, 16 | testDai, 17 | ]; 18 | -------------------------------------------------------------------------------- /src/learning-token/contracts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/learning-token/contracts/.DS_Store -------------------------------------------------------------------------------- /src/learning-token/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", 5 | "@nomicfoundation/hardhat-network-helpers": "^1.0.0", 6 | "@nomicfoundation/hardhat-toolbox": "^2.0.2", 7 | "@nomiclabs/hardhat-ethers": "^2.0.0", 8 | "@nomiclabs/hardhat-etherscan": "^3.0.0", 9 | "@openzeppelin/test-helpers": "^0.5.11", 10 | "@typechain/ethers-v5": "^10.2.1", 11 | "@typechain/hardhat": "^6.1.6", 12 | "@types/jest": "^29.5.3", 13 | "@types/mocha": "^10.0.1", 14 | "hardhat-gas-reporter": "^1.0.9", 15 | "solidity-coverage": "^0.8.5", 16 | "ts-node": "^10.9.1", 17 | "typechain": "^8.3.1", 18 | "typescript": "^5.1.6" 19 | }, 20 | "dependencies": { 21 | "@openzeppelin/contracts": "^4.8.2", 22 | "dotenv": "^16.0.3", 23 | "hardhat": "2.18.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/learning-token/scripts/DeployLive.ts: -------------------------------------------------------------------------------- 1 | /// ------------------------ Deploy to local testnet ---------------------- 2 | 3 | import { ethers } from "hardhat"; 4 | import dotenv from "dotenv"; 5 | 6 | async function main() { 7 | const LearningToken = await ethers.getContractFactory("LearningToken"); 8 | const learningToken = await LearningToken.deploy(); 9 | 10 | console.log(`LearningToken Contract deployed to ${learningToken.address}`); 11 | console.log( 12 | `LearningToken Contract Owner address ${await learningToken.owner()}` 13 | ); 14 | //print the tx hash 15 | console.log(`Tx hash: ${learningToken.deployTransaction.hash}`); 16 | } 17 | 18 | // We recommend this pattern to be able to use async/await everywhere 19 | // and properly handle errors. 20 | main().catch((error) => { 21 | console.error(error); 22 | process.exitCode = 1; 23 | }); 24 | -------------------------------------------------------------------------------- /src/learning-token/scripts/DeployLocalHardhat.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "hardhat"; 2 | import dotenv from "dotenv"; 3 | 4 | async function main() { 5 | type EnvVariables = { 6 | SUPER_ADMIN_PRI_KEY_HARDHATNODE: string; 7 | }; 8 | const { SUPER_ADMIN_PRI_KEY_HARDHATNODE } = process.env as EnvVariables; // Use "as" to cast process.env to the defined type 9 | 10 | const provider = new ethers.providers.JsonRpcProvider( 11 | "http://127.0.0.1:8545" 12 | ); 13 | const superAdminWallet = new ethers.Wallet( 14 | SUPER_ADMIN_PRI_KEY_HARDHATNODE, 15 | provider 16 | ); 17 | const LearningToken = await ethers.getContractFactory("LearningToken"); 18 | const learningToken = await LearningToken.connect(superAdminWallet).deploy(); 19 | console.log(`LearningToken Contract deployed to ${learningToken.address}`); 20 | console.log( 21 | `LearningToken Contract Owner address ${await learningToken.owner()}` 22 | ); 23 | } 24 | 25 | // We recommend this pattern to be able to use async/await everywhere 26 | // and properly handle errors. 27 | main().catch((error) => { 28 | console.error(error); 29 | process.exitCode = 1; 30 | }); 31 | -------------------------------------------------------------------------------- /src/learning-token/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | 5 | # Executes cleanup function at script exit. 6 | trap cleanup EXIT 7 | 8 | cleanup() { 9 | # Kill the Hardhat Network instance that we started (if we started one and if it's still running). 10 | if [ -n "$hardhat_network_pid" ] && ps -p $hardhat_network_pid > /dev/null; then 11 | kill -9 $hardhat_network_pid 12 | fi 13 | } 14 | 15 | hardhat_network_port=8545 16 | 17 | export CI=true 18 | 19 | hardhat_network_running() { 20 | nc -z localhost "$hardhat_network_port" 21 | } 22 | 23 | start_hardhat_network() { 24 | node_modules/.bin/hardhat --version 25 | node_modules/.bin/hardhat node > /dev/null & 26 | hardhat_network_pid=$! 27 | 28 | sleep 1 29 | } 30 | 31 | if hardhat_network_running; then 32 | echo "Using existing Hardhat Network instance" 33 | else 34 | echo "Starting our own Hardhat Network instance" 35 | start_hardhat_network 36 | fi 37 | 38 | ./node_modules/.bin/hardhat test --network localhost -------------------------------------------------------------------------------- /src/learning-token/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "resolveJsonModule": true, 10 | "typeRoots": ["./typings"] 11 | } 12 | } 13 | 14 | // { 15 | // "compilerOptions": { 16 | // "target": "es2020", 17 | // "module": "commonjs", 18 | // "esModuleInterop": true, 19 | // "forceConsistentCasingInFileNames": true, 20 | // "strict": true, 21 | // "skipLibCheck": true, 22 | // "resolveJsonModule": true, 23 | // "typeRoots": ["./typings"] 24 | // } 25 | // } 26 | -------------------------------------------------------------------------------- /src/quorum-test-network/.env: -------------------------------------------------------------------------------- 1 | # This file defines environment variables defaults for Docker-compose 2 | # but we also use it for shell scripts as a sourced file 3 | 4 | BESU_VERSION=23.4.1 5 | QUORUM_VERSION=23.4.0 6 | TESSERA_VERSION=23.4.0 7 | ETHSIGNER_VERSION=22.1.3 8 | QUORUM_EXPLORER_VERSION=4f60191 9 | 10 | LOCK_FILE=.quorumDevQuickstart.lock 11 | 12 | # GoQuorum consensus algorithm 13 | # istanbul, qbft, raft 14 | # !!! lower case ONLY here 15 | GOQUORUM_CONS_ALGO=qbft 16 | 17 | # Besu consensus algorithm 18 | # IBFT, QBFT, CLIQUE 19 | # PLEASE NOTE: IBFT used here refers to IBFT2.0 and not IBFT1.0 More information can be found https://besu.hyperledger.org/en/latest/HowTo/Configure/Consensus-Protocols/IBFT/ 20 | # We use IBFT here to keep the API names consistent 21 | # !!! upper case ONLY here 22 | BESU_CONS_ALGO=QBFT 23 | -------------------------------------------------------------------------------- /src/quorum-test-network/attach.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MEMBER_NUMBER=$1 4 | MEMBER_NODE="member${MEMBER_NUMBER}quorum" 5 | echo "Attempting to connect to $MEMBER_NODE" 6 | if [ -z `docker compose -f docker-compose.yml ps -q ${MEMBER_NODE} 2>/dev/null` ] ; then 7 | echo "$MEMBER_NUMBER is not a valid member node. Must be between 1 and 3" >&2 8 | exit 1 9 | fi 10 | 11 | # can also do geth attach http://localhost:8545 12 | docker compose exec ${MEMBER_NODE} /bin/sh -c "geth attach /data/geth.ipc" 13 | -------------------------------------------------------------------------------- /src/quorum-test-network/chainlens/nginx.conf: -------------------------------------------------------------------------------- 1 | events { } 2 | 3 | http { 4 | server { 5 | listen 80; 6 | charset utf-8; 7 | 8 | location /api/ { 9 | proxy_pass http://chainlensapi:8090/; 10 | } 11 | 12 | location / { 13 | proxy_pass http://chainlensweb:3000/; 14 | } 15 | 16 | error_page 500 502 503 504 /5xx.html; 17 | location /5xx.html { 18 | root /www/error_pages/; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/besu/.env: -------------------------------------------------------------------------------- 1 | 2 | # OpenTelemetry metrics 3 | BESU_METRICS_ENABLED=true 4 | BESU_METRICS_PROTOCOL=opentelemetry 5 | OTEL_EXPORTER_OTLP_METRIC_ENDPOINT=otelcollector:55680 6 | OTEL_EXPORTER_OTLP_SPAN_ENDPOINT=otelcollector:55680 7 | OTEL_EXPORTER_OTLP_METRIC_INSECURE=true 8 | OTEL_EXPORTER_OTLP_SPAN_INSECURE=true 9 | # Splunk logging configuration 10 | BESU_LOGGING=info 11 | LOGGER=Splunk 12 | SPLUNK_URL=https://splunk:8088/ 13 | SPLUNK_INDEX=logs 14 | SPLUNK_TOKEN=11111111-1111-1111-1111-1111111111113 15 | SPLUNK_SKIPTLSVERIFY=true 16 | LOG4J_CONFIGURATION_FILE=/config/log-config-splunk.xml 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/besu/config.toml: -------------------------------------------------------------------------------- 1 | 2 | genesis-file="/config/genesis.json" 3 | node-private-key-file="/opt/besu/keys/nodekey" 4 | logging="INFO" 5 | data-path="/opt/besu/data" 6 | host-allowlist=["*"] 7 | min-gas-price=0 8 | 9 | # rpc 10 | rpc-http-enabled=true 11 | rpc-http-host="0.0.0.0" 12 | rpc-http-port=8545 13 | rpc-http-cors-origins=["*"] 14 | 15 | # ws 16 | rpc-ws-enabled=true 17 | rpc-ws-host="0.0.0.0" 18 | rpc-ws-port=8546 19 | 20 | # graphql 21 | graphql-http-enabled=true 22 | graphql-http-host="0.0.0.0" 23 | graphql-http-port=8547 24 | graphql-http-cors-origins=["*"] 25 | 26 | # metrics 27 | metrics-enabled=true 28 | metrics-host="0.0.0.0" 29 | metrics-port=9545 30 | 31 | # permissions 32 | permissions-nodes-config-file-enabled=true 33 | permissions-nodes-config-file="/config/permissions_config.toml" 34 | 35 | # bootnodes 36 | bootnodes=["enode://8208a3f344695d44e9cf2c023683cbea7b9343e2f70a5e804bd2c93858e945f8f91439eef96a4ab6c47ff06637d6fbe6472f96de1655a1bee57ea896654f3a22@172.16.239.11:30303"] 37 | 38 | 39 | # Discovery at boot is set to a list of static files, but will also discover new nodes should they be added 40 | # static nodes 41 | static-nodes-file="/config/static-nodes.json" 42 | discovery-enabled=true 43 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/besu/log-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | INFO 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/besu/permissions_config.toml: -------------------------------------------------------------------------------- 1 | nodes-allowlist=[ 2 | "enode://8208a3f344695d44e9cf2c023683cbea7b9343e2f70a5e804bd2c93858e945f8f91439eef96a4ab6c47ff06637d6fbe6472f96de1655a1bee57ea896654f3a22@172.16.239.11:30303", 3 | "enode://b9050e002aa42464e6b07c811a1f9dfec01249af03f67b753e8415420649b184447bb2a784863ccbf327ad9e31aaba803464979dfe6a7facc669151a5fa6ad1b@172.16.239.12:30303", 4 | "enode://59cf0c623c582fa9b19bdf70fb6bade07f4ae32218dd4d1c7e2c7e65acf87da45cf2ab55d16d27360aafef17622c37c09db60d7680ebcc17b78867f4c05bcaa4@172.16.239.13:30303", 5 | "enode://2fd5b5b6ad529f55b71602026d1849d0036f06482368b5812fa793014195d3571b0840dbc4175617de2a12db8f1222c012420d471ae5c0d982118625cae58868@172.16.239.14:30303", 6 | "enode://86fcc16f4730fbfd238dc17ea552854c0943923bb1d5e886e5601b8d884fb0519060e0023f495dd24ffe60a65660fb7fdcdebfceedd2b3673dfa63658825924b@172.16.239.15:30303", 7 | "enode://98496800174b3c73ae33cba59f8f5e686cd488f7897c2edb52e2cf46383d75cd03dbb58dde07185bc0953f98800ca9a89f4b5ef450c5e51292ea08ec6130ee0c@172.16.239.16:30303", 8 | "enode://ad2c79c6561bc8212c2e8382611c62e406e767d1f3106c68ca206900f575cb8ba9a8be111c645cd9803701d684454c782c40d2361b000a32ed03d26228b30ec1@172.16.239.17:30303", 9 | "enode://af19c92deb635bd7720634de9b2e7908208530d6f5e96eee003a8f1799e5be4037957d7e2fdbe3605e3a38dab05c961679c02133a0e624e23a72f7961e8af6ac@172.16.239.18:30303" 10 | ] 11 | 12 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/besu/static-nodes.json: -------------------------------------------------------------------------------- 1 | [ 2 | "enode://8208a3f344695d44e9cf2c023683cbea7b9343e2f70a5e804bd2c93858e945f8f91439eef96a4ab6c47ff06637d6fbe6472f96de1655a1bee57ea896654f3a22@172.16.239.11:30303", 3 | "enode://b9050e002aa42464e6b07c811a1f9dfec01249af03f67b753e8415420649b184447bb2a784863ccbf327ad9e31aaba803464979dfe6a7facc669151a5fa6ad1b@172.16.239.12:30303", 4 | "enode://59cf0c623c582fa9b19bdf70fb6bade07f4ae32218dd4d1c7e2c7e65acf87da45cf2ab55d16d27360aafef17622c37c09db60d7680ebcc17b78867f4c05bcaa4@172.16.239.13:30303", 5 | "enode://2fd5b5b6ad529f55b71602026d1849d0036f06482368b5812fa793014195d3571b0840dbc4175617de2a12db8f1222c012420d471ae5c0d982118625cae58868@172.16.239.14:30303", 6 | "enode://86fcc16f4730fbfd238dc17ea552854c0943923bb1d5e886e5601b8d884fb0519060e0023f495dd24ffe60a65660fb7fdcdebfceedd2b3673dfa63658825924b@172.16.239.15:30303", 7 | "enode://98496800174b3c73ae33cba59f8f5e686cd488f7897c2edb52e2cf46383d75cd03dbb58dde07185bc0953f98800ca9a89f4b5ef450c5e51292ea08ec6130ee0c@172.16.239.16:30303", 8 | "enode://ad2c79c6561bc8212c2e8382611c62e406e767d1f3106c68ca206900f575cb8ba9a8be111c645cd9803701d684454c782c40d2361b000a32ed03d26228b30ec1@172.16.239.17:30303", 9 | "enode://af19c92deb635bd7720634de9b2e7908208530d6f5e96eee003a8f1799e5be4037957d7e2fdbe3605e3a38dab05c961679c02133a0e624e23a72f7961e8af6ac@172.16.239.18:30303" 10 | ] 11 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/ethsigner/createKey.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3') 2 | 3 | // Web3 initialization (should point to the JSON-RPC endpoint) 4 | const web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:8545')) 5 | 6 | var V3KeyStore = web3.eth.accounts.encrypt("797bbe0373132e8c5483515b68ecbb6d3581b56f0205b653ad2b30a559e83891", "Password1"); 7 | console.log(JSON.stringify(V3KeyStore)); 8 | process.exit(); 9 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/ethsigner/key: -------------------------------------------------------------------------------- 1 | {"version":3,"id":"0e3d044a-26b4-429f-a5d3-def4a62a77ec","address":"9b790656b9ec0db1936ed84b3bea605873558198","crypto":{"ciphertext":"4d34be50618c36fb57349a8a7dc7b0c46f7c6883c817087863ff4f1fbc957582","cipherparams":{"iv":"723a6a815dcaf255ebd1da1bfb14e1b8"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"3d04a3f225d3d5874388484730a30d45627399d69721a7c7fb653f8e0e90a67b","n":8192,"r":8,"p":1},"mac":"5c04e705196b35abace4da61700921d7762dba782ed68a4cd9917dd75badaacb"}} -------------------------------------------------------------------------------- /src/quorum-test-network/config/ethsigner/password: -------------------------------------------------------------------------------- 1 | Password1 -------------------------------------------------------------------------------- /src/quorum-test-network/config/grafana/provisioning/dashboards/dashboard.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: 1 3 | 4 | providers: 5 | - name: 'Prometheus' 6 | orgId: 1 7 | folder: '' 8 | type: file 9 | disableDeletion: false 10 | editable: true 11 | options: 12 | path: /etc/grafana/provisioning/dashboards 13 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/grafana/provisioning/datasources/loki.yml: -------------------------------------------------------------------------------- 1 | # config file version 2 | apiVersion: 1 3 | 4 | # list of datasources that should be deleted from the database 5 | deleteDatasources: 6 | - name: Graphite 7 | orgId: 1 8 | 9 | # list of datasources to insert/update depending 10 | # what's available in the database 11 | datasources: 12 | # name of the datasource. Required 13 | - name: Loki 14 | # datasource type. Required 15 | type: loki 16 | # access mode. proxy or direct (Server or Browser in the UI). Required 17 | access: proxy 18 | # org id. will default to orgId 1 if not specified 19 | orgId: 1 20 | # url 21 | url: http://loki:3100/ 22 | # Deprecated, use secureJsonData.password 23 | password: 24 | # database user, if used 25 | user: 26 | # database name, if used 27 | database: 28 | # enable/disable basic auth 29 | basicAuth: 30 | # basic auth username 31 | basicAuthUser: 32 | # Deprecated, use secureJsonData.basicAuthPassword 33 | basicAuthPassword: 34 | # enable/disable with credentials headers 35 | withCredentials: 36 | # mark as default datasource. Max one per org 37 | isDefault: false 38 | # fields that will be converted to json and stored in jsonData 39 | jsonData: 40 | graphiteVersion: "1.1" 41 | tlsAuth: false 42 | tlsAuthWithCACert: false 43 | # json object of data that will be encrypted. 44 | secureJsonData: 45 | tlsCACert: "..." 46 | tlsClientCert: "..." 47 | tlsClientKey: "..." 48 | # database password, if used 49 | password: 50 | # basic auth password 51 | basicAuthPassword: 52 | version: 1 53 | # allow users to edit datasources from the UI. 54 | editable: true 55 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member1/accountKeystore: -------------------------------------------------------------------------------- 1 | {"address":"f0e2db6c8dc6c681bb5d6ad121a107f300e9b2b5","crypto":{"cipher":"aes-128-ctr","ciphertext":"f2af258ee3733513333652be19197ae7eace4b5e79a346cf25b02a857e6043f3","cipherparams":{"iv":"587d7faaa6403b8a73273d0ad58dd71f"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b93c7d69c5bb0a760c3b7fdf791c47896a552c5c977648b392a24d708674dcf3"},"mac":"d83bcb555c92fc5a32ceacabbb6b99f59515ec3986b9fe5995c67e027bd750c8"},"id":"5392d73f-08dd-42b8-bca9-6f6d35c419d9","version":3} 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member1/accountPassword: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/config/nodes/member1/accountPassword -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member1/accountPrivateKey: -------------------------------------------------------------------------------- 1 | 0x8bbbb1b345af56b560a5b20bd4b0ed1cd8cc9958a16262bc75118453cb546df7 -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member1/address: -------------------------------------------------------------------------------- 1 | 0x13a52aab892e1322e8b52506276363d4754c122e 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member1/nodekey: -------------------------------------------------------------------------------- 1 | b9a4bd1539c15bcc83fa9078fe89200b6e9e802ae992f13cd83c853f16e8bed4 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member1/nodekey.pub: -------------------------------------------------------------------------------- 1 | 98496800174b3c73ae33cba59f8f5e686cd488f7897c2edb52e2cf46383d75cd03dbb58dde07185bc0953f98800ca9a89f4b5ef450c5e51292ea08ec6130ee0c 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member1/tm.key: -------------------------------------------------------------------------------- 1 | {"data":{"bytes":"Wl+xSyXVuuqzpvznOS7dOobhcn4C5auxkFRi7yLtgtA="},"type":"unlocked"} -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member1/tm.pub: -------------------------------------------------------------------------------- 1 | BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo= -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member1/tma.key: -------------------------------------------------------------------------------- 1 | {"data":{"bytes":"wGEar7J9G0JAgdisp61ZChyrJWeW2QPyKvecjjeVHOY="},"type":"unlocked"} -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member1/tma.pub: -------------------------------------------------------------------------------- 1 | 8SjRHlUBe4hAmTk3KDeJ96RhN+s10xRrHDrxEi1O5W0= -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member2/accountKeystore: -------------------------------------------------------------------------------- 1 | {"address":"ca843569e3427144cead5e4d5999a3d0ccf92b8e","crypto":{"cipher":"aes-128-ctr","ciphertext":"01d409941ce57b83a18597058033657182ffb10ae15d7d0906b8a8c04c8d1e3a","cipherparams":{"iv":"0bfb6eadbe0ab7ffaac7e1be285fb4e5"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"7b90f455a95942c7c682e0ef080afc2b494ef71e749ba5b384700ecbe6f4a1bf"},"mac":"4cc851f9349972f851d03d75a96383a37557f7c0055763c673e922de55e9e307"},"id":"354e3b35-1fed-407d-a358-889a29111211","version":3} -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member2/accountPassword: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/config/nodes/member2/accountPassword -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member2/accountPrivateKey: -------------------------------------------------------------------------------- 1 | 0x4762e04d10832808a0aebdaa79c12de54afbe006bfffd228b3abcc494fe986f9 -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member2/address: -------------------------------------------------------------------------------- 1 | 0xe090a28b8a9d0a69ec259cb745036d5d1030e3ea 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member2/nodekey: -------------------------------------------------------------------------------- 1 | f18166704e19b895c1e2698ebc82b4e007e6d2933f4b31be23662dd0ec602570 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member2/nodekey.pub: -------------------------------------------------------------------------------- 1 | ad2c79c6561bc8212c2e8382611c62e406e767d1f3106c68ca206900f575cb8ba9a8be111c645cd9803701d684454c782c40d2361b000a32ed03d26228b30ec1 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member2/tm.key: -------------------------------------------------------------------------------- 1 | {"data":{"bytes":"nDFwJNHSiT1gNzKBy9WJvMhmYRkW3TzFUmPsNzR6oFk="},"type":"unlocked"} -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member2/tm.pub: -------------------------------------------------------------------------------- 1 | QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc= -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member2/tma.key: -------------------------------------------------------------------------------- 1 | {"data":{"bytes":"rwfJC1kNa8BjPfc+zZXug+it9sdWa0vbdN6pp6IXlAs="},"type":"unlocked"} -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member2/tma.pub: -------------------------------------------------------------------------------- 1 | 2T7xkjblN568N1QmPeElTjoeoNT4tkWYOJYxSMDO5i0= -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member3/accountKeystore: -------------------------------------------------------------------------------- 1 | {"address":"0fbdc686b912d7722dc86510934589e0aaf3b55a","crypto":{"cipher":"aes-128-ctr","ciphertext":"6b2c72c6793f3da8185e36536e02f574805e41c18f551f24b58346ef4ecf3640","cipherparams":{"iv":"582f27a739f39580410faa108d5cc59f"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"1a79b0db3f8cb5c2ae4fa6ccb2b5917ce446bd5e42c8d61faeee512b97b4ad4a"},"mac":"cecb44d2797d6946805d5d744ff803805477195fab1d2209eddc3d1158f2e403"},"id":"f7292e90-af71-49af-a5b3-40e8493f4681","version":3} -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member3/accountPassword: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/config/nodes/member3/accountPassword -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member3/accountPrivateKey: -------------------------------------------------------------------------------- 1 | 0x61dced5af778942996880120b303fc11ee28cc8e5036d2fdff619b5675ded3f0 -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member3/address: -------------------------------------------------------------------------------- 1 | 0x401bdfcd9221cd790e7cd66eece303ed4d4b53b1 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member3/nodekey: -------------------------------------------------------------------------------- 1 | 4107f0b6bf67a3bc679a15fe36f640415cf4da6a4820affaac89c8b280dfd1b3 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member3/nodekey.pub: -------------------------------------------------------------------------------- 1 | af19c92deb635bd7720634de9b2e7908208530d6f5e96eee003a8f1799e5be4037957d7e2fdbe3605e3a38dab05c961679c02133a0e624e23a72f7961e8af6ac 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member3/tm.key: -------------------------------------------------------------------------------- 1 | {"data":{"bytes":"tMxUVR8bX7aq/TbpVHc2QV3SN2iUuExBwefAuFsO0Lg="},"type":"unlocked"} -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member3/tm.pub: -------------------------------------------------------------------------------- 1 | 1iTZde/ndBHvzhcl7V68x44Vx7pl8nwx9LqnM/AfJUg= -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member3/tma.key: -------------------------------------------------------------------------------- 1 | {"data":{"bytes":"yLcbICXicELZOnvpkDXB2UkQUiNAMIfsEOsgtFOGkQU="},"type":"unlocked"} -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/member3/tma.pub: -------------------------------------------------------------------------------- 1 | 3nLS1GSlPs3/AccoZ20WTBrYP/ua5KDlUM1uGrDKHTs= -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/rpcnode/accountKeystore: -------------------------------------------------------------------------------- 1 | {"address":"c9c913c8c3c1cd416d80a0abf475db2062f161f6","crypto":{"cipher":"aes-128-ctr","ciphertext":"ce8e51e64e9f053414616c62b3924536f3f9144638359e2e2eb00e04ad095b0a","cipherparams":{"iv":"648343bce02b158eda9bb2074f8dc601"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0982402da973d8176315aeae4415b328a7ce4393e217a0c4f45385f1cee9bc3e"},"mac":"5707caff457f930655849293dc1101e13ab32b175fdf5538869a2a3ffc716d8b"},"id":"8d031b90-ab7f-48dc-9b7a-ce41abd7f9c8","version":3} 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/rpcnode/accountPassword: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/config/nodes/rpcnode/accountPassword -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/rpcnode/accountPrivateKey: -------------------------------------------------------------------------------- 1 | 0x60bbe10a196a4e71451c0f6e9ec9beab454c2a5ac0542aa5b8b733ff5719fec3 -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/rpcnode/address: -------------------------------------------------------------------------------- 1 | 0xdf8b560be949c229c821731554c33ead5e3888a4 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/rpcnode/nodekey: -------------------------------------------------------------------------------- 1 | 0e93a540518eeb673d94fb496b746008ab56605463cb9212493997f5755124d1 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/rpcnode/nodekey.pub: -------------------------------------------------------------------------------- 1 | 86fcc16f4730fbfd238dc17ea552854c0943923bb1d5e886e5601b8d884fb0519060e0023f495dd24ffe60a65660fb7fdcdebfceedd2b3673dfa63658825924b 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator1/accountKeystore: -------------------------------------------------------------------------------- 1 | {"address":"ed9d02e382b34818e88b88a309c7fe71e65f419d","crypto":{"cipher":"aes-128-ctr","ciphertext":"4e77046ba3f699e744acb4a89c36a3ea1158a1bd90a076d36675f4c883864377","cipherparams":{"iv":"a8932af2a3c0225ee8e872bc0e462c11"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"8ca49552b3e92f79c51f2cd3d38dfc723412c212e702bd337a3724e8937aff0f"},"mac":"6d1354fef5aa0418389b1a5d1f5ee0050d7273292a1171c51fd02f9ecff55264"},"id":"a65d1ac3-db7e-445d-a1cc-b6c5eeaa05e0","version":3} -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator1/accountPassword: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/config/nodes/validator1/accountPassword -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator1/accountPrivateKey: -------------------------------------------------------------------------------- 1 | 0xe6181caaffff94a09d7e332fc8da9884d99902c7874eb74354bdcadf411929f1 -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator1/address: -------------------------------------------------------------------------------- 1 | 0x93917cadbace5dfce132b991732c6cda9bcc5b8a 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator1/nodekey: -------------------------------------------------------------------------------- 1 | 1a2c4ff0f1b38e2322658dba692816138eb22d002515df1fffca21278f406aa9 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator1/nodekey.pub: -------------------------------------------------------------------------------- 1 | 8208a3f344695d44e9cf2c023683cbea7b9343e2f70a5e804bd2c93858e945f8f91439eef96a4ab6c47ff06637d6fbe6472f96de1655a1bee57ea896654f3a22 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator2/accountKeystore: -------------------------------------------------------------------------------- 1 | {"address":"b30f304642de3fee4365ed5cd06ea2e69d3fd0ca","crypto":{"cipher":"aes-128-ctr","ciphertext":"cf7f44a86510c497f2a6727f62b8e89c8cd42dbfd8e3377658d659c776c75f30","cipherparams":{"iv":"5d320e3072939817faa2caefdb810239"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e637b069dacfe77f3a495d8a0d3735544e73973c03e107976545df78e6f04289"},"mac":"e20c97b8ee7d54072b9cfac201d52ef360ecacdbd1f7187e7547b3cd9be00599"},"id":"5bf73d6b-340b-4e9f-a7f3-f9ab41f39726","version":3} 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator2/accountPassword: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/config/nodes/validator2/accountPassword -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator2/accountPrivateKey: -------------------------------------------------------------------------------- 1 | 0x5ad8b28507578c429dfa9f178d7f742f4861716ee956eb75648a7dbc5ffe915d -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator2/address: -------------------------------------------------------------------------------- 1 | 0x27a97c9aaf04f18f3014c32e036dd0ac76da5f18 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator2/nodekey: -------------------------------------------------------------------------------- 1 | 7f9af699dd2bb1af76c90b3f67183dd48abae509c315eb8f2c55301ad90ba978 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator2/nodekey.pub: -------------------------------------------------------------------------------- 1 | b9050e002aa42464e6b07c811a1f9dfec01249af03f67b753e8415420649b184447bb2a784863ccbf327ad9e31aaba803464979dfe6a7facc669151a5fa6ad1b 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator3/accountKeystore: -------------------------------------------------------------------------------- 1 | {"address":"0886328869e4e1f401e1052a5f4aae8b45f42610","crypto":{"cipher":"aes-128-ctr","ciphertext":"6e0e228b810a88f2cea85c439b005a92bba6220de8cd6ba73a8f7ecd681fde09","cipherparams":{"iv":"5264c2defa48f7f9fa103899acaea021"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"15ef956dab453387ddf7afd6775f3727fb560a77028b5a14d774c3bfff17f101"},"mac":"6ca1d88defee18378789d191ca7b32bbecbd6dd5a6c39427ed45b13c9595edc3"},"id":"734d1189-4e1e-44bf-854a-642485532715","version":3} 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator3/accountPassword: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/config/nodes/validator3/accountPassword -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator3/accountPrivateKey: -------------------------------------------------------------------------------- 1 | 0xf23f92ed543046498d7616807b18a8f304855cb644df25bc7d0b0b37d8a66019 -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator3/address: -------------------------------------------------------------------------------- 1 | 0xce412f988377e31f4d0ff12d74df73b51c42d0ca 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator3/nodekey: -------------------------------------------------------------------------------- 1 | fe006b00c738e7e5af7f7623290ffc83f394741ae6fb6afc6081cab49e1e1a70 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator3/nodekey.pub: -------------------------------------------------------------------------------- 1 | 59cf0c623c582fa9b19bdf70fb6bade07f4ae32218dd4d1c7e2c7e65acf87da45cf2ab55d16d27360aafef17622c37c09db60d7680ebcc17b78867f4c05bcaa4 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator4/accountKeystore: -------------------------------------------------------------------------------- 1 | {"address":"f48de4a0c2939e62891f3c6aca68982975477e45","crypto":{"cipher":"aes-128-ctr","ciphertext":"402a2d8eb1ff6bab713ddb81f68142c4f0113d32e9f0cc8969347a4945cd1e5f","cipherparams":{"iv":"a1f708815212854c0c49081869198dd5"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a24d95de8680d8d214ae5e9060e919eb563ce513bf63021497e0d218ed68f89d"},"mac":"571164da79472f210caeb45af2b9715fb22eef8d485ce5c6a4e0c52865398ea7"},"id":"d5723032-0a81-46ec-ac34-9d8362e2250c","version":3} 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator4/accountPassword: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/config/nodes/validator4/accountPassword -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator4/accountPrivateKey: -------------------------------------------------------------------------------- 1 | 0x7f012b2a11fc651c9a73ac13f0a298d89186c23c2c9a0e83206ad6e274ba3fc7 -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator4/address: -------------------------------------------------------------------------------- 1 | 0x98c1334496614aed49d2e81526d089f7264fed9c 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator4/nodekey: -------------------------------------------------------------------------------- 1 | 8f6ae009cdbbf6e6fa739b91a4483f251bbe89f6570d34856554533b36c93c55 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/nodes/validator4/nodekey.pub: -------------------------------------------------------------------------------- 1 | 2fd5b5b6ad529f55b71602026d1849d0036f06482368b5812fa793014195d3571b0840dbc4175617de2a12db8f1222c012420d471ae5c0d982118625cae58868 2 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/tessera/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG TESSERA_VERSION=latest 2 | 3 | FROM quorumengineering/tessera:${TESSERA_VERSION} 4 | 5 | # develop uses a debain container, all releases use an alpine container - this allows both to be used for the quickstart 6 | # set the version in ../../.env 7 | RUN if [ -e /sbin/apk ] ; then apk add gettext --no-cache ; else apt-get update && apt-get install -y gettext && rm -rf /var/lib/apt/lists/* ; fi 8 | 9 | ENV JAVA_OPTS="-Dlogback.configurationFile=/data/logback.xml" 10 | 11 | COPY docker-entrypoint.sh /usr/bin/ 12 | COPY data data 13 | 14 | ENTRYPOINT ["docker-entrypoint.sh"] 15 | 16 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/tessera/data/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {"timestamp":"%d{ISO8601}","container":"${hostName}","level":"%level","thread":"%thread","logger":"%logger{36}","message":"%replace(%replace(%msg){'[\r\n]',''}){'"','\\"'}","throwable":"%replace(%replace(%throwable){'[\r\n]',''}){'"','\\"'}"}%n 9 | 10 | 11 | 12 | 13 | /var/log/tessera/tessera-${HOSTNAME}.log 14 | true 15 | true 16 | 17 | {"timestamp":"%d{ISO8601}","container":"${hostName}","level":"%level","thread":"%thread","class":"%c{1}","logger":"%logger{36}","message":"%replace(%msg){'[\r\n]', ''}","throwable":"%replace(%replace(%throwable){'[\r\n]',''}){'"','\\"'}"}%n 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/quorum-test-network/config/tessera/data/tessera-config-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "mode": "${TESSERA_MODE}", 3 | "useWhiteList": false, 4 | "jdbc": { 5 | "username": "sa", 6 | "password": "", 7 | "url": "jdbc:h2:./data/tm/db;MODE=Oracle;TRACE_LEVEL_SYSTEM_OUT=0", 8 | "autoCreateTables": true 9 | }, 10 | "serverConfigs": [ 11 | { 12 | "app": "ThirdParty", 13 | "enabled": true, 14 | "serverAddress": "http://${HOSTNAME}:9080", 15 | "communicationType": "REST" 16 | }, 17 | { 18 | "app": "Q2T", 19 | "enabled": true, 20 | "serverAddress": "http://${HOSTNAME}:9101", 21 | "sslConfig": { 22 | "tls": "OFF" 23 | }, 24 | "communicationType": "REST" 25 | }, 26 | { 27 | "app": "P2P", 28 | "enabled": true, 29 | "serverAddress": "http://${HOSTNAME}:9000", 30 | "sslConfig": { 31 | "tls": "OFF" 32 | }, 33 | "communicationType": "REST" 34 | } 35 | ], 36 | "peer": [ 37 | { 38 | "url": "http://member1tessera:9000" 39 | }, 40 | { 41 | "url": "http://member2tessera:9000" 42 | }, 43 | { 44 | "url": "http://member3tessera:9000" 45 | } 46 | ], 47 | "keys": { 48 | "passwords": [], 49 | "keyData": [ 50 | { 51 | "privateKeyPath": "/config/keys/tm.key", 52 | "publicKeyPath": "/config/keys/tm.pub" 53 | } 54 | ] 55 | }, 56 | "alwaysSendTo": [], 57 | "bootstrapNode": false, 58 | "features": { 59 | "enableRemoteKeyValidation": false, 60 | "enablePrivacyEnhancements": true 61 | } 62 | } -------------------------------------------------------------------------------- /src/quorum-test-network/config/tessera/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir -p /var/log/tessera/; 4 | mkdir -p /data/tm/; 5 | 6 | envsubst < /data/tessera-config-template.json > /data/tessera-config.json 7 | 8 | cat /data/tessera-config.json 9 | 10 | exec /tessera/bin/tessera \ 11 | -configfile /data/tessera-config.json 12 | 13 | -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/contracts/QuorumToken.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: Unlicense 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract QuorumToken is ERC20 { 7 | constructor(uint256 initialSupply) 8 | ERC20("QuorumToken", "QT") 9 | { 10 | _mint(msg.sender, initialSupply); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webapp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev -p 3001", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@chakra-ui/react": "^2.8.0", 13 | "@emotion/react": "^11.11.1", 14 | "@emotion/styled": "^11.11.0", 15 | "ethers": "6.7.1", 16 | "framer-motion": "^10.16.1", 17 | "next": "13.4.19", 18 | "react": "18.2.0", 19 | "react-dom": "18.2.0" 20 | }, 21 | "devDependencies": { 22 | "@types/node": "20.5.4", 23 | "@types/react": "18.2.21", 24 | "@types/react-dom": "18.2.7", 25 | "eslint": "8.47.0", 26 | "eslint-config-next": "13.4.19", 27 | "typescript": "5.1.6" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/src/components/Layout.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react' 2 | import { Container, Flex, useColorModeValue, Spacer, Heading, Center, Text } from '@chakra-ui/react' 3 | 4 | interface LayoutProps { 5 | children: React.ReactNode; 6 | } 7 | 8 | export default function Layout({ children }: LayoutProps) { 9 | return ( 10 |
11 | 12 | 13 | Quorum Quickstart DApp 14 | 15 | 16 | 17 | 18 | {children} 19 | 20 | 21 |
22 | © {new Date().getFullYear()} ConsenSys Software, Inc. All rights reserved. 23 |
24 | 25 |
26 | ) 27 | } -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/src/components/MMAccount.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React, {useEffect, useState } from 'react'; 3 | import { Heading, Text, VStack, Box, Button, Input, Spacer, Flex } from '@chakra-ui/react' 4 | 5 | interface MMAccountProps { 6 | balance: string | undefined, 7 | chainId: number | undefined 8 | erc20ContractAddress: string 9 | deployedAddressHandler: any 10 | } 11 | 12 | export default function MMAccount(props:MMAccountProps){ 13 | 14 | return ( 15 | 16 | Account 17 | Details of the account connected to Metamask 18 | Balance of current account (ETH): {props.balance} 19 | ChainId: {props.chainId} 20 | {/* todo: fix formatting here */} 21 | Address that the QuorumToken was deployed to: 22 | 23 | 24 | ) 25 | } -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/src/components/quorumToken/QuorumTokenABI.tsx: -------------------------------------------------------------------------------- 1 | // In order to interact with a contract from js, we need the contract's ABI 2 | // Im using a human readable format here, but you can just as easily use the compiled output from HardHat 3 | 4 | export const QuorumTokenABI = [ 5 | // Read-Only Functions 6 | "function balanceOf(address owner) view returns (uint256)", 7 | "function totalSupply() view returns (uint256)", 8 | "function decimals() view returns (uint8)", 9 | "function symbol() view returns (string)", 10 | // Authenticated Functions 11 | "function transfer(address to, uint amount) returns (bool)", 12 | // Events 13 | "event Transfer(address indexed from, address indexed to, uint amount)" 14 | ]; -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | 2 | import type { AppProps } from "next/app"; 3 | import { ChakraProvider } from "@chakra-ui/react"; 4 | import "../../styles/globals.css"; 5 | import Layout from '../components/Layout'; 6 | 7 | function MyApp({ Component, pageProps, router }: AppProps) { 8 | 9 | return ( 10 | 11 | Quorum Quickstart DApp 12 | 13 | 14 | 15 | 16 | ) 17 | } 18 | 19 | export default MyApp; 20 | -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/src/pages/_document.js: -------------------------------------------------------------------------------- 1 | import { ColorModeScript } from "@chakra-ui/react"; 2 | import NextDocument, { Html, Head, Main, NextScript } from "next/document"; 3 | 4 | export default class Document extends NextDocument { 5 | render() { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/styles/globals.css: -------------------------------------------------------------------------------- 1 | :root, 2 | body { 3 | height: 100%; 4 | margin: 0; 5 | padding: 0; 6 | width: 100%; 7 | } 8 | 9 | #__next { 10 | display: flex; 11 | flex: 1; 12 | flex-direction: column; 13 | height: 100%; 14 | width: 100%; 15 | } 16 | 17 | main { 18 | display: flex; 19 | flex: 1; 20 | flex-direction: column; 21 | } -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "baseUrl": "./src" 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | // https://hardhat.org/hardhat-runner/docs/config 2 | import { HardhatUserConfig } from "hardhat/config"; 3 | import "@nomicfoundation/hardhat-toolbox"; 4 | 5 | module.exports = { 6 | networks: { 7 | // in built test network to use when developing contracts 8 | hardhat: { 9 | chainId: 1337 10 | }, 11 | quickstart: { 12 | url: "http://127.0.0.1:8545", 13 | chainId: 1337, 14 | // test accounts only, all good ;) 15 | accounts: [ 16 | "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 17 | "0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3", 18 | "0xae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f" 19 | ] 20 | } 21 | }, 22 | defaultNetwork: "hardhat", 23 | solidity: { 24 | version: "0.8.19", 25 | settings: { 26 | optimizer: { 27 | enabled: true, 28 | runs: 200 29 | } 30 | } 31 | }, 32 | paths: { 33 | sources: "./contracts", 34 | tests: "./test", 35 | cache: "./cache", 36 | artifacts: "./artifacts" 37 | }, 38 | mocha: { 39 | timeout: 40000 40 | } 41 | } -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quorumToken", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "compile": "npx hardhat compile", 8 | "test": "npx hardhat test", 9 | "deploy-quorumtoken": "npx hardhat run ./scripts/deploy_quorumtoken.ts --network quickstart " 10 | }, 11 | "dependencies": { 12 | "@openzeppelin/contracts": "^4.9.3", 13 | "hardhat": "^2.17.1" 14 | }, 15 | "devDependencies": { 16 | "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", 17 | "@nomicfoundation/hardhat-ethers": "^3.0.0", 18 | "@nomicfoundation/hardhat-network-helpers": "^1.0.0", 19 | "@nomicfoundation/hardhat-toolbox": "^3.0.0", 20 | "@nomicfoundation/hardhat-verify": "^1.0.0", 21 | "@typechain/ethers-v6": "^0.4.0", 22 | "@typechain/hardhat": "^8.0.0", 23 | "@types/chai": "^4.2.0", 24 | "@types/mocha": ">=9.1.0", 25 | "@types/node": ">=16.0.0", 26 | "chai": "^4.2.0", 27 | "ethers": "6.7.1", 28 | "hardhat-gas-reporter": "^1.0.8", 29 | "solidity-coverage": "^0.8.0", 30 | "ts-node": ">=8.0.0", 31 | "typechain": "^8.1.0", 32 | "typescript": ">=4.5.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/scripts/deploy_quorumtoken.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "hardhat" 2 | 3 | async function main() { 4 | const initialSupply = ethers.parseEther('10000.0') 5 | const QuorumToken = await ethers.getContractFactory("QuorumToken") 6 | const deploy = await QuorumToken.deploy(initialSupply) 7 | console.log("Contract deploy at: %s", await deploy.getAddress()); 8 | } 9 | 10 | // We recommend this pattern to be able to use async/await everywhere 11 | // and properly handle errors. 12 | main().catch((error) => { 13 | console.error(error) 14 | process.exitCode = 1 15 | }) -------------------------------------------------------------------------------- /src/quorum-test-network/dapps/quorumToken/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "resolveJsonModule": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/quorum-test-network/extra/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@consensys-software/generate_node_details", 3 | "version": "1.0.0", 4 | "description": "Example script to create nodekeys and address for a Quorum (Besu or GoQuorum) node", 5 | "scripts": {}, 6 | "license": "Apache-2.0", 7 | "dependencies": { 8 | "secp256k1": "^4.0.0", 9 | "keccak": "^3.0.0", 10 | "ethereumjs-wallet": "^1.0.2", 11 | "yargs": "^17.2.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/quorum-test-network/filebeat/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.elastic.co/beats/filebeat:7.14.1 2 | ENV ENV_NAME dev 3 | ENV IP_ADDRESS "127.0.0.1" 4 | ENV REDIS_HOST localhost 5 | ENV REDIS_PORT 6379 6 | 7 | USER root 8 | ADD ./filebeat.yml /usr/share/filebeat/filebeat.yml 9 | RUN chown root:filebeat /usr/share/filebeat/filebeat.yml && chmod go-w /usr/share/filebeat/filebeat.yml 10 | USER filebeat 11 | 12 | CMD ["filebeat", "-c", "filebeat.yml"] 13 | -------------------------------------------------------------------------------- /src/quorum-test-network/filebeat/filebeat.yml: -------------------------------------------------------------------------------- 1 | 2 | filebeat.modules: 3 | 4 | # List of inputs to fetch data. 5 | filebeat.inputs: 6 | - paths: 7 | - "/var/log/logstash/logstash-*.log" 8 | type: log 9 | enabled: true 10 | document_type: logstash 11 | fields_under_root: true 12 | fields: 13 | service_name: logstash 14 | env_name: ${ENV_NAME} 15 | ip_address: ${IP_ADDRESS} 16 | 17 | - paths: 18 | - "/var/log/besu/*.log" 19 | type: log 20 | enabled: true 21 | document_type: besu 22 | fields_under_root: true 23 | fields: 24 | service_name: besu 25 | env_name: ${ENV_NAME} 26 | ip_address: ${IP_ADDRESS} 27 | 28 | - paths: 29 | - "/var/log/quorum/*.log" 30 | type: log 31 | enabled: true 32 | document_type: quorum 33 | fields_under_root: true 34 | fields: 35 | service_name: quorum 36 | env_name: ${ENV_NAME} 37 | ip_address: ${IP_ADDRESS} 38 | 39 | - paths: 40 | - "/var/log/tessera/*.log" 41 | type: log 42 | enabled: true 43 | document_type: tessera 44 | fields_under_root: true 45 | fields: 46 | service_name: tessera 47 | env_name: ${ENV_NAME} 48 | ip_address: ${IP_ADDRESS} 49 | 50 | output.redis: 51 | enabled: true 52 | hosts: ["${REDIS_HOST}:${REDIS_PORT}"] 53 | key: filebeat 54 | 55 | 56 | logging: 57 | level: error 58 | metrics.enabled: false 59 | to_files: false 60 | json: true 61 | files: 62 | path: /var/log/filebeat 63 | name: filebeat-all.log 64 | keepfiles: 0 65 | #rotateonstartup: true 66 | 67 | -------------------------------------------------------------------------------- /src/quorum-test-network/logstash/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.elastic.co/logstash/logstash:7.14.1 2 | 3 | ENV ES_HOST http://localhost:9200 4 | ENV REDIS_HOST localhost 5 | ENV REDIS_PORT 6379 6 | 7 | # Remove exisiting file 8 | RUN mkdir -p /usr/share/logstash/logs && \ 9 | rm -f /usr/share/logstash/pipeline/logstash.conf 10 | 11 | # Add pipeline files 12 | ADD pipeline/ /usr/share/logstash/pipeline/ 13 | 14 | # Add configuration files 15 | ADD config/ /usr/share/logstash/config/ 16 | 17 | # Test the configuration 18 | RUN /usr/share/logstash/bin/logstash -t 19 | -------------------------------------------------------------------------------- /src/quorum-test-network/logstash/config/logstash.yml: -------------------------------------------------------------------------------- 1 | # ensure name is set so that monitoring in Kibana is easy to identify 2 | node.name: "logstash-quorum" 3 | 4 | log.format: json 5 | path: 6 | config: /usr/share/logstash/pipeline 7 | logs: /usr/share/logstash/logs 8 | 9 | xpack: 10 | monitoring: 11 | enabled: true 12 | elasticsearch: 13 | hosts: ${ES_HOST} -------------------------------------------------------------------------------- /src/quorum-test-network/logstash/pipeline/10_filebeat_redis.conf: -------------------------------------------------------------------------------- 1 | input { 2 | redis { 3 | host => "${REDIS_HOST}" 4 | port => "${REDIS_PORT}" 5 | codec => "json" 6 | data_type => "list" 7 | key => "filebeat" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/quorum-test-network/logstash/pipeline/10_metricbeat_redis.conf: -------------------------------------------------------------------------------- 1 | input { 2 | redis { 3 | host => "${REDIS_HOST}" 4 | port => "${REDIS_PORT}" 5 | codec => "json" 6 | data_type => "list" 7 | type => "metricbeat" 8 | key => "metricbeat" 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/quorum-test-network/logstash/pipeline/20_besu.conf: -------------------------------------------------------------------------------- 1 | filter { 2 | if [service_name] == "besu" { 3 | json { 4 | source => "message" 5 | } 6 | date { 7 | match => [ "timestamp" , "ISO8601" ] 8 | remove_field => [ "timestamp" ] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/quorum-test-network/logstash/pipeline/20_logstash.conf: -------------------------------------------------------------------------------- 1 | filter { 2 | if [service_name] == "logstash" { 3 | json { 4 | source => "message" 5 | } 6 | 7 | date { 8 | match => [ "timeMillis", "UNIX_MS" ] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/quorum-test-network/logstash/pipeline/20_quorum.conf: -------------------------------------------------------------------------------- 1 | filter { 2 | if [service_name] == "quorum" { 3 | grok { 4 | match => { "message" => "%{GREEDYDATA:level}\[%{MONTHNUM:monthnum}\-%{DATA:monthday}\|%{TIME:time}\] %{GREEDYDATA:message}" } 5 | overwrite => [ "message" ] 6 | } 7 | mutate { 8 | add_field => { 9 | "timestamp" => "%{monthnum} %{monthday} %{time}" 10 | } 11 | } 12 | date { 13 | match => [ "timestamp" , "MM dd HH:mm:ss.SSS", "MM dd HH:mm:ss.SSS", "ISO8601"] 14 | remove_field => [ "timestamp" ] 15 | } 16 | mutate { 17 | remove_field => [ "time" ,"month","monthday","year","timestamp"] 18 | } 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/quorum-test-network/logstash/pipeline/20_tessera.conf: -------------------------------------------------------------------------------- 1 | filter { 2 | if [service_name] == "tessera" { 3 | json { 4 | source => "message" 5 | } 6 | date { 7 | match => [ "timestamp" , "ISO8601" ] 8 | remove_field => [ "timestamp" ] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/quorum-test-network/logstash/pipeline/30_elasticsearch.conf: -------------------------------------------------------------------------------- 1 | output { 2 | if [service_name] == "logstash" { 3 | elasticsearch { 4 | hosts => ["${ES_HOST}"] 5 | index => "logstash-%{+YYYY.MM.dd}" 6 | } 7 | } 8 | 9 | else if [service_name] == "besu" { 10 | elasticsearch { 11 | hosts => ["${ES_HOST}"] 12 | index => "besu-%{+YYYY.MM.dd}" 13 | } 14 | } 15 | 16 | else if [service_name] == "tessera" { 17 | elasticsearch { 18 | hosts => ["${ES_HOST}"] 19 | index => "tessera-%{+YYYY.MM.dd}" 20 | } 21 | } 22 | 23 | else if [service_name] == "quorum" { 24 | elasticsearch { 25 | hosts => ["${ES_HOST}"] 26 | index => "quorum-%{+YYYY.MM.dd}" 27 | } 28 | } 29 | 30 | else if [type] == "metricbeat" { 31 | elasticsearch { 32 | hosts => ["${ES_HOST}"] 33 | index => "metricbeat-%{+YYYY.MM.dd}" 34 | } 35 | } 36 | 37 | else { 38 | elasticsearch { 39 | hosts => ["${ES_HOST}"] 40 | index => "unknown-%{+YYYY.MM.dd}" 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/quorum-test-network/loki/loki.yml: -------------------------------------------------------------------------------- 1 | auth_enabled: false 2 | 3 | server: 4 | http_listen_port: 3100 5 | grpc_listen_port: 9096 6 | 7 | common: 8 | path_prefix: /tmp/loki 9 | storage: 10 | filesystem: 11 | chunks_directory: /tmp/loki/chunks 12 | rules_directory: /tmp/loki/rules 13 | replication_factor: 1 14 | ring: 15 | instance_addr: 127.0.0.1 16 | kvstore: 17 | store: inmemory 18 | 19 | schema_config: 20 | configs: 21 | - from: 2021-01-01 22 | store: boltdb-shipper 23 | object_store: filesystem 24 | schema: v11 25 | index: 26 | prefix: index_ 27 | period: 24h 28 | 29 | # If you would like to disable reporting, uncomment the following lines: 30 | #analytics: 31 | # reporting_enabled: false -------------------------------------------------------------------------------- /src/quorum-test-network/metricbeat/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.elastic.co/beats/metricbeat:7.14.1 2 | ENV IP_ADDRESS "127.0.0.1" 3 | ENV REDIS_HOST localhost 4 | ENV REDIS_PORT 6379 5 | 6 | USER root 7 | ADD ./metricbeat.yml /usr/share/metricbeat/metricbeat.yml 8 | RUN chown root:metricbeat /usr/share/metricbeat/metricbeat.yml && chmod go-w /usr/share/metricbeat/metricbeat.yml 9 | USER metricbeat 10 | 11 | CMD ["metricbeat", "-c", "metricbeat.yml"] 12 | -------------------------------------------------------------------------------- /src/quorum-test-network/metricbeat/metricbeat.yml: -------------------------------------------------------------------------------- 1 | 2 | metricbeat.modules: 3 | - module: prometheus 4 | period: 15s 5 | hosts: 6 | - validator1:9545 7 | - validator2:9545 8 | - validator3:9545 9 | - validator4:9545 10 | - rpcnode:9545 11 | - member1besu:9545 12 | - member2besu:9545 13 | - member3besu:9545 14 | metrics_path: /metrics 15 | 16 | output.redis: 17 | enabled: true 18 | hosts: ["${REDIS_HOST}:${REDIS_PORT}"] 19 | key: metricbeat 20 | 21 | 22 | logging: 23 | level: error 24 | to_files: false 25 | json: true 26 | files: 27 | path: /var/log/metricbeat 28 | name: metricbeat-all.log 29 | keepfiles: 0 30 | #rotateonstartup: true 31 | 32 | -------------------------------------------------------------------------------- /src/quorum-test-network/quorum-explorer/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "algorithm": "qbft", 3 | "nodes": [ 4 | { 5 | "name": "rpcnode", 6 | "client": "besu", 7 | "rpcUrl": "http://rpcnode:8545", 8 | "privateTxUrl": "" 9 | }, 10 | { 11 | "name": "validator1", 12 | "client": "besu", 13 | "rpcUrl": "http://validator1:8545", 14 | "privateTxUrl": "" 15 | }, 16 | { 17 | "name": "validator2", 18 | "client": "besu", 19 | "rpcUrl": "http://validator2:8545", 20 | "privateTxUrl": "" 21 | }, 22 | { 23 | "name": "validator3", 24 | "client": "besu", 25 | "rpcUrl": "http://validator3:8545", 26 | "privateTxUrl": "" 27 | }, 28 | { 29 | "name": "validator4", 30 | "client": "besu", 31 | "rpcUrl": "http://validator4:8545", 32 | "privateTxUrl": "" 33 | }, 34 | { 35 | "name": "member1", 36 | "client": "besu", 37 | "rpcUrl": "http://member1besu:8545", 38 | "privateTxUrl": "http://member1tessera:9080", 39 | "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 40 | "accountAddress": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73" 41 | }, 42 | { 43 | "name": "member2", 44 | "client": "besu", 45 | "rpcUrl": "http://member2besu:8545", 46 | "privateTxUrl": "http://member2tessera:9080", 47 | "privateKey": "0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3", 48 | "accountAddress": "0x627306090abaB3A6e1400e9345bC60c78a8BEf57" 49 | }, 50 | { 51 | "name": "member3", 52 | "client": "besu", 53 | "rpcUrl": "http://member3besu:8545", 54 | "privateTxUrl": "http://member3tessera:9080", 55 | "privateKey": "0xae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f", 56 | "accountAddress": "0xf17f52151EbEF6C7334FAD080c5704D77216b732" 57 | } 58 | ] 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/quorum-test-network/quorum-explorer/env: -------------------------------------------------------------------------------- 1 | QE_BASEPATH="/explorer" 2 | QE_CONFIG_PATH="/app/config.json" 3 | NODE_ENV=production 4 | 5 | DISABLE_AUTH=true 6 | 7 | NEXTAUTH_URL=http://localhost:25000 8 | NEXTAUTH_URL_INTERNAL=http://localhost:25000 9 | NEXTAUTH_SECRET=68134139e258058cd8c74fc362cec39db176aa17a359e2a63233b9c858947445 10 | # DO NOT RE-USE THE ABOVE GENERATED IN PRODUCTION 11 | # To generate NEXTAUTH_SECRET: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32; 12 | 13 | local_username= 14 | local_password= 15 | 16 | GITHUB_ID= 17 | GITHUB_SECRET= 18 | 19 | AUTH0_ID= 20 | AUTH0_SECRET= 21 | AUTH0_DOMAIN= 22 | 23 | FACEBOOK_ID= 24 | FACEBOOK_SECRET= 25 | 26 | GOOGLE_ID= 27 | GOOGLE_SECRET= 28 | 29 | TWITTER_ID= 30 | TWITTER_SECRET= 31 | 32 | GITLAB_CLIENT_ID= 33 | GITLAB_CLIENT_SECRET= 34 | 35 | AZURE_AD_CLIENT_ID= 36 | AZURE_AD_CLIENT_SECRET= 37 | AZURE_AD_TENANT_ID= 38 | 39 | ATLASSIAN_CLIENT_ID= 40 | ATLASSIAN_CLIENT_SECRET= 41 | 42 | COGNITO_CLIENT_ID= 43 | COGNITO_CLIENT_SECRET= 44 | COGNITO_ISSUER= 45 | 46 | OKTA_CLIENT_ID= 47 | OKTA_CLIENT_SECRET= 48 | OKTA_ISSUER= 49 | 50 | SLACK_CLIENT_ID= 51 | SLACK_CLIENT_SECRET= 52 | -------------------------------------------------------------------------------- /src/quorum-test-network/remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -u 2 | 3 | # Copyright 2018 ConsenSys AG. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 11 | # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | # specific language governing permissions and limitations under the License. 13 | 14 | NO_LOCK_REQUIRED=false 15 | 16 | . ./.env 17 | . ./.common.sh 18 | 19 | removeDockerImage(){ 20 | if [[ ! -z `docker ps -a | grep $1` ]]; then 21 | docker image rm $1 22 | fi 23 | } 24 | 25 | echo "${bold}*************************************" 26 | echo "Quorum Dev Quickstart " 27 | echo "*************************************${normal}" 28 | echo "Stop and remove network..." 29 | 30 | docker compose down -v 31 | docker compose rm -sfv 32 | 33 | if [ -f "docker-compose-deps.yml" ]; then 34 | echo "Stopping dependencies..." 35 | docker compose -f docker-compose-deps.yml down -v 36 | docker compose rm -sfv 37 | fi 38 | # pet shop dapp 39 | if [[ ! -z `docker ps -a | grep quorum-dev-quickstart_pet_shop` ]]; then 40 | docker stop quorum-dev-quickstart_pet_shop 41 | docker rm quorum-dev-quickstart_pet_shop 42 | removeDockerImage quorum-dev-quickstart_pet_shop 43 | fi 44 | 45 | if grep -q 'kibana:' docker-compose.yml 2> /dev/null ; then 46 | docker image rm quorum-test-network_elasticsearch 47 | docker image rm quorum-test-network_logstash 48 | docker image rm quorum-test-network_filebeat 49 | docker image rm quorum-test-network_metricbeat 50 | fi 51 | 52 | rm ${LOCK_FILE} 53 | echo "Lock file ${LOCK_FILE} removed" 54 | -------------------------------------------------------------------------------- /src/quorum-test-network/restart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./stop.sh 4 | echo "Waiting 30s for containers to stop" 5 | sleep 30 6 | ./resume.sh 7 | -------------------------------------------------------------------------------- /src/quorum-test-network/resume.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -u 2 | 3 | # Copyright 2018 ConsenSys AG. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 11 | # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | # specific language governing permissions and limitations under the License. 13 | 14 | NO_LOCK_REQUIRED=false 15 | 16 | . ./.env 17 | . ./.common.sh 18 | 19 | echo "${bold}*************************************" 20 | echo "Quorum Dev Quickstart " 21 | echo "*************************************${normal}" 22 | echo "Resuming network..." 23 | echo "----------------------------------" 24 | 25 | if [ -f "docker-compose-deps.yml" ]; then 26 | echo "Starting dependencies..." 27 | docker compose -f docker-compose-deps.yml start 28 | sleep 60 29 | fi 30 | 31 | docker compose start 32 | 33 | -------------------------------------------------------------------------------- /src/quorum-test-network/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -u 2 | 3 | # Copyright 2018 ConsenSys AG. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 11 | # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | # specific language governing permissions and limitations under the License. 13 | 14 | NO_LOCK_REQUIRED=true 15 | 16 | . ./.env 17 | . ./.common.sh 18 | 19 | # create log folders with the user permissions so it won't conflict with container permissions 20 | mkdir -p logs/besu logs/quorum logs/tessera 21 | 22 | # Build and run containers and network 23 | echo "docker-compose.yml" > ${LOCK_FILE} 24 | 25 | echo "${bold}*************************************" 26 | echo "Quorum Dev Quickstart" 27 | echo "*************************************${normal}" 28 | echo "Start network" 29 | echo "--------------------" 30 | 31 | if [ -f "docker-compose-deps.yml" ]; then 32 | echo "Starting dependencies..." 33 | docker compose -f docker-compose-deps.yml up --detach 34 | sleep 60 35 | fi 36 | 37 | echo "Starting network..." 38 | docker compose build --pull 39 | docker compose up --detach 40 | 41 | 42 | #list services and endpoints 43 | ./list.sh 44 | -------------------------------------------------------------------------------- /src/quorum-test-network/smart_contracts/contracts/Counter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | contract Counter { 4 | int private count = 0; 5 | function incrementCounter() public { 6 | count += 1; 7 | } 8 | function decrementCounter() public { 9 | count -= 1; 10 | } 11 | function getCount() public view returns (int) { 12 | return count; 13 | } 14 | } -------------------------------------------------------------------------------- /src/quorum-test-network/smart_contracts/contracts/SimpleStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.10; 3 | 4 | contract SimpleStorage { 5 | uint public storedData; 6 | event stored(address _to, uint _amount); 7 | constructor(uint initVal) { 8 | emit stored(msg.sender, initVal); 9 | storedData = initVal; 10 | } 11 | function set(uint x) public { 12 | emit stored(msg.sender, x); 13 | storedData = x; 14 | } 15 | function get() view public returns (uint retVal) { 16 | return storedData; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/quorum-test-network/smart_contracts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@consensys-software/smart_contracts", 3 | "version": "1.0.0", 4 | "description": "Example smart contracts for trying out Quorum", 5 | "scripts": { 6 | "compile": "node scripts/compile.js", 7 | "deploy": "node scripts/deploy.js", 8 | "public-transaction": "node scripts/public_tx.js", 9 | "private-transaction": "node scripts/private_tx.js" 10 | }, 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "async-promise-pool": "^1.0.6", 14 | "fs-extra": "^10.0.0", 15 | "solc": "0.8.10", 16 | "@nomicfoundation/hardhat-ethers": "^3.0.0", 17 | "@nomicfoundation/hardhat-network-helpers": "^1.0.0", 18 | "@nomicfoundation/hardhat-toolbox": "^3.0.0", 19 | "@nomicfoundation/hardhat-verify": "^1.0.0", 20 | "ethers": "6.7.1", 21 | "hardhat-gas-reporter": "^1.0.8", 22 | "@ethereumjs/common": "^4.0.0", 23 | "@ethereumjs/tx": "^5.0.0", 24 | "web3js-quorum": "22.4.0", 25 | "web3": "1.10.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/quorum-test-network/smart_contracts/scripts/compile.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs-extra'); 3 | const solc = require('solc'); 4 | 5 | const contractsPath = path.resolve(__dirname, '../', 'contracts'); 6 | 7 | function buildSources() { 8 | const sources = {}; 9 | const contractsFiles = fs.readdirSync(contractsPath); 10 | contractsFiles.forEach(file => { 11 | if(file.endsWith(".sol")){ 12 | const contractFullPath = path.resolve(contractsPath, file); 13 | sources[file] = { 14 | content: fs.readFileSync(contractFullPath, 'utf8') 15 | }; 16 | } 17 | }); 18 | return sources; 19 | } 20 | 21 | const input = { 22 | language: 'Solidity', 23 | sources: buildSources(), 24 | settings: { 25 | outputSelection: { 26 | '*': { 27 | '*': [ '*', 'evm.bytecode' ] 28 | } 29 | } 30 | } 31 | } 32 | 33 | function compileContracts() { 34 | const stringifiedJson = JSON.stringify(input); 35 | console.log(stringifiedJson) 36 | const compilationResult = solc.compile(stringifiedJson); 37 | console.log(compilationResult) 38 | const output = JSON.parse(compilationResult); 39 | console.log(output) 40 | const compiledContracts = output.contracts; 41 | for (let contract in compiledContracts) { 42 | for(let contractName in compiledContracts[contract]) { 43 | console.log(contract) 44 | fs.outputJsonSync( 45 | path.resolve(contractsPath, `${contractName}.json`), 46 | compiledContracts[contract][contractName], { spaces: 2 } 47 | ) 48 | } 49 | } 50 | } 51 | 52 | const main = () => { 53 | compileContracts(); 54 | } 55 | 56 | if (require.main === module) { 57 | main(); 58 | } 59 | 60 | module.exports = exports = main 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/quorum-test-network/splunk/splunk.yml: -------------------------------------------------------------------------------- 1 | splunk: 2 | conf: 3 | indexes: 4 | directory: /opt/splunk/etc/apps/search/local 5 | content: 6 | ledger: 7 | coldPath: $SPLUNK_DB/ledger/colddb 8 | datatype: event 9 | homePath: $SPLUNK_DB/ledger/db 10 | maxTotalDataSizeMB: 4096 11 | thawedPath: $SPLUNK_DB/ledger/thaweddb 12 | logs: 13 | coldPath: $SPLUNK_DB/logs/colddb 14 | datatype: event 15 | homePath: $SPLUNK_DB/logs/db 16 | maxTotalDataSizeMB: 4096 17 | thawedPath: $SPLUNK_DB/logs/thaweddb 18 | metrics: 19 | coldPath: $SPLUNK_DB/metrics/colddb 20 | datatype: metric 21 | homePath: $SPLUNK_DB/metrics/db 22 | maxTotalDataSizeMB: 1024 23 | thawedPath: $SPLUNK_DB/metrics/thaweddb 24 | traces: 25 | coldPath: $SPLUNK_DB/traces/colddb 26 | datatype: event 27 | homePath: $SPLUNK_DB/traces/db 28 | maxTotalDataSizeMB: 1024 29 | thawedPath: $SPLUNK_DB/traces/thaweddb 30 | 31 | -------------------------------------------------------------------------------- /src/quorum-test-network/static/blockchain-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/static/blockchain-network.png -------------------------------------------------------------------------------- /src/quorum-test-network/static/metamask-faucet-transfer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/static/metamask-faucet-transfer.png -------------------------------------------------------------------------------- /src/quorum-test-network/static/npm-send-private-tx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/static/npm-send-private-tx.png -------------------------------------------------------------------------------- /src/quorum-test-network/static/qs-dapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-labs/learning-tokens/c31285bccf76d87f74bf979800d844fc7394a375/src/quorum-test-network/static/qs-dapp.png -------------------------------------------------------------------------------- /src/quorum-test-network/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -u 2 | 3 | # Copyright 2018 ConsenSys AG. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 11 | # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | # specific language governing permissions and limitations under the License. 13 | 14 | NO_LOCK_REQUIRED=false 15 | 16 | . ./.env 17 | . ./.common.sh 18 | 19 | echo "${bold}*************************************" 20 | echo "Quorum Dev Quickstart " 21 | echo "*************************************${normal}" 22 | echo "Stopping network" 23 | echo "----------------------------------" 24 | 25 | 26 | docker compose stop 27 | 28 | if [ -f "docker-compose-deps.yml" ]; then 29 | echo "Stopping dependencies..." 30 | docker compose -f docker-compose-deps.yml stop 31 | fi 32 | 33 | --------------------------------------------------------------------------------