diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 417d97d5..ac2109ea 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -34,11 +34,12 @@ body: label: Domain description: Which GovTool instance were you connected to? options: + - gov.tools + - preview.gov.tools - sanchogov.tools - dev-sanchogov.tools - test-sanchogov.tools - stage-sanchogov.tools - - preview.gov.tools - Custom setup validations: required: true diff --git a/generate_latest_report_redirect.sh b/.github/scripts/generate_latest_report_redirect.sh similarity index 100% rename from generate_latest_report_redirect.sh rename to .github/scripts/generate_latest_report_redirect.sh diff --git a/generate_report_details.sh b/.github/scripts/generate_report_details.sh similarity index 55% rename from generate_report_details.sh rename to .github/scripts/generate_report_details.sh index f9e4416b..bf813195 100644 --- a/generate_report_details.sh +++ b/.github/scripts/generate_report_details.sh @@ -7,5 +7,6 @@ else latest_number=$(echo "$gh_pages_content" | grep -Eo '[0-9]+' | sort -nr | head -n 1) fi -echo "::set-output name=report_number::$((latest_number+1))" -echo "::set-output name=report_url::https://$(dirname "$GH_PAGES").github.io/$(basename "$GH_PAGES")/$REPORT_NAME" +echo "report_number=$((latest_number+1))" >> $GITHUB_OUTPUT +echo "report_url=https://$(dirname "$GH_PAGES").github.io/$(basename "$GH_PAGES")/$REPORT_NAME" >> $GITHUB_OUTPUT + diff --git a/register_report.sh b/.github/scripts/register_report.sh similarity index 74% rename from register_report.sh rename to .github/scripts/register_report.sh index a36016eb..f5e5756f 100644 --- a/register_report.sh +++ b/.github/scripts/register_report.sh @@ -8,8 +8,8 @@ cp -r gh-pages/* "$PROJECT_DIR" || true if grep -q "$REPORT_NAME" "$PROJECT_DIR/$PROJECT_FILE"; then echo "Project already exists" - echo "::set-output name=project_exists::true" + echo "project_exists=true">> $GITHUB_OUTPUT else echo "$REPORT_NAME" >> "$PROJECT_DIR/$PROJECT_FILE" - echo "::set-output name=project_exists::false" + echo "project_exists=false">> $GITHUB_OUTPUT fi diff --git a/.github/workflows/build-and-deploy-test-stack.yml b/.github/workflows/build-and-deploy-test-stack.yml index f003258c..a4d3c07a 100644 --- a/.github/workflows/build-and-deploy-test-stack.yml +++ b/.github/workflows/build-and-deploy-test-stack.yml @@ -15,39 +15,64 @@ jobs: deploy: name: Deploy app runs-on: ubuntu-latest - env: - GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} - GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} - GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} - SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} - GTM_ID: ${{ secrets.GTM_ID }} - NPMRC_TOKEN: ${{ secrets.NPMRC_TOKEN }} - SENTRY_DSN_FRONTEND: ${{ secrets.SENTRY_DSN_FRONTEND }} - PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - USERSNAP_SPACE_API_KEY: ${{ secrets.USERSNAP_SPACE_API_KEY }} - APP_ENV: test - PDF_API_URL: ${{ secrets.PDF_API_URL}} steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Setup SSH agent - uses: webfactory/ssh-agent@v0.8.0 + - name: Set up SSH and deploy + uses: appleboy/ssh-action@v1.0.3 with: - ssh-private-key: ${{ secrets.TEST_STACK_SSH_KEY }} - - - name: Run Ansible playbook - uses: dawidd6/action-ansible-playbook@v2 - with: - playbook: playbook.yml - directory: ./tests/test-infrastructure + host: ${{ secrets.TEST_STACK_SERVER_IP }} + username: ec2-user key: ${{ secrets.TEST_STACK_SSH_KEY }} - inventory: | - [test_server] - ${{ secrets.TEST_STACK_SERVER_IP }} ansible_user=ec2-user - options: | - --verbose + command_timeout: 100m ## Haskell container build takes a lot of time. + script: | + REPO_URL="https://github.com/${{ github.repository }}" + DEST_DIR="$HOME/Documents/govtool" + + # Create parent directory if it does not exist + mkdir -p "$(dirname "$DEST_DIR")" + + # Check if $DEST_DIR exists + if [ -d "$DEST_DIR" ]; then + if [ -d "$DEST_DIR/.git" ]; then + cd $DEST_DIR || exit + echo "Updating repository..." + git fetch --all + git checkout --force "$GOVTOOL_TAG" + else + echo "Not a git repository. Re-cloning..." + rm -rf "$DEST_DIR" + git clone "$REPO_URL" "$DEST_DIR" + cd "$DEST_DIR" || exit + git checkout --force "$GOVTOOL_TAG" + fi + else + echo "Directory does not exist. Cloning repository..." + git clone "$REPO_URL" "$DEST_DIR" + cd "$DEST_DIR" || exit + git checkout --force "$GOVTOOL_TAG" + fi + + # Execute the build-and-deploy.sh script + cd $DEST_DIR/tests/test-infrastructure + ./build-and-deploy.sh update-images + docker system prune + (docker image ls -q | xargs docker image rm --force ) || echo "Images cleaned-up" + envs: GOVTOOL_TAG, GRAFANA_ADMIN_PASSWORD, GRAFANA_SLACK_RECIPIENT, GRAFANA_SLACK_OAUTH_TOKEN, SENTRY_DSN_BACKEND, GTM_ID, NPMRC_TOKEN, SENTRY_DSN_FRONTEND, PIPELINE_URL, USERSNAP_SPACE_API_KEY, APP_ENV, PDF_API_URL env: GOVTOOL_TAG: ${{ github.sha }} + GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} + GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} + GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} + SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} + GTM_ID: ${{ secrets.GTM_ID }} + NPMRC_TOKEN: ${{ secrets.NPMRC_TOKEN }} + SENTRY_DSN_FRONTEND: ${{ secrets.SENTRY_DSN_FRONTEND }} + PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + USERSNAP_SPACE_API_KEY: ${{ secrets.USERSNAP_SPACE_API_KEY }} + APP_ENV: test + PDF_API_URL: ${{ secrets.PDF_API_URL }} + KUBER_API_KEY: ${{secrets.KUBER_API_KEY}} diff --git a/.github/workflows/frontend_sonar_scan.yml b/.github/workflows/frontend_sonar_scan.yml index 5a78a37b..a2504652 100644 --- a/.github/workflows/frontend_sonar_scan.yml +++ b/.github/workflows/frontend_sonar_scan.yml @@ -12,35 +12,35 @@ jobs: runs-on: ubuntu-latest permissions: read-all steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: govtool/frontend/node_modules - key: ${{ runner.os }}-node-${{ hashFiles('govtool/frontend/package-lock.json') }} + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: govtool/frontend/node_modules + key: ${{ runner.os }}-node-${{ hashFiles('govtool/frontend/package-lock.json') }} - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version-file: "govtool/frontend/.nvmrc" - registry-url: "https://registry.npmjs.org/" - scope: "@intersect.mbo" - - name: 🧪 Test - working-directory: govtool/frontend - env: - NODE_OPTIONS: "--max_old_space_size=6144" - NODE_AUTH_TOKEN: ${{ secrets.NPMRC_TOKEN }} - run: | - npm ci - npm run test:coverage + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version-file: "govtool/frontend/.nvmrc" + registry-url: "https://registry.npmjs.org/" + scope: "@intersect.mbo" + - name: 🧪 Test + working-directory: govtool/frontend + env: + NODE_OPTIONS: "--max_old_space_size=6144" + NODE_AUTH_TOKEN: ${{ secrets.NPMRC_TOKEN }} + run: | + npm ci + npm run test:coverage - - uses: sonarsource/sonarqube-scan-action@master - if: always() - with: - projectBaseDir: govtool/frontend - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: https://sonarcloud.io \ No newline at end of file + - uses: sonarsource/sonarqube-scan-action@master + if: always() + with: + projectBaseDir: govtool/frontend + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: https://sonarcloud.io diff --git a/.github/workflows/merge.yaml b/.github/workflows/merge.yaml index 29a7969d..d89b4ee3 100644 --- a/.github/workflows/merge.yaml +++ b/.github/workflows/merge.yaml @@ -20,6 +20,7 @@ jobs: check-build-deploy: environment: ${{ (github.ref_name == 'main' && 'prod-govtool') || (github.ref_name == 'staging' && 'pre-prod-govtool') || (github.ref_name == 'test' && 'qa-govtool') || (github.ref_name == 'develop' && 'dev-govtool') }} strategy: + fail-fast: false matrix: include: - workdir: ./govtool/backend @@ -120,9 +121,10 @@ jobs: context: ${{ matrix.workdir }} file: ${{ matrix.dockerfile }} tags: ${{ steps.image_lowercase.outputs.lowercase }}:${{ env.TAG }} - load: true + load: false cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache + outputs: type=docker,dest=/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar build-args: | VITE_APP_ENV=${{ secrets.VITE_APP_ENV }} VITE_BASE_URL=${{ secrets.VITE_BASE_URL }} @@ -145,11 +147,11 @@ jobs: - name: Scan Docker image with Dockle id: dockle run: | - wget https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.tar.gz - tar zxvf dockle_0.4.14_Linux-64bit.tar.gz + wget -q https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.tar.gz + tar zxf dockle_0.4.14_Linux-64bit.tar.gz sudo mv dockle /usr/local/bin - dockle --exit-level fatal --format json --output ${{ matrix.workdir }}/dockle_scan_output.json ${{ steps.image_lowercase.outputs.lowercase }}:${{ env.TAG }} + dockle --exit-code 1 --exit-level fatal --format json -ak GHC_RELEASE_KEY -ak CABAL_INSTALL_RELEASE_KEY -ak STACK_RELEASE_KEY -ak KEY_SHA512 --input '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' --output ${{ matrix.workdir }}/dockle_scan_output.json echo " dockle exited w/ $?" cat ${{ matrix.workdir }}/dockle_scan_output.json @@ -157,30 +159,6 @@ jobs: - name: Push Docker image to GHCR run: | + docker load -i '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' + rm -rf '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' docker push ${{ steps.image_lowercase.outputs.lowercase }}:${{ env.TAG }} - - - name: Deploy with Qovery - if: github.ref == 'refs/heads/develop' - env: - QOVERY_CLI_ACCESS_TOKEN: ${{secrets.QOVERY_CLI_ACCESS_TOKEN }} - run: | - - echo "Deploying on $ENVIRONMENT" - echo "Organization - ${{ vars.ORGANIZATION }}" - echo "Project - ${{ vars.PROJECT }}" - - # Download and install Qovery CLI - curl -s https://get.qovery.com | bash - - qovery container list \ - --organization ${{ vars.ORGANIZATION }} \ - --project ${{ vars.PROJECT }} \ - --environment $ENVIRONMENT - - qovery container deploy \ - --organization ${{ vars.ORGANIZATION }} \ - --project ${{ vars.PROJECT }} \ - --environment $ENVIRONMENT \ - --container ${{ matrix.qovery_container_name }} \ - --tag ${{ env.TAG }} \ - --watch diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 44601ee2..7b5c5685 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -16,6 +16,7 @@ permissions: jobs: static-checks: strategy: + fail-fast: false matrix: include: - workdir: ./govtool/backend @@ -107,9 +108,10 @@ jobs: context: ${{ matrix.workdir }} file: ${{ matrix.dockerfile }} tags: ${{ steps.image_lowercase.outputs.lowercase }} - load: true - # cache-from: type=local,src=/tmp/.buildx-cache - # cache-to: type=local,dest=/tmp/.buildx-cache + load: false + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + outputs: type=docker,dest=/tmp/image-${{ matrix.name }}-${{ github.sha }}-pr.tar build-args: | VITE_APP_ENV=${{ secrets.VITE_APP_ENV }} VITE_BASE_URL=${{ secrets.VITE_BASE_URL }} @@ -125,17 +127,12 @@ jobs: - name: Scan Docker image with Dockle id: dockle run: | - set -ex - wget https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.tar.gz - tar zxvf dockle_0.4.14_Linux-64bit.tar.gz + wget -q https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.tar.gz + tar zxf dockle_0.4.14_Linux-64bit.tar.gz sudo mv dockle /usr/local/bin - docker images - docker image prune -af --filter "until=1h" - docker save ${{ steps.image_lowercase.outputs.lowercase }} -o image.tar || : - touch ${{ matrix.workdir }}/dockle_scan_output.json - dockle --input image.tar --exit-level fatal --format json --output ${{ matrix.workdir }}/dockle_scan_output.json || : - rm -rf image.tar - echo " dockle exited w/ $?" + + dockle --exit-code 1 --exit-level fatal -ak GHC_RELEASE_KEY -ak CABAL_INSTALL_RELEASE_KEY -ak STACK_RELEASE_KEY -ak KEY_SHA512 --format json --input '/tmp/image-${{ matrix.name }}-${{ github.sha }}-pr.tar' --output ${{ matrix.workdir }}/dockle_scan_output.json + rm -rf '/tmp/image-${{ matrix.name }}-${{ github.sha }}-pr.tar' cat ${{ matrix.workdir }}/dockle_scan_output.json echo "outcome=success" >> $GITHUB_OUTPUT diff --git a/.github/workflows/test_backend.yml b/.github/workflows/test_backend.yml index a8e0560f..faf2cbb8 100644 --- a/.github/workflows/test_backend.yml +++ b/.github/workflows/test_backend.yml @@ -72,8 +72,8 @@ jobs: id: register-project if: ${{success()}} run: | - chmod +x ./register_report.sh - ./register_report.sh + chmod +x .github/scripts/register_report.sh + .github/scripts/register_report.sh - if: steps.register-project.outputs.project_exists != 'true' uses: JamesIves/github-pages-deploy-action@v4 with: @@ -85,8 +85,8 @@ jobs: - name: Generate report details id: report-details run: | - chmod +x ./generate_report_details.sh - ./generate_report_details.sh + chmod +x .github/scripts/generate_report_details.sh + .github/scripts/generate_report_details.sh - name: Build report uses: simple-elf/allure-report-action@master @@ -102,8 +102,8 @@ jobs: - name: Generate Latest Report run: | - chmod +x ./generate_latest_report_redirect.sh - ./generate_latest_report_redirect.sh ${{steps.report-details.outputs.report_number}} + chmod +x .github/scripts/generate_latest_report_redirect.sh + .github/scripts/generate_latest_report_redirect.sh ${{steps.report-details.outputs.report_number}} - name: Deploy report to Github Pages uses: JamesIves/github-pages-deploy-action@v4 diff --git a/.github/workflows/test_integration_playwright.yml b/.github/workflows/test_integration_playwright.yml index 474bbbfb..95a5151a 100644 --- a/.github/workflows/test_integration_playwright.yml +++ b/.github/workflows/test_integration_playwright.yml @@ -106,8 +106,8 @@ jobs: id: register-project if: ${{success()}} run: | - chmod +x ./register_report.sh - ./register_report.sh + chmod +x .github/scripts/register_report.sh + .github/scripts/register_report.sh - if: steps.register-project.outputs.project_exists != 'true' uses: JamesIves/github-pages-deploy-action@v4 with: @@ -119,8 +119,8 @@ jobs: - name: Generate report details id: report-details run: | - chmod +x ./generate_report_details.sh - ./generate_report_details.sh + chmod +x .github/scripts/generate_report_details.sh + .github/scripts/generate_report_details.sh - name: Build report uses: simple-elf/allure-report-action@master @@ -137,8 +137,8 @@ jobs: - name: Generate Latest Report run: | - chmod +x ./generate_latest_report_redirect.sh - ./generate_latest_report_redirect.sh ${{steps.report-details.outputs.report_number}} + chmod +x .github/scripts/generate_latest_report_redirect.sh + .github/scripts/generate_latest_report_redirect.sh ${{steps.report-details.outputs.report_number}} - name: Deploy report to Github Pages uses: JamesIves/github-pages-deploy-action@v4 diff --git a/.github/workflows/test_storybook.yml b/.github/workflows/test_storybook.yml index 88b58a87..85f7f97c 100644 --- a/.github/workflows/test_storybook.yml +++ b/.github/workflows/test_storybook.yml @@ -23,7 +23,7 @@ jobs: run: | npm config set @intersect.mbo:registry "https://registry.npmjs.org/" --location=global npm config set //registry.npmjs.org/:_authToken ${NPMRC_TOKEN} --location=global - npm install + npm ci - name: Install Playwright run: npx playwright install --with-deps - name: Build Storybook diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..c4d175a6 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,24 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + + - repo: local + hooks: + - id: hlint + name: hlint + description: HLint gives suggestions on how to improve your source code. + entry: hlint + language: system + files: '\.l?hs$' + + - id: stylish-haskell + name: stylish-haskell + description: Haskell code format checker. + entry: stylish-haskell --config govtool/backend/.stylish-haskell.yaml + language: system + files: '\.l?hs$' diff --git a/CHANGELOG.md b/CHANGELOG.md index 1295a98c..4ec1ed24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,103 @@ changes. - +### Removed + +- + +## [sancho-v1.0.17](https://github.com/IntersectMBO/govtool/releases/tag/sancho-v1.0.17) 2024-09-05 + +### Added + +- + +### Fixed + +- Make testIds for link and identity references in drep form unique [Issue 1928](https://github.com/IntersectMBO/govtool/issues/1928) +- Fix saving the Do Not List checkbox value on DRep registration [Issue 1940](https://github.com/IntersectMBO/govtool/issues/1940) + +### Changed + +- Make displaying own DRep in DRep directory available [Issue 1934](https://github.com/IntersectMBO/govtool/issues/1934) + +### Removed + +- + +## [sancho-v1.0.16](https://github.com/IntersectMBO/govtool/releases/tag/sancho-v1.0.16) 2024-09-04 + +### Fixed + +- Fix incorrect documentation link for "Learn More" button on proposal [Issue 1877](https://github.com/IntersectMBO/govtool/issues/1877) +- Fix getVotes sql to query time from vote tx instead of govAaction tx [Issue 1925](https://github.com/IntersectMBO/govtool/issues/1925) +- Map references from validation service to format expected by FE [Issue 1924](https://github.com/IntersectMBO/govtool/issues/1924) + +### Changed + +- Change the spelling of ADA to Ada or ada [Issue 1916](https://github.com/IntersectMBO/govtool/issues/1916) + +### Removed + +- + +## [sancho-v1.0.15](https://github.com/IntersectMBO/govtool/releases/tag/sancho-v1.0.15) 2024-09-03 + +### Added + +- Add missing test DRep Details test IDs [Issue 1863](https://github.com/IntersectMBO/govtool/issues/1863) +- Add missing system banners test IDs [Issue 1839](https://github.com/IntersectMBO/govtool/issues/1839) + +### Fixed + +- Delete duplicate text on DRep registration form [Issue 1847](https://github.com/IntersectMBO/govtool/issues/1847) +- Fix modal content invisible on ios [Issue 1842](https://github.com/IntersectMBO/govtool/issues/1842) +- Fix counting votes by CC committee members and SPOs [Issue 1838](https://github.com/IntersectMBO/govtool/issues/1838) +- Fix displaying non relevant data in protocol parameter change Governance Action [Issue 1601](https://github.com/IntersectMBO/govtool/issues/1601) +- Fix voting on info actions in bootstrapping phase [Issue 1876](https://github.com/IntersectMBO/govtool/issues/1876) +- Fix missing DRep name whitespace validation [Issue 1873](https://github.com/IntersectMBO/govtool/issues/1873) +- Fix displaying wrongly formatted Governance Action ID [Issue 1866](https://github.com/IntersectMBO/govtool/issues/1866k) +- Make payment address optional in DRep registration and edit form [Issue 1871](https://github.com/IntersectMBO/govtool/issues/1871) +- Fix displaying wrongly formatted Governance Action ID [Issue 1866](https://github.com/IntersectMBO/govtool/issues/1866) +- Fix displaying the proper Governance Action Details on renavigating between pages +- Fix displaying protocol params Governance Action details when metadata validation fails [Issue 1889](https://github.com/IntersectMBO/govtool/issues/1889) +- Fix runtime error when navigating to GA details from Voted on by me tab [Issue 1910](https://github.com/IntersectMBO/govtool/issues/1910) + +### Changed + +- Replace diff library to avoid usage of `--force` in package installation +- Bump @intersect.mbo/pdf-ui to v0.3.8 +- Change logo to Cardano GovTool [Issue 1851](https://github.com/IntersectMBO/govtool/issues/1851) +- Change copy to Cardano GovTool [Issue 1852](https://github.com/IntersectMBO/govtool/issues/1852) +- Replace mocked MrDRep label in DRep retired card with given name if exists, or make the description more neutral if the given name is not provided [Issue 1887](https://github.com/IntersectMBO/govtool/issues/1887) +- Change home page hero copy [Issue 1903](https://github.com/IntersectMBO/govtool/issues/1903) +- Bump cardano-node to 9.1.1 [Issue 1895](https://github.com/IntersectMBO/govtool/issues/1895) +- Bump cardano-db-sync 13.5.0.1 [Issue 1906](https://github.com/IntersectMBO/govtool/issues/1906) +- Adjust CIP119 support to match final designs [Issue 1850](https://github.com/IntersectMBO/govtool/issues/1850) + +## [sancho-v1.0.14](https://github.com/IntersectMBO/govtool/releases/tag/sancho-v1.0.14) 2024-08-26 + +### Added + +- Add support for displaying protocol parameters governance actions [Issue 1601](https://github.com/IntersectMBO/govtool/issues/1601) +- Add SPO and CC committee total votes to gov actions [Issue 1704](https://github.com/IntersectMBO/govtool/issues/1704) +- Add support for hard fork initiation governance action details [Issue 1600](https://github.com/IntersectMBO/govtool/issues/1600) +- Add support for hard fork initiation previous governance action data [Issue 1600](https://github.com/IntersectMBO/govtool/issues/1600) +- Add support for CIP-119 on the backend and metadata validation [Issue 1758](https://github.com/IntersectMBO/govtool/issues/1758) +- Add support for CIP-119 on the frontend [Issue 1760](https://github.com/IntersectMBO/govtool/issues/1758) +- Add support for HF Initiation and Protocol Parameter Change governance action builders [Issue 1600](https://github.com/IntersectMBO/govtool/issues/1600) & [Issue 1601](https://github.com/IntersectMBO/govtool/issues/1601) + +### Fixed + +- Fix typescript bug leading to runtime error when entering Governance Action details page via direct link [Issue 1801](https://github.com/IntersectMBO/govtool/issues/1801) +- Fix accessing missing epochParams drep_deposit [Issue 1733](https://github.com/IntersectMBO/govtool/issues/1733) + +### Changed + +- Bump @intersect.mbo/pdf-ui to v0.3.7 +- Decrease level of wallet related sentry reports [Issue 1699](https://github.com/IntersectMBO/govtool/issues/1699) +- Bump cardano-db-sync to 13.3.0.0 [Issue 1809](https://github.com/IntersectMBO/govtool/issues/1809) +- Update Gitbook links [Issue 1774](https://github.com/IntersectMBO/govtool/issues/1774) + ## [sancho-v1.0.13](https://github.com/IntersectMBO/govtool/releases/tag/sancho-v1.0.13) 2024-08-22 ### Added @@ -30,6 +127,8 @@ changes. - Add network metrics model to frontend service - Added workflows to add labels to issues - Make voting on governance actions enabled based on protocol version [Issue 1703](https://github.com/IntersectMBO/govtool/issues/1703) +- Add banner informing about network [Issue 1702](https://github.com/IntersectMBO/govtool/issues/1702) +- Add banner informing about bootstrapping phase [Issue 1708](https://github.com/IntersectMBO/govtool/issues/1708) ### Fixed diff --git a/README.md b/README.md index 0f81436c..8a8aea50 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

- Monorepo containing Voltaire GovTool and supporting utilities + Monorepo containing Cardano GovTool and supporting utilities

@@ -18,7 +18,7 @@ ## 🌄 Purpose -The Voltaire GovTool enables ada holders to experience the governance features described in [CIP-1694](https://github.com/cardano-foundation/CIPs/blob/master/CIP-1694/README.md). +The Cardano GovTool enables ada holders to experience the governance features described in [CIP-1694](https://github.com/cardano-foundation/CIPs/blob/master/CIP-1694/README.md). ### Instances @@ -48,7 +48,7 @@ Learn more; [docs.gov.tools](https://docs.gov.tools/). ### Utilities -- [Governance Action Loader](./governance-action-loader/) +- [Governance Action Loader](./gov-action-loader/) ### Backend diff --git a/docs/GOVERNANCE_ACTION_SUBMISSION.md b/docs/GOVERNANCE_ACTION_SUBMISSION.md index 2262d5dd..c2aa0825 100644 --- a/docs/GOVERNANCE_ACTION_SUBMISSION.md +++ b/docs/GOVERNANCE_ACTION_SUBMISSION.md @@ -15,7 +15,15 @@ For creating the Governance Action, you need to consume 2 utility methods provid ### Types ```typescript -import { VotingProposalBuilder } from "@emurgo/cardano-serialization-lib-nodejs"; +import { + VotingProposalBuilder, + Costmdls, + DrepVotingThresholds, + ExUnitPrices, + UnitInterval, + ExUnits, + PoolVotingThresholds, +} from "@emurgo/cardano-serialization-lib-nodejs"; interface GovernanceAction { title: string; @@ -37,6 +45,48 @@ interface TreasuryProps { url: string; } +type ProtocolParamsUpdate = { + adaPerUtxo: string; + collateralPercentage: number; + committeeTermLimit: number; + costModels: Costmdls; + drepDeposit: string; + drepInactivityPeriod: number; + drepVotingThresholds: DrepVotingThresholds; + executionCosts: ExUnitPrices; + expansionRate: UnitInterval; + governanceActionDeposit: string; + governanceActionValidityPeriod: number; + keyDeposit: string; + maxBlockBodySize: number; + maxBlockExUnits: ExUnits; + maxBlockHeaderSize: number; + maxCollateralInputs: number; + maxEpoch: number; + maxTxExUnits: ExUnits; + maxTxSize: number; + maxValueSize: number; + minCommitteeSize: number; + minPoolCost: string; + minFeeA: string; + minFeeB: string; + nOpt: number; + poolDeposit: string; + poolPledgeInfluence: UnitInterval; + poolVotingThresholds: PoolVotingThresholds; + refScriptCoinsPerByte: UnitInterval; + treasuryGrowthRate: UnitInterval; +}; + +interface ProtocolParameterChangeProps { + prevGovernanceActionHash: string; + prevGovernanceActionIndex: number; + url: string; + hash: string; + + protocolParamsUpdate: Partial; +} + const createGovernanceActionJsonLD: ( governanceAction: GovernanceAction ) => NodeObject; @@ -111,10 +161,14 @@ Example: ```typescript // When used within a CardanoProvider -const { buildSignSubmitConwayCertTx, buildNewInfoGovernanceAction } = - useCardano(); - -// hash of the generated Governance Action metadata, url of the metadata +const { + buildSignSubmitConwayCertTx, + buildNewInfoGovernanceAction, + buildProtocolParameterChangeGovernanceAction, + buildHardForkInitiationGovernanceAction, +} = useCardano(); + +// Info Governance Action const govActionBuilder = await buildNewInfoGovernanceAction({ hash, url }); // sign and submit the transaction @@ -123,7 +177,7 @@ await buildSignSubmitConwayCertTx({ type: "createGovAction", }); -// or if you want to use the Treasury Governance Action +// Treasury Governance Action const { buildTreasuryGovernanceAction } = useCardano(); // hash of the generated Governance Action metadata, url of the metadata, amount of the transaction, receiving address is the stake key address @@ -134,6 +188,31 @@ const govActionBuilder = await buildTreasuryGovernanceAction({ receivingAddress, }); +// Protocol Parameter Change Governance Action +const { buildProtocolParameterChangeGovernanceAction } = useCardano(); + +// hash of the previous Governance Action, index of the previous Governance Action, url of the metadata, hash of the metadata, and the updated protocol parameters +const govActionBuilder = await buildProtocolParameterChangeGovernanceAction({ + prevGovernanceActionHash, + prevGovernanceActionIndex, + url, + hash, + protocolParamsUpdate, +}); + +// Hard Fork Initiation Governance Action +const { buildHardForkInitiationGovernanceAction } = useCardano(); + +// hash of the previous Governance Action, index of the previous Governance Action, url of the metadata, hash of the metadata, and the major and minor numbers of the hard fork initiation +const govActionBuilder = await buildHardForkInitiationGovernanceAction({ + prevGovernanceActionHash, + prevGovernanceActionIndex, + url, + hash, + major, + minor, +}); + // sign and submit the transaction await buildSignSubmitConwayCertTx({ govActionBuilder, diff --git a/govtool/backend/Dockerfile b/govtool/backend/Dockerfile index fbeb614a..38c09931 100644 --- a/govtool/backend/Dockerfile +++ b/govtool/backend/Dockerfile @@ -4,4 +4,4 @@ FROM $BASE_IMAGE_REPO:$BASE_IMAGE_TAG WORKDIR /src COPY . . RUN cabal build -RUN cp dist-newstyle/build/x86_64-linux/ghc-9.2.7/vva-be-1.0.13/x/vva-be/build/vva-be/vva-be /usr/local/bin +RUN cp dist-newstyle/build/x86_64-linux/ghc-9.2.7/vva-be-1.0.17/x/vva-be/build/vva-be/vva-be /usr/local/bin diff --git a/govtool/backend/Dockerfile.base b/govtool/backend/Dockerfile.base index 8f4e4c35..6dd3c75a 100644 --- a/govtool/backend/Dockerfile.base +++ b/govtool/backend/Dockerfile.base @@ -6,5 +6,13 @@ FROM haskell:9.2.7-buster WORKDIR /src + +RUN apt-get update && \ + apt-get install -y wget lsb-release && \ + sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' && \ + wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \ + apt-get update && \ + apt-get install -y postgresql-14 libpq-dev + COPY . . RUN cabal update && cabal configure && cabal install --only-dependencies && rm -rf /src/* diff --git a/govtool/backend/Dockerfile.qovery b/govtool/backend/Dockerfile.qovery index a6789ec6..cdf1acc7 100644 --- a/govtool/backend/Dockerfile.qovery +++ b/govtool/backend/Dockerfile.qovery @@ -4,7 +4,7 @@ FROM $BASE_IMAGE_REPO:$BASE_IMAGE_TAG WORKDIR /src COPY . . RUN cabal build -RUN cp dist-newstyle/build/x86_64-linux/ghc-9.2.7/vva-be-1.0.13/x/vva-be/build/vva-be/vva-be /usr/local/bin +RUN cp dist-newstyle/build/x86_64-linux/ghc-9.2.7/vva-be-1.0.17/x/vva-be/build/vva-be/vva-be /usr/local/bin # Expose the necessary port EXPOSE 9876 diff --git a/govtool/backend/sql/get-drep-info.sql b/govtool/backend/sql/get-drep-info.sql index 2e8ee08f..ca4505d6 100644 --- a/govtool/backend/sql/get-drep-info.sql +++ b/govtool/backend/sql/get-drep-info.sql @@ -176,7 +176,14 @@ SELECT DRepRegister.tx_hash, DRepRetire.tx_hash, SoleVoterRegister.tx_hash, - SoleVoterRetire.tx_hash + SoleVoterRetire.tx_hash, + off_chain_vote_drep_data.payment_address, + off_chain_vote_drep_data.given_name, + off_chain_vote_drep_data.objectives, + off_chain_vote_drep_data.motivations, + off_chain_vote_drep_data.qualifications, + off_chain_vote_drep_data.image_url, + off_chain_vote_drep_data.image_hash FROM IsRegisteredAsDRep CROSS JOIN IsRegisteredAsSoleVoter @@ -189,3 +196,6 @@ FROM CROSS JOIN DRepRetire CROSS JOIN SoleVoterRegister CROSS JOIN SoleVoterRetire + CROSS JOIN LatestRegistrationEntry + LEFT JOIN off_chain_vote_data ON off_chain_vote_data.voting_anchor_id = LatestRegistrationEntry.voting_anchor_id + LEFT JOIN off_chain_vote_drep_data ON off_chain_vote_drep_data.off_chain_vote_data_id = off_chain_vote_data.id diff --git a/govtool/backend/sql/get-votes.sql b/govtool/backend/sql/get-votes.sql index 7a875aba..31aaba85 100644 --- a/govtool/backend/sql/get-votes.sql +++ b/govtool/backend/sql/get-votes.sql @@ -11,6 +11,6 @@ on gov_action_tx.id = gov_action_proposal.tx_id join tx as vote_tx on vote_tx.id = voting_procedure.tx_id join block -on block.id = gov_action_tx.block_id +on block.id = vote_tx.block_id where drep_hash.raw = decode(?, 'hex') order by voting_procedure.gov_action_proposal_id, voting_procedure.drep_voter, voting_procedure.id desc diff --git a/govtool/backend/sql/list-dreps.sql b/govtool/backend/sql/list-dreps.sql index 399b5087..917f0641 100644 --- a/govtool/backend/sql/list-dreps.sql +++ b/govtool/backend/sql/list-dreps.sql @@ -29,7 +29,14 @@ SELECT encode(dr_voting_anchor.tx_hash, 'hex') AS tx_hash, newestRegister.time AS last_register_time, COALESCE(latestDeposit.deposit, 0), - non_deregister_voting_anchor.url IS NOT NULL AS has_non_deregister_voting_anchor + non_deregister_voting_anchor.url IS NOT NULL AS has_non_deregister_voting_anchor, + off_chain_vote_drep_data.payment_address, + off_chain_vote_drep_data.given_name, + off_chain_vote_drep_data.objectives, + off_chain_vote_drep_data.motivations, + off_chain_vote_drep_data.qualifications, + off_chain_vote_drep_data.image_url, + off_chain_vote_drep_data.image_hash FROM drep_hash dh JOIN ( @@ -89,6 +96,8 @@ FROM AND DRepDistr.rn = 1 LEFT JOIN voting_anchor va ON va.id = dr_voting_anchor.voting_anchor_id LEFT JOIN voting_anchor non_deregister_voting_anchor on non_deregister_voting_anchor.id = dr_non_deregister_voting_anchor.voting_anchor_id + LEFT JOIN off_chain_vote_data ON off_chain_vote_data.voting_anchor_id = va.id + LEFT JOIN off_chain_vote_drep_data on off_chain_vote_drep_data.off_chain_vote_data_id = off_chain_vote_data.id CROSS JOIN DRepActivity LEFT JOIN voting_procedure AS voting_procedure ON voting_procedure.drep_voter = dh.id LEFT JOIN tx AS tx ON tx.id = voting_procedure.tx_id @@ -128,4 +137,11 @@ GROUP BY dr_voting_anchor.tx_hash, newestRegister.time, latestDeposit.deposit, - non_deregister_voting_anchor.url + non_deregister_voting_anchor.url, + off_chain_vote_drep_data.payment_address, + off_chain_vote_drep_data.given_name, + off_chain_vote_drep_data.objectives, + off_chain_vote_drep_data.motivations, + off_chain_vote_drep_data.qualifications, + off_chain_vote_drep_data.image_url, + off_chain_vote_drep_data.image_hash diff --git a/govtool/backend/sql/list-proposals-my.sql b/govtool/backend/sql/list-proposals-my.sql deleted file mode 100644 index fd2454ae..00000000 --- a/govtool/backend/sql/list-proposals-my.sql +++ /dev/null @@ -1,113 +0,0 @@ -WITH LatestDrepDistr AS ( - SELECT - *, - ROW_NUMBER() OVER (PARTITION BY hash_id ORDER BY epoch_no DESC) AS rn - FROM - drep_distr -), -EpochUtils AS ( - SELECT - (Max(end_time) - Min(end_time)) / (Max(NO) - Min(NO)) AS epoch_duration, - Max(NO) AS last_epoch_no, - Max(end_time) AS last_epoch_end_time - FROM - epoch -), -always_no_confidence_voting_power AS ( - SELECT - coalesce(( - SELECT - amount - FROM drep_hash - LEFT JOIN drep_distr ON drep_hash.id = drep_distr.hash_id - WHERE - drep_hash.view = 'drep_always_no_confidence' ORDER BY epoch_no DESC LIMIT 1), 0) AS amount -), -always_abstain_voting_power AS ( - SELECT - coalesce(( - SELECT - amount - FROM drep_hash - LEFT JOIN drep_distr ON drep_hash.id = drep_distr.hash_id - WHERE - drep_hash.view = 'drep_always_abstain' ORDER BY epoch_no DESC LIMIT 1), 0) AS amount -) -SELECT - gov_action_proposal.id AS proposal_id, - encode(creator_tx.hash, 'hex') AS tx_hash, - gov_action_proposal.index, - gov_action_proposal.type::text, - CASE - WHEN gov_action_proposal.type = 'TreasuryWithdrawals' THEN - json_build_object('Reward Address', stake_address.view, 'Amount', treasury_withdrawal.amount) - WHEN gov_action_proposal.type::text = 'InfoAction' THEN - json_build_object() - ELSE - NULL - END AS description, - epoch_utils.last_epoch_end_time + epoch_utils.epoch_duration * (gov_action_proposal.expiration - epoch_utils.last_epoch_no) AS expiry_date, - gov_action_proposal.expiration AS expiry_epoch_no, - creator_block.time AS created_date, - creator_block.epoch_no AS created_epoch_no, - voting_anchor.url, - encode(voting_anchor.data_hash, 'hex') AS metadata_hash, - off_chain_vote_gov_action_data.title, - off_chain_vote_gov_action_data.abstract, - off_chain_vote_gov_action_data.motivation, - off_chain_vote_gov_action_data.rationale, - coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'Yes'), 0) + - CASE - WHEN gov_action_proposal.type = 'NoConfidence' THEN always_no_confidence_voting_power.amount - ELSE 0 - END AS yes_votes, - coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'No'), 0) + - CASE - WHEN gov_action_proposal.type = 'NoConfidence' THEN 0 - ELSE always_no_confidence_voting_power.amount - END AS no_votes, - coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'Abstain'), 0) + always_abstain_voting_power.amount AS abstain_votes -FROM - gov_action_proposal - LEFT JOIN treasury_withdrawal ON gov_action_proposal.id = treasury_withdrawal.gov_action_proposal_id - LEFT JOIN stake_address ON stake_address.id = treasury_withdrawal.stake_address_id - CROSS JOIN EpochUtils AS epoch_utils - CROSS JOIN always_no_confidence_voting_power - CROSS JOIN always_abstain_voting_power - CROSS JOIN off_chain_vote_gov_action_data ON off_chain_vote_gov_action_data.off_chain_vote_data_id = off_chain_vote_data.id - JOIN tx AS creator_tx ON creator_tx.id = gov_action_proposal.tx_id - JOIN block AS creator_block ON creator_block.id = creator_tx.block_id - LEFT JOIN voting_anchor ON voting_anchor.id = gov_action_proposal.voting_anchor_id - LEFT JOIN off_chain_vote_data ON off_chain_vote_data.voting_anchor_id = voting_anchor.id - LEFT JOIN voting_procedure ON voting_procedure.gov_action_proposal_id = gov_action_proposal.id - LEFT JOIN LatestDrepDistr ldd ON ldd.hash_id = voting_procedure.drep_voter AND ldd.rn = 1 -WHERE (NOT ? - OR (concat(encode(creator_tx.hash, 'hex'), '#', gov_action_proposal.index) IN ?)) -AND gov_action_proposal.expiration > ( - SELECT - Max(NO) - FROM - epoch) - AND gov_action_proposal.ratified_epoch IS NULL - AND gov_action_proposal.enacted_epoch IS NULL - AND gov_action_proposal.expired_epoch IS NULL - AND gov_action_proposal.dropped_epoch IS NULL -GROUP BY - (gov_action_proposal.id, - stake_address.view, - treasury_withdrawal.amount, - creator_block.epoch_no, - off_chain_vote_gov_action_data.title, - off_chain_vote_gov_action_data.abstract, - off_chain_vote_gov_action_data.motivation, - off_chain_vote_gov_action_data.rationale, - gov_action_proposal.index, - creator_tx.hash, - creator_block.time, - epoch_utils.epoch_duration, - epoch_utils.last_epoch_no, - epoch_utils.last_epoch_end_time, - voting_anchor.url, - voting_anchor.data_hash, - always_no_confidence_voting_power.amount, - always_abstain_voting_power.amount) diff --git a/govtool/backend/sql/list-proposals.sql b/govtool/backend/sql/list-proposals.sql index f09ec6f6..7926fd6b 100644 --- a/govtool/backend/sql/list-proposals.sql +++ b/govtool/backend/sql/list-proposals.sql @@ -44,6 +44,12 @@ SELECT when gov_action_proposal.type::text = 'InfoAction' then json_build_object() + + when gov_action_proposal.type::text = 'HardForkInitiation' then + json_build_object( + 'major', (gov_action_proposal.description->'contents'->1->>'major')::int, + 'minor', (gov_action_proposal.description->'contents'->1->>'minor')::int + ) else null end @@ -54,23 +60,32 @@ SELECT creator_block.epoch_no, voting_anchor.url, encode(voting_anchor.data_hash, 'hex'), + ROW_TO_JSON(proposal_params), off_chain_vote_gov_action_data.title, off_chain_vote_gov_action_data.abstract, off_chain_vote_gov_action_data.motivation, off_chain_vote_gov_action_data.rationale, - coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'Yes'), 0) +( + coalesce(Sum(ldd_drep.amount) FILTER (WHERE voting_procedure.vote::text = 'Yes'), 0) +( CASE WHEN gov_action_proposal.type = 'NoConfidence' THEN always_no_confidence_voting_power.amount ELSE 0 END) "yes_votes", - coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'No'), 0) +( + coalesce(Sum(ldd_drep.amount) FILTER (WHERE voting_procedure.vote::text = 'No'), 0) +( CASE WHEN gov_action_proposal.type = 'NoConfidence' THEN 0 ELSE always_no_confidence_voting_power.amount END) "no_votes", - coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'Abstain'), 0) + always_abstain_voting_power.amount "abstain_votes" + coalesce(Sum(ldd_drep.amount) FILTER (WHERE voting_procedure.vote::text = 'Abstain'), 0) + always_abstain_voting_power.amount "abstain_votes", + coalesce(vp_by_pool.poolYesVotes, 0), + coalesce(vp_by_pool.poolNoVotes, 0), + coalesce(vp_by_pool.poolAbstainVotes, 0), + coalesce(vp_by_cc.ccYesVotes, 0), + coalesce(vp_by_cc.ccNoVotes, 0), + coalesce(vp_by_cc.ccAbstainVotes, 0), + prev_gov_action.index as prev_gov_action_index, + encode(prev_gov_action_tx.hash, 'hex') as prev_gov_action_tx_hash FROM gov_action_proposal LEFT JOIN treasury_withdrawal @@ -83,11 +98,47 @@ FROM JOIN tx AS creator_tx ON creator_tx.id = gov_action_proposal.tx_id JOIN block AS creator_block ON creator_block.id = creator_tx.block_id LEFT JOIN voting_anchor ON voting_anchor.id = gov_action_proposal.voting_anchor_id + LEFT JOIN param_proposal as proposal_params ON gov_action_proposal.param_proposal = proposal_params.id LEFT JOIN off_chain_vote_data ON off_chain_vote_data.voting_anchor_id = voting_anchor.id LEFT JOIN off_chain_vote_gov_action_data ON off_chain_vote_gov_action_data.off_chain_vote_data_id = off_chain_vote_data.id LEFT JOIN voting_procedure ON voting_procedure.gov_action_proposal_id = gov_action_proposal.id - LEFT JOIN LatestDrepDistr ldd ON ldd.hash_id = voting_procedure.drep_voter - AND ldd.rn = 1 + LEFT JOIN LatestDrepDistr ldd_drep ON ldd_drep.hash_id = voting_procedure.drep_voter + AND ldd_drep.rn = 1 + LEFT JOIN + ( + SELECT + gov_action_proposal_id, + SUM(CASE WHEN vote = 'Yes' THEN 1 ELSE 0 END) AS poolYesVotes, + SUM(CASE WHEN vote = 'No' THEN 1 ELSE 0 END) AS poolNoVotes, + SUM(CASE WHEN vote = 'Abstain' THEN 1 ELSE 0 END) AS poolAbstainVotes + FROM + voting_procedure + WHERE + pool_voter IS NOT NULL + GROUP BY + gov_action_proposal_id + ) vp_by_pool + ON gov_action_proposal.id = vp_by_pool.gov_action_proposal_id + LEFT JOIN + ( + SELECT + gov_action_proposal_id, + SUM(CASE WHEN vote = 'Yes' THEN 1 ELSE 0 END) AS ccYesVotes, + SUM(CASE WHEN vote = 'No' THEN 1 ELSE 0 END) AS ccNoVotes, + SUM(CASE WHEN vote = 'Abstain' THEN 1 ELSE 0 END) AS ccAbstainVotes + FROM + voting_procedure + WHERE + committee_voter IS NOT NULL + GROUP BY + gov_action_proposal_id + ) vp_by_cc + ON gov_action_proposal.id = vp_by_cc.gov_action_proposal_id + + LEFT JOIN LatestDrepDistr ldd_cc ON ldd_cc.hash_id = voting_procedure.committee_voter + AND ldd_cc.rn = 1 + LEFT JOIN gov_action_proposal AS prev_gov_action ON gov_action_proposal.prev_gov_action_proposal = prev_gov_action.id + LEFT JOIN tx AS prev_gov_action_tx ON prev_gov_action.tx_id = prev_gov_action_tx.id WHERE (NOT ? OR (concat(encode(creator_tx.hash, 'hex'), '#', gov_action_proposal.index) IN ?)) AND gov_action_proposal.expiration >( @@ -108,13 +159,22 @@ GROUP BY off_chain_vote_gov_action_data.abstract, off_chain_vote_gov_action_data.motivation, off_chain_vote_gov_action_data.rationale, + vp_by_pool.poolYesVotes, + vp_by_pool.poolNoVotes, + vp_by_pool.poolAbstainVotes, + vp_by_cc.ccYesVotes, + vp_by_cc.ccNoVotes, + vp_by_cc.ccAbstainVotes, gov_action_proposal.index, creator_tx.hash, creator_block.time, epoch_utils.epoch_duration, epoch_utils.last_epoch_no, epoch_utils.last_epoch_end_time, + proposal_params, voting_anchor.url, voting_anchor.data_hash, always_no_confidence_voting_power.amount, - always_abstain_voting_power.amount) \ No newline at end of file + always_abstain_voting_power.amount, + prev_gov_action.index, + prev_gov_action_tx.hash) \ No newline at end of file diff --git a/govtool/backend/src/VVA/API.hs b/govtool/backend/src/VVA/API.hs index 702af1b7..64f6236d 100644 --- a/govtool/backend/src/VVA/API.hs +++ b/govtool/backend/src/VVA/API.hs @@ -22,6 +22,7 @@ import Data.Ord (Down (..)) import Data.Text hiding (any, drop, elem, filter, length, map, null, take) import qualified Data.Text as Text import qualified Data.Vector as V +import Data.Time.LocalTime (TimeZone, getCurrentTimeZone) import Numeric.Natural (Natural) @@ -44,6 +45,7 @@ import qualified VVA.Types as Types import VVA.Types (App, AppEnv (..), AppError (CriticalError, InternalError, ValidationError), CacheEnv (..)) +import Data.Time (TimeZone, localTimeToUTC) type VVAApi = "drep" :> "list" @@ -112,7 +114,14 @@ drepRegistrationToDrep Types.DRepRegistration {..} = dRepStatus = mapDRepStatus dRepRegistrationStatus, dRepType = mapDRepType dRepRegistrationType, dRepLatestTxHash = HexText <$> dRepRegistrationLatestTxHash, - dRepLatestRegistrationDate = dRepRegistrationLatestRegistrationDate + dRepLatestRegistrationDate = dRepRegistrationLatestRegistrationDate, + dRepPaymentAddress = dRepRegistrationPaymentAddress, + dRepGivenName = dRepRegistrationGivenName, + dRepObjectives = dRepRegistrationObjectives, + dRepMotivations = dRepRegistrationMotivations, + dRepQualifications = dRepRegistrationQualifications, + dRepImageUrl = dRepRegistrationImageUrl, + dRepImageHash = HexText <$> dRepRegistrationImageHash } delegationToResponse :: Types.Delegation -> DelegationResponse @@ -179,27 +188,36 @@ getVotingPower (unHexText -> dRepId) = do CacheEnv {dRepVotingPowerCache} <- asks vvaCache cacheRequest dRepVotingPowerCache dRepId $ DRep.getVotingPower dRepId -proposalToResponse :: Types.Proposal -> ProposalResponse -proposalToResponse Types.Proposal {..} = +proposalToResponse :: TimeZone -> Types.Proposal -> ProposalResponse +proposalToResponse timeZone Types.Proposal {..} = ProposalResponse { proposalResponseId = pack $ show proposalId, proposalResponseTxHash = HexText proposalTxHash, proposalResponseIndex = proposalIndex, proposalResponseType = fromMaybe InfoAction $ readMaybe $ unpack proposalType, proposalResponseDetails = GovernanceActionDetails <$> proposalDetails, - proposalResponseExpiryDate = proposalExpiryDate, + proposalResponseExpiryDate = localTimeToUTC timeZone <$> proposalExpiryDate, proposalResponseExpiryEpochNo = proposalExpiryEpochNo, - proposalResponseCreatedDate = proposalCreatedDate, + proposalResponseCreatedDate = localTimeToUTC timeZone proposalCreatedDate, proposalResponseCreatedEpochNo = proposalCreatedEpochNo, proposalResponseUrl = proposalUrl, proposalResponseMetadataHash = HexText proposalDocHash, + proposalResponseProtocolParams = ProtocolParams <$> proposalProtocolParams, proposalResponseTitle = proposalTitle, proposalResponseAbstract = proposalAbstract, proposalResponseMotivation = proposalMotivation, proposalResponseRationale = proposalRationale, - proposalResponseYesVotes = proposalYesVotes, - proposalResponseNoVotes = proposalNoVotes, - proposalResponseAbstainVotes = proposalAbstainVotes + proposalResponseDRepYesVotes = proposalDRepYesVotes, + proposalResponseDRepNoVotes = proposalDRepNoVotes, + proposalResponseDRepAbstainVotes = proposalDRepAbstainVotes, + proposalResponsePoolYesVotes = proposalPoolYesVotes, + proposalResponsePoolNoVotes = proposalPoolNoVotes, + proposalResponsePoolAbstainVotes = proposalPoolAbstainVotes, + proposalResponseCcYesVotes = proposalCcYesVotes, + proposalResponseCcNoVotes = proposalCcNoVotes, + proposalResponseCcAbstainVotes = proposalCcAbstainVotes, + proposalResponsePrevGovActionIndex = proposalPrevGovActionIndex, + proposalResponsePrevGovActionTxHash = HexText <$> proposalPrevGovActionTxHash } voteToResponse :: Types.Vote -> VoteParams @@ -222,7 +240,9 @@ mapSortAndFilterProposals -> [Types.Proposal] -> m [ProposalResponse] mapSortAndFilterProposals selectedTypes sortMode proposals = do - let mappedProposals = map proposalToResponse proposals + timeZone <- liftIO getCurrentTimeZone + + let mappedProposals = map (proposalToResponse timeZone) proposals let filteredProposals = if null selectedTypes then mappedProposals @@ -232,11 +252,14 @@ mapSortAndFilterProposals selectedTypes sortMode proposals = do proposalResponseType `elem` selectedTypes ) mappedProposals + + let totalYesVotes (ProposalResponse{..}) = proposalResponseDRepYesVotes + proposalResponsePoolYesVotes + proposalResponseCcYesVotes + let sortedProposals = case sortMode of Nothing -> filteredProposals Just NewestCreated -> sortOn (Down . proposalResponseCreatedDate) filteredProposals Just SoonestToExpire -> sortOn proposalResponseExpiryDate filteredProposals - Just MostYesVotes -> sortOn (Down . proposalResponseYesVotes) filteredProposals + Just MostYesVotes -> sortOn (Down . totalYesVotes) filteredProposals return sortedProposals getVotes :: App m => HexText -> [GovernanceActionType] -> Maybe GovernanceActionSortMode -> Maybe Text -> m [VoteResponse] @@ -270,6 +293,13 @@ drepInfo (unHexText -> dRepId) = do , dRepInfoResponseDRepRetireTxHash = HexText <$> dRepInfoDRepRetireTx , dRepInfoResponseSoleVoterRegisterTxHash = HexText <$> dRepInfoSoleVoterRegisterTx , dRepInfoResponseSoleVoterRetireTxHash = HexText <$> dRepInfoSoleVoterRetireTx + , dRepInfoResponsePaymentAddress = dRepInfoPaymentAddress + , dRepInfoResponseGivenName = dRepInfoGivenName + , dRepInfoResponseObjectives = dRepInfoObjectives + , dRepInfoResponseMotivations = dRepInfoMotivations + , dRepInfoResponseQualifications = dRepInfoQualifications + , dRepInfoResponseImageUrl = dRepInfoImageUrl + , dRepInfoResponseImageHash = HexText <$> dRepInfoImageHash } getCurrentDelegation :: App m => HexText -> m (Maybe DelegationResponse) @@ -346,7 +376,10 @@ getProposal g@(GovActionId govActionTxHash govActionIndex) mDrepId' = do let mDrepId = unHexText <$> mDrepId' CacheEnv {getProposalCache} <- asks vvaCache proposal@Types.Proposal {proposalUrl, proposalDocHash} <- cacheRequest getProposalCache (unHexText govActionTxHash, govActionIndex) (Proposal.getProposal (unHexText govActionTxHash) govActionIndex) - let proposalResponse = proposalToResponse proposal + + timeZone <- liftIO getCurrentTimeZone + + let proposalResponse = proposalToResponse timeZone proposal voteResponse <- case mDrepId of Nothing -> return Nothing Just drepId -> do diff --git a/govtool/backend/src/VVA/API/Types.hs b/govtool/backend/src/VVA/API/Types.hs index a2c410d6..308c1766 100644 --- a/govtool/backend/src/VVA/API/Types.hs +++ b/govtool/backend/src/VVA/API/Types.hs @@ -111,103 +111,6 @@ instance ToSchema AnyValue where & example ?~ toJSON exampleAnyValue -data MetadataValidationStatus = IncorrectFormat | IncorrectJSONLD | IncorrectHash | UrlNotFound deriving - ( Eq - , Show - ) - -instance ToJSON MetadataValidationStatus where - toJSON IncorrectFormat = "INCORRECT_FORMTAT" - toJSON IncorrectJSONLD = "INVALID_JSONLD" - toJSON IncorrectHash = "INVALID_HASH" - toJSON UrlNotFound = "URL_NOT_FOUND" - -instance FromJSON MetadataValidationStatus where - parseJSON (String s) = case s of - "INCORRECT_FORMTAT" -> pure IncorrectFormat - "INVALID_JSONLD" -> pure IncorrectJSONLD - "INVALID_HASH" -> pure IncorrectHash - "URL_NOT_FOUND" -> pure UrlNotFound - _ -> fail "Invalid MetadataValidationStatus" - parseJSON _ = fail "Invalid MetadataValidationStatus" - -instance ToSchema MetadataValidationStatus where - declareNamedSchema _ = pure $ NamedSchema (Just "MetadataValidationStatus") $ mempty - & type_ ?~ OpenApiString - & description ?~ "Metadata Validation Status" - & enum_ ?~ map toJSON [IncorrectFormat, IncorrectJSONLD, IncorrectHash, UrlNotFound] - - - -data InternalMetadataValidationResponse - = InternalMetadataValidationResponse - { internalMetadataValidationResponseStatus :: Maybe MetadataValidationStatus - , internalMmetadataValidationResponseValid :: Bool - } - deriving (Generic, Show) - -deriveJSON (jsonOptions "internalMetadataValidationResponse") ''InternalMetadataValidationResponse - -instance ToSchema InternalMetadataValidationResponse where - declareNamedSchema _ = do - NamedSchema name_ schema_ <- - genericDeclareNamedSchema - ( fromAesonOptions $ jsonOptions "internalMetadataValidationResponse" ) - (Proxy :: Proxy InternalMetadataValidationResponse) - return $ - NamedSchema name_ $ - schema_ - & description ?~ "Metadata Validation Response" - & example - ?~ toJSON ("{\"status\": \"INCORRECT_FORMTAT\", \"valid\":false, \"raw\":{\"some\":\"key\"}}" :: Text) - - -data MetadataValidationResponse - = MetadataValidationResponse - { metadataValidationResponseStatus :: Maybe Text - , metadataValidationResponseValid :: Bool - } - deriving (Generic, Show) - -deriveJSON (jsonOptions "metadataValidationResponse") ''MetadataValidationResponse - -instance ToSchema MetadataValidationResponse where - declareNamedSchema _ = do - NamedSchema name_ schema_ <- - genericDeclareNamedSchema - ( fromAesonOptions $ jsonOptions "metadataValidationResponse" ) - (Proxy :: Proxy MetadataValidationResponse) - return $ - NamedSchema name_ $ - schema_ - & description ?~ "Metadata Validation Response" - & example - ?~ toJSON ("{\"status\": \"INCORRECT_FORMTAT\", \"valid\":false}" :: Text) - -data MetadataValidationParams - = MetadataValidationParams - { metadataValidationParamsUrl :: Text - , metadataValidationParamsHash :: HexText - } - deriving (Generic, Show) - -deriveJSON (jsonOptions "metadataValidationParams") ''MetadataValidationParams - -instance ToSchema MetadataValidationParams where - declareNamedSchema proxy = do - NamedSchema name_ schema_ <- - genericDeclareNamedSchema - ( fromAesonOptions $ jsonOptions "metadataValidationParams" ) - proxy - return $ - NamedSchema name_ $ - schema_ - & description ?~ "Metadata Validation Params" - & example - ?~ toJSON ("{\"url\": \"https://metadata.xyz\", \"hash\": \"9af10e89979e51b8cdc827c963124a1ef4920d1253eef34a1d5cfe76438e3f11\"}" :: Text) - - - data GovActionId = GovActionId { govActionIdTxHash :: HexText @@ -414,6 +317,45 @@ instance ToSchema GovernanceActionMetadata where ?~ toJSON ("{\"some_key\": \"some value\", \"some_key2\": [1,2,3]}" :: Text) +newtype GetCurrentEpochParamsResponse + = GetCurrentEpochParamsResponse { getCurrentEpochParamsResponse :: Maybe Value } + deriving newtype (Show) + +instance FromJSON GetCurrentEpochParamsResponse where + parseJSON = pure . GetCurrentEpochParamsResponse . Just + +instance ToJSON GetCurrentEpochParamsResponse where + toJSON (GetCurrentEpochParamsResponse Nothing) = Null + toJSON (GetCurrentEpochParamsResponse (Just params)) = toJSON params + +exampleGetCurrentEpochParamsResponse :: Text +exampleGetCurrentEpochParamsResponse = + "{ \"id\":90,\"epoch_no\":90,\"min_fee_a\":44,\"min_fee_b\":155381,\"max_block_size\":90112,\"max_tx_size\":16384,\"max_bh_size\":1100,\"key_deposit\":2000000,\"pool_deposit\":500000000,\"max_epoch\":18,\"optimal_pool_count\":5\r\n00,\"influence\":0.3,\"monetary_expand_rate\":0.003,\"treasury_growth_rate\":0.2,\"decentralisation\":0,\"protocol_major\":8,\"protocol_minor\":0,\"min_utxo_value\":0,\"min_pool_cost\":340000000,\"nonce\":\"\\\\x664c2d0eedc1c\r\n9ee7fc8b4f242c8d13ba17fd31454c84357fa8f1ac62f682cf9\",\"cost_model_id\":2,\"price_mem\":0.0577,\"price_step\":7.21e-05,\"max_tx_ex_mem\":14000000,\"max_tx_ex_steps\":10000000000,\"max_block_ex_mem\":62000000,\"max_bloc\r\nk_ex_steps\":20000000000,\"max_val_size\":5000,\"collateral_percent\":150,\"max_collateral_inputs\":3,\"block_id\":387943,\"extra_entropy\":null,\"coins_per_utxo_size\":4310}" + +instance ToSchema GetCurrentEpochParamsResponse where + declareNamedSchema _ = pure $ NamedSchema (Just "GetCurrentEpochParamsResponse") $ mempty + & type_ ?~ OpenApiObject + & description ?~ "Protocol parameters encoded as JSON" + & example + ?~ toJSON exampleGetCurrentEpochParamsResponse + + +newtype ProtocolParams + = ProtocolParams { getProtocolParams :: Value } + deriving newtype (Show) + +instance FromJSON ProtocolParams where + parseJSON = pure . ProtocolParams + +instance ToJSON ProtocolParams where + toJSON (ProtocolParams params) = toJSON params + +instance ToSchema ProtocolParams where + declareNamedSchema _ = pure $ NamedSchema (Just "ProtocolParams") $ mempty + & type_ ?~ OpenApiObject + & description ?~ "Protocol parameters encoded as JSON" + & example + ?~ toJSON exampleGetCurrentEpochParamsResponse newtype GovernanceActionReferences @@ -435,28 +377,35 @@ instance ToSchema GovernanceActionReferences where ?~ toJSON ("[{\"uri\": \"google.com\", \"@type\": \"Other\", \"label\": \"example label\"}]" :: Text) - - data ProposalResponse = ProposalResponse - { proposalResponseId :: Text - , proposalResponseTxHash :: HexText - , proposalResponseIndex :: Integer - , proposalResponseType :: GovernanceActionType - , proposalResponseDetails :: Maybe GovernanceActionDetails - , proposalResponseExpiryDate :: Maybe UTCTime - , proposalResponseExpiryEpochNo :: Maybe Integer - , proposalResponseCreatedDate :: UTCTime - , proposalResponseCreatedEpochNo :: Integer - , proposalResponseUrl :: Text - , proposalResponseMetadataHash :: HexText - , proposalResponseTitle :: Maybe Text - , proposalResponseAbstract :: Maybe Text - , proposalResponseMotivation :: Maybe Text - , proposalResponseRationale :: Maybe Text - , proposalResponseYesVotes :: Integer - , proposalResponseNoVotes :: Integer - , proposalResponseAbstainVotes :: Integer + { proposalResponseId :: Text + , proposalResponseTxHash :: HexText + , proposalResponseIndex :: Integer + , proposalResponseType :: GovernanceActionType + , proposalResponseDetails :: Maybe GovernanceActionDetails + , proposalResponseExpiryDate :: Maybe UTCTime + , proposalResponseExpiryEpochNo :: Maybe Integer + , proposalResponseCreatedDate :: UTCTime + , proposalResponseCreatedEpochNo :: Integer + , proposalResponseUrl :: Text + , proposalResponseMetadataHash :: HexText + , proposalResponseProtocolParams :: Maybe ProtocolParams + , proposalResponseTitle :: Maybe Text + , proposalResponseAbstract :: Maybe Text + , proposalResponseMotivation :: Maybe Text + , proposalResponseRationale :: Maybe Text + , proposalResponseDRepYesVotes :: Integer + , proposalResponseDRepNoVotes :: Integer + , proposalResponseDRepAbstainVotes :: Integer + , proposalResponsePoolYesVotes :: Integer + , proposalResponsePoolNoVotes :: Integer + , proposalResponsePoolAbstainVotes :: Integer + , proposalResponseCcYesVotes :: Integer + , proposalResponseCcNoVotes :: Integer + , proposalResponseCcAbstainVotes :: Integer + , proposalResponsePrevGovActionIndex :: Maybe Integer + , proposalResponsePrevGovActionTxHash :: Maybe HexText } deriving (Generic, Show) @@ -474,13 +423,22 @@ exampleProposalResponse = "{ \"id\": \"proposalId123\"," <> "\"createdEpochNo\": 0," <> "\"url\": \"https://proposal.metadata.xyz\"," <> "\"metadataHash\": \"9af10e89979e51b8cdc827c963124a1ef4920d1253eef34a1d5cfe76438e3f11\"," + <> "\"protocolParams\": " <> exampleGetCurrentEpochParamsResponse <> "," <> "\"title\": \"Proposal Title\"," <> "\"abstract\": \"Proposal About\"," <> "\"motivation\": \"Proposal Motivation\"," <> "\"rationale\": \"Proposal Rationale\"," - <> "\"yesVotes\": 0," - <> "\"noVotes\": 0," - <> "\"abstainVotes\": 0}" + <> "\"dRepYesVotes\": 0," + <> "\"dRepNoVotes\": 0," + <> "\"dRepAbstainVotes\": 0," + <> "\"poolYesVotes\": 0," + <> "\"poolNoVotes\": 0," + <> "\"poolAbstainVotes\": 0," + <> "\"cCYesVotes\": 0," + <> "\"cCNoVotes\": 0," + <> "\"cCAbstainVotes\": 0," + <> "\"prevGovActionIndex\": 0," + <> "\"prevGovActionTxHash\": \"47c14a128cd024f1b990c839d67720825921ad87ed875def42641ddd2169b39c\"}" instance ToSchema ProposalResponse where declareNamedSchema proxy = do @@ -615,6 +573,13 @@ data DRepInfoResponse , dRepInfoResponseDRepRetireTxHash :: Maybe HexText , dRepInfoResponseSoleVoterRegisterTxHash :: Maybe HexText , dRepInfoResponseSoleVoterRetireTxHash :: Maybe HexText + , dRepInfoResponsePaymentAddress :: Maybe Text + , dRepInfoResponseGivenName :: Maybe Text + , dRepInfoResponseObjectives :: Maybe Text + , dRepInfoResponseMotivations :: Maybe Text + , dRepInfoResponseQualifications :: Maybe Text + , dRepInfoResponseImageUrl :: Maybe Text + , dRepInfoResponseImageHash :: Maybe HexText } deriving (Generic, Show) @@ -633,7 +598,14 @@ exampleDRepInfoResponse = <> "\"dRepRegisterTxHash\": \"47c14a128cd024f1b990c839d67720825921ad87ed875def42641ddd2169b39c\"," <> "\"dRepRetireTxHash\": \"47c14a128cd024f1b990c839d67720825921ad87ed875def42641ddd2169b39c\"," <> "\"soleVoterRegisterTxHash\": \"47c14a128cd024f1b990c839d67720825921ad87ed875def42641ddd2169b39c\"," - <> "\"soleVoterRetireTxHash\": \"47c14a128cd024f1b990c839d67720825921ad87ed875def42641ddd2169b39c\"}" + <> "\"soleVoterRetireTxHash\": \"47c14a128cd024f1b990c839d67720825921ad87ed875def42641ddd2169b39c\"," + <> "\"paymentAddress\": \"addr1qy49kr45ue0wq78d34dpg79syx3yekxryjadv9ykzczhjwm09pmyt6f6xvq5x9yah2vrxyg0np44ynm6n7hzafl2rqxs4v6nn3\"," + <> "\"givenName\": \"John Doe\"," + <> "\"objectives\": \"Objectives of the DRep\"," + <> "\"motivations\": \"Motivations of the DRep\"," + <> "\"qualifications\": \"Qualifications of the DRep\"," + <> "\"imageUrl\": \"https://drep.image.xyz\"," + <> "\"imageHash\": \"9af10e89979e51b8cdc827c963124a1ef4920d1253eef34a1d5cfe76438e3f11\"}" instance ToSchema DRepInfoResponse where declareNamedSchema proxy = do @@ -648,7 +620,6 @@ instance ToSchema DRepInfoResponse where & example ?~ toJSON exampleDRepInfoResponse - data GetProposalResponse = GetProposalResponse { getProposalResponseVote :: Maybe VoteParams @@ -661,7 +632,6 @@ exampleGetProposalResponse = "{\"vote\": " <> exampleVoteParams <> "," <> "\"proposal\": " <> exampleProposalResponse <> "}" - deriveJSON (jsonOptions "getProposalResponse") ''GetProposalResponse instance ToSchema GetProposalResponse where @@ -679,29 +649,6 @@ instance ToSchema GetProposalResponse where & example ?~ toJSON exampleGetProposalResponse - -newtype GetCurrentEpochParamsResponse - = GetCurrentEpochParamsResponse { getCurrentEpochParamsResponse :: Maybe Value } - deriving newtype (Show) - -instance FromJSON GetCurrentEpochParamsResponse where - parseJSON = pure . GetCurrentEpochParamsResponse . Just - -instance ToJSON GetCurrentEpochParamsResponse where - toJSON (GetCurrentEpochParamsResponse Nothing) = Null - toJSON (GetCurrentEpochParamsResponse (Just params)) = toJSON params - -exampleGetCurrentEpochParamsResponse :: Text -exampleGetCurrentEpochParamsResponse = - "{ \"id\":90,\"epoch_no\":90,\"min_fee_a\":44,\"min_fee_b\":155381,\"max_block_size\":90112,\"max_tx_size\":16384,\"max_bh_size\":1100,\"key_deposit\":2000000,\"pool_deposit\":500000000,\"max_epoch\":18,\"optimal_pool_count\":5\r\n00,\"influence\":0.3,\"monetary_expand_rate\":0.003,\"treasury_growth_rate\":0.2,\"decentralisation\":0,\"protocol_major\":8,\"protocol_minor\":0,\"min_utxo_value\":0,\"min_pool_cost\":340000000,\"nonce\":\"\\\\x664c2d0eedc1c\r\n9ee7fc8b4f242c8d13ba17fd31454c84357fa8f1ac62f682cf9\",\"cost_model_id\":2,\"price_mem\":0.0577,\"price_step\":7.21e-05,\"max_tx_ex_mem\":14000000,\"max_tx_ex_steps\":10000000000,\"max_block_ex_mem\":62000000,\"max_bloc\r\nk_ex_steps\":20000000000,\"max_val_size\":5000,\"collateral_percent\":150,\"max_collateral_inputs\":3,\"block_id\":387943,\"extra_entropy\":null,\"coins_per_utxo_size\":4310}" - -instance ToSchema GetCurrentEpochParamsResponse where - declareNamedSchema _ = pure $ NamedSchema (Just "GetCurrentEpochParamsResponse") $ mempty - & type_ ?~ OpenApiObject - & description ?~ "Protocol parameters encoded as JSON" - & example - ?~ toJSON exampleGetCurrentEpochParamsResponse - newtype GetTransactionStatusResponse = GetTransactionStatusResponse { getTransactionstatusResponseTransactionConfirmed :: Bool } deriving (Generic, Show) @@ -784,8 +731,6 @@ instance ToParamSchema DRepStatus where & type_ ?~ OpenApiString & enum_ ?~ map toJSON (enumFromTo minBound maxBound :: [DRepStatus]) - - data DRepType = NormalDRep | SoleVoter instance Show DRepType where @@ -823,6 +768,13 @@ data DRep , dRepType :: DRepType , dRepLatestTxHash :: Maybe HexText , dRepLatestRegistrationDate :: UTCTime + , dRepPaymentAddress :: Maybe Text + , dRepGivenName :: Maybe Text + , dRepObjectives :: Maybe Text + , dRepMotivations :: Maybe Text + , dRepQualifications :: Maybe Text + , dRepImageUrl :: Maybe Text + , dRepImageHash :: Maybe HexText } deriving (Generic, Show) @@ -840,7 +792,15 @@ exampleDrep = <> "\"status\": \"Active\"," <> "\"type\": \"DRep\"," <> "\"latestTxHash\": \"47c14a128cd024f1b990c839d67720825921ad87ed875def42641ddd2169b39c\"," - <> "\"latestRegistrationDate\": \"1970-01-01T00:00:00Z\"}" + <> "\"latestRegistrationDate\": \"1970-01-01T00:00:00Z\"," + <> "\"paymentAddress\": \"addr1qy49kr45ue0wq78d34dpg79syx3yekxryjadv9ykzczhjwm09pmyt6f6xvq5x9yah2vrxyg0np44ynm6n7hzafl2rqxs4v6nn3\"," + <> "\"givenName\": \"John Doe\"," + <> "\"objectives\": \"Some Objectives\"," + <> "\"motivations\": \"Some Motivations\"," + <> "\"qualifications\": \"Some Qualifications\"," + <> "\"qualifications\": \"Some Qualifications\"," + <> "\"imageUrl\": \"https://image.url\"," + <> "\"imageHash\": \"9198b1b204273ba5c67a13310b5a806034160f6a063768297e161d9b759cad61\"}" -- ToSchema instance for DRep instance ToSchema DRep where diff --git a/govtool/backend/src/VVA/DRep.hs b/govtool/backend/src/VVA/DRep.hs index 07b20408..fd262bc9 100644 --- a/govtool/backend/src/VVA/DRep.hs +++ b/govtool/backend/src/VVA/DRep.hs @@ -61,8 +61,26 @@ listDReps = withPool $ \conn -> do results <- liftIO $ SQL.query_ conn listDRepsSql timeZone <- liftIO getCurrentTimeZone return - [ DRepRegistration drepHash drepView url dataHash (floor @Scientific deposit) votingPower status drepType txHash (localTimeToUTC timeZone date) - | (drepHash, drepView, url, dataHash, deposit, votingPower, isActive, txHash, date, latestDeposit, latestNonDeregisterVotingAnchorWasNotNull) <- results + [ DRepRegistration drepHash drepView url dataHash (floor @Scientific deposit) votingPower status drepType txHash (localTimeToUTC timeZone date) paymentAddress givenName objectives motivations qualifications imageUrl imageHash + | ( drepHash + , drepView + , url + , dataHash + , deposit + , votingPower + , isActive + , txHash + , date + , latestDeposit + , latestNonDeregisterVotingAnchorWasNotNull + , paymentAddress + , givenName + , objectives + , motivations + , qualifications + , imageUrl + , imageHash + ) <- results , let status = case (isActive, deposit) of (_, d) | d < 0 -> Retired (isActive, d) | d >= 0 && isActive -> Active @@ -125,6 +143,13 @@ getDRepInfo drepId = withPool $ \conn -> do , drepRetireTx , soleVoterRegisterTx , soleVoterRetireTx + , paymentAddress + , givenName + , objectives + , motivations + , qualifications + , imageUrl + , imageHash )] -> return $ DRepInfo { dRepInfoIsRegisteredAsDRep = fromMaybe False isRegisteredAsDRep @@ -139,5 +164,12 @@ getDRepInfo drepId = withPool $ \conn -> do , dRepInfoDRepRetireTx = drepRetireTx , dRepInfoSoleVoterRegisterTx = soleVoterRegisterTx , dRepInfoSoleVoterRetireTx = soleVoterRetireTx + , dRepInfoPaymentAddress = paymentAddress + , dRepInfoGivenName = givenName + , dRepInfoObjectives = objectives + , dRepInfoMotivations = motivations + , dRepInfoQualifications = qualifications + , dRepInfoImageUrl = imageUrl + , dRepInfoImageHash = imageHash } - [] -> return $ DRepInfo False False False False Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing + [] -> return $ DRepInfo False False False False Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing diff --git a/govtool/backend/src/VVA/Proposal.hs b/govtool/backend/src/VVA/Proposal.hs index b68074e0..bc9fb6a2 100644 --- a/govtool/backend/src/VVA/Proposal.hs +++ b/govtool/backend/src/VVA/Proposal.hs @@ -64,53 +64,7 @@ getProposals :: (Has ConnectionPool r, Has VVAConfig r, MonadReader r m, MonadIO m, MonadFail m, MonadError AppError m) => Maybe [Text] -> m [Proposal] -getProposals mProposalIds = withPool $ \conn -> do - proposalResults <- liftIO $ case mProposalIds of +getProposals mProposalIds = withPool $ \conn -> + liftIO $ case mProposalIds of Nothing -> SQL.query @(Bool, SQL.In [Text]) conn listProposalsSql (False, SQL.In []) Just proposalIds -> SQL.query conn listProposalsSql (True, SQL.In proposalIds) - - timeZone <- liftIO getCurrentTimeZone - return $ map - ( \( id' - , txHash' - , index' - , type' - , details' - , expiryDate' - , expiryEpochNo' - , createdDate' - , createdEpochNo' - , url' - , docHash' - , title' - , about' - , motivation' - , rationale' - , yesVotes' - , noVotes' - , abstainVotes' - ) -> - let eDate = localTimeToUTC timeZone <$> expiryDate' - cDate = localTimeToUTC timeZone createdDate' - in - Proposal - id' - txHash' - (floor @Scientific index') - type' - details' - eDate - expiryEpochNo' - cDate - createdEpochNo' - url' - docHash' - title' - about' - motivation' - rationale' - (floor @Scientific yesVotes') - (floor @Scientific noVotes') - (floor @Scientific abstainVotes') - ) - proposalResults diff --git a/govtool/backend/src/VVA/Types.hs b/govtool/backend/src/VVA/Types.hs index c23eae9f..d3965ff3 100644 --- a/govtool/backend/src/VVA/Types.hs +++ b/govtool/backend/src/VVA/Types.hs @@ -3,6 +3,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE TypeApplications #-} module VVA.Types where @@ -18,9 +19,11 @@ import qualified Data.Cache as Cache import Data.Has import Data.Pool (Pool) import Data.Text (Text) -import Data.Time (UTCTime) +import Data.Time (UTCTime, LocalTime) +import Data.Scientific import Database.PostgreSQL.Simple (Connection) +import Database.PostgreSQL.Simple.FromRow import VVA.Cache import VVA.Config @@ -81,6 +84,13 @@ data DRepInfo , dRepInfoDRepRetireTx :: Maybe Text , dRepInfoSoleVoterRegisterTx :: Maybe Text , dRepInfoSoleVoterRetireTx :: Maybe Text + , dRepInfoPaymentAddress :: Maybe Text + , dRepInfoGivenName :: Maybe Text + , dRepInfoObjectives :: Maybe Text + , dRepInfoMotivations :: Maybe Text + , dRepInfoQualifications :: Maybe Text + , dRepInfoImageUrl :: Maybe Text + , dRepInfoImageHash :: Maybe Text } data DRepStatus = Active | Inactive | Retired deriving (Eq, Ord) @@ -99,31 +109,78 @@ data DRepRegistration , dRepRegistrationType :: DRepType , dRepRegistrationLatestTxHash :: Maybe Text , dRepRegistrationLatestRegistrationDate :: UTCTime + , dRepRegistrationPaymentAddress :: Maybe Text + , dRepRegistrationGivenName :: Maybe Text + , dRepRegistrationObjectives :: Maybe Text + , dRepRegistrationMotivations :: Maybe Text + , dRepRegistrationQualifications :: Maybe Text + , dRepRegistrationImageUrl :: Maybe Text + , dRepRegistrationImageHash :: Maybe Text } data Proposal = Proposal - { proposalId :: Integer - , proposalTxHash :: Text - , proposalIndex :: Integer - , proposalType :: Text - , proposalDetails :: Maybe Value - , proposalExpiryDate :: Maybe UTCTime - , proposalExpiryEpochNo :: Maybe Integer - , proposalCreatedDate :: UTCTime - , proposalCreatedEpochNo :: Integer - , proposalUrl :: Text - , proposalDocHash :: Text - , proposalTitle :: Maybe Text - , proposalAbstract :: Maybe Text - , proposalMotivation :: Maybe Text - , proposalRationale :: Maybe Text - , proposalYesVotes :: Integer - , proposalNoVotes :: Integer - , proposalAbstainVotes :: Integer + { proposalId :: Integer + , proposalTxHash :: Text + , proposalIndex :: Integer + , proposalType :: Text + , proposalDetails :: Maybe Value + , proposalExpiryDate :: Maybe LocalTime + , proposalExpiryEpochNo :: Maybe Integer + , proposalCreatedDate :: LocalTime + , proposalCreatedEpochNo :: Integer + , proposalUrl :: Text + , proposalDocHash :: Text + , proposalProtocolParams :: Maybe Value + , proposalTitle :: Maybe Text + , proposalAbstract :: Maybe Text + , proposalMotivation :: Maybe Text + , proposalRationale :: Maybe Text + , proposalDRepYesVotes :: Integer + , proposalDRepNoVotes :: Integer + , proposalDRepAbstainVotes :: Integer + , proposalPoolYesVotes :: Integer + , proposalPoolNoVotes :: Integer + , proposalPoolAbstainVotes :: Integer + , proposalCcYesVotes :: Integer + , proposalCcNoVotes :: Integer + , proposalCcAbstainVotes :: Integer + , proposalPrevGovActionIndex :: Maybe Integer + , proposalPrevGovActionTxHash :: Maybe Text } deriving (Show) +instance FromRow Proposal where + fromRow = + Proposal + <$> field + <*> field + <*> (floor @Scientific <$> field) + <*> field + <*> field + <*> field + <*> field + <*> field + <*> field + <*> field + <*> field + <*> field + <*> field + <*> field + <*> field + <*> field + <*> (floor @Scientific <$> field) + <*> (floor @Scientific <$> field) + <*> (floor @Scientific <$> field) + <*> (floor @Scientific <$> field) + <*> (floor @Scientific <$> field) + <*> (floor @Scientific <$> field) + <*> (floor @Scientific <$> field) + <*> (floor @Scientific <$> field) + <*> (floor @Scientific <$> field) + <*> field + <*> field + data TransactionStatus = TransactionConfirmed | TransactionUnconfirmed data CacheEnv diff --git a/govtool/backend/vva-be.cabal b/govtool/backend/vva-be.cabal index 022b13ac..97e5c569 100644 --- a/govtool/backend/vva-be.cabal +++ b/govtool/backend/vva-be.cabal @@ -1,6 +1,6 @@ cabal-version: 3.6 name: vva-be -version: 1.0.13 +version: 1.0.17 -- A short (one-line) description of the package. -- synopsis: diff --git a/govtool/frontend/index.html b/govtool/frontend/index.html index e3ff6728..8032b4a3 100644 --- a/govtool/frontend/index.html +++ b/govtool/frontend/index.html @@ -10,7 +10,7 @@ rel="stylesheet" /> - Voltaire Govtool + Cardano Govtool