Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
58162bb
feat: add image validation for dRep form
kneerose May 6, 2025
7b3c3f7
fix: wrong env and its value on env.example
kneerose May 7, 2025
44ad7bc
docs: update readme for network and faucet
kneerose May 7, 2025
588c66d
Merge pull request #3584 from IntersectMBO/feat/add-network-wallet-fu…
kneerose May 7, 2025
f282593
Merge pull request #3575 from IntersectMBO/feat/dRep-form-image-valid…
kneerose May 7, 2025
c87a1f5
feat: add budgetProposal05 wallet and its auth file references
kneerose May 8, 2025
ca9fa5b
tests: verify created proposal in my proposal list filter
kneerose May 8, 2025
2408fb3
feat: add README for Governance Action Loader
kneerose May 8, 2025
532687a
Merge pull request #3594 from IntersectMBO/docs/gov-action-loader
kneerose May 8, 2025
5efb2dd
Merge pull request #3593 from IntersectMBO/tests/filter-by-my-proposal
kneerose May 8, 2025
07db866
fix(#3591): remove canonicalization from the governance action metadata
MSzalowski May 8, 2025
c7ba100
chore: update @intersect.mbo/pdf-ui to 0.7.0-beta-26
github-actions[bot] May 8, 2025
1a17177
Merge pull request #3596 from IntersectMBO/chore/@intersect.mbo/pdf-u…
MSzalowski May 8, 2025
db265c8
chore: switch into npm in metadata validation dockerfile
MSzalowski May 8, 2025
b5b8072
Merge pull request #3595 from IntersectMBO/workaround/3591-bug-govtoo…
MSzalowski May 8, 2025
30b5e32
Merge pull request #3597 from IntersectMBO/chore/switch-into-npm-for-…
MSzalowski May 8, 2025
d296ac4
Merge pull request #3598 from IntersectMBO/develop
MSzalowski May 8, 2025
97b4925
Merge pull request #3599 from IntersectMBO/test
MSzalowski May 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ changes.

### Removed

- Remove additional canonicalization of the metadata [Issue 3591](https://github.com/IntersectMBO/govtool/issues/3591)

## [v2.0.20](https://github.com/IntersectMBO/govtool/releases/tag/v2.0.20) 2025-04-16

### Added
Expand Down
14 changes: 14 additions & 0 deletions gov-action-loader/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Governance Action Loader

This directory contains the platform for submitting governance action data transactions on-chain, supporting both individual and bulk submission methods.

## 📍 Navigation

- [Frontend](./frontend/)
- [Backend](./backend/)

## Frontend
The Governance Action Loader frontend is a web application that communicates with the backend via a REST interface to facilitate the submission of on-chain governance data transactions.

## Backend
The Governance Action Loader backend uses a predefined wallet to execute transactions for on-chain governance data.
8 changes: 4 additions & 4 deletions govtool/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion govtool/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@hookform/resolvers": "^3.3.1",
"@intersect.mbo/govtool-outcomes-pillar-ui": "1.4.1",
"@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8",
"@intersect.mbo/pdf-ui": "0.7.0-beta-25",
"@intersect.mbo/pdf-ui": "0.7.0-beta-26",
"@mui/icons-material": "^5.14.3",
"@mui/material": "^5.14.4",
"@rollup/plugin-babel": "^6.0.4",
Expand Down
8 changes: 4 additions & 4 deletions govtool/frontend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1512,10 +1512,10 @@
resolved "https://registry.npmjs.org/@intersect.mbo/intersectmbo.org-icons-set/-/intersectmbo.org-icons-set-1.1.0.tgz"
integrity sha512-sjKEtnK9eLYH/8kCD0YRQCms3byFA/tnSsei9NHTZbBYX9sBpeX6ErfR0sKYjOSxQOxl4FumX9D0X+vHIqxo8g==

"@intersect.mbo/pdf-ui@0.7.0-beta-25":
version "0.7.0-beta-25"
resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-25.tgz"
integrity sha512-TDeWjJVMvLOR6sgTT6bCoHspZbybiRH0C5OzDDaU1yLSFD7xKx1aW5eAVdG0uzxrO+C0X7ceBGFoN5ucHICdlg==
"@intersect.mbo/pdf-ui@0.7.0-beta-26":
version "0.7.0-beta-26"
resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-26.tgz"
integrity sha512-05HR82ZKpJzitH7MgdNEdGr/Rc9A8PNPfPF5bX/z4We2y+iSi5kEoZdflpaUUWG3fFDwiaQCKe2xMiNwbGMOIQ==
dependencies:
"@emurgo/cardano-serialization-lib-asmjs" "^12.0.0-beta.2"
"@fontsource/poppins" "^5.0.14"
Expand Down
6 changes: 3 additions & 3 deletions govtool/metadata-validation/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ WORKDIR /dist

COPY package*.json ./

RUN yarn
RUN npm install

COPY . /dist

RUN yarn build
RUN npm run build

ENV IPFS_GATEWAY=$IPFS_GATEWAY
ENV IPFS_PROJECT_ID=$IPFS_PROJECT_ID

ENTRYPOINT ["/bin/sh", "-c", "yarn start:prod"]
ENTRYPOINT ["/bin/sh", "-c", "npm run start:prod"]
25 changes: 1 addition & 24 deletions govtool/metadata-validation/src/app.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common';
import { catchError, finalize, firstValueFrom } from 'rxjs';
import { HttpService } from '@nestjs/axios';
import * as blake from 'blakejs';
import * as jsonld from 'jsonld';

import { ValidateMetadataDTO } from '@dto';
import { LoggerMessage, MetadataValidationStatus } from '@enums';
Expand Down Expand Up @@ -81,29 +80,7 @@ export class AppService {
const hashedMetadata = blake.blake2bHex(rawData, undefined, 32);

if (hashedMetadata !== hash) {
// Optionally validate on a parsed metadata
const hashedParsedMetadata = blake.blake2bHex(
JSON.stringify(parsedData, null, 2),
undefined,
32,
);
if (hashedParsedMetadata !== hash) {
// Optional support for the canonized data hash
// Validate canonized data hash
const canonizedMetadata = await jsonld.canonize(JSON.parse(rawData), {
safe: false,
});

const hashedCanonizedMetadata = blake.blake2bHex(
canonizedMetadata,
undefined,
32,
);

if (hashedCanonizedMetadata !== hash) {
throw MetadataValidationStatus.INVALID_HASH;
}
}
throw MetadataValidationStatus.INVALID_HASH;
}
} catch (error) {
Logger.error(LoggerMessage.METADATA_VALIDATION_ERROR, error);
Expand Down
6 changes: 4 additions & 2 deletions tests/govtool-frontend/playwright/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
HOST_URL=http://localhost:3000

DOCS_URL=https://docs.gov.tools
DOCS_URL=https://docs.gov.tools/cardano-govtool

#Blockfrost
BLOCKFROST_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXX
Expand All @@ -12,7 +12,9 @@ KUBER_API_KEY=
TX_TIMEOUT=240000 # milliseconds

# Metadata Bucket
METADATA_BUCKET_URL=https://metadata-govtool.cardanoapi.io
CARDANOAPI_METADATA_URL=https://metadata-govtool.cardanoapi.io

NETWORK=preview

FAUCET_ADDRESS=
FAUCET_PAYMENT_PRIVATE=
Expand Down
44 changes: 30 additions & 14 deletions tests/govtool-frontend/playwright/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ npx playwright install

### HOST URL

| Environment | URL |
| :---------- | :----------------------------------------------------------------------------------------------------------------------- |
| Development | [https://p80-z78acf3c2-zded6a792-gtw.z937eb260.rustrocks.fr](https://p80-z78acf3c2-zded6a792-gtw.z937eb260.rustrocks.fr) |
| QA | [https://govtool.cardanoapi.io](https://govtool.cardanoapi.io) |
| Preview | [https://preview.gov.tools](https://preview.gov.tools) |
| Pre-Prod | [https://pre-prod.gov.tools](https://pre-prod.gov.tools) |
| Mainnet | [https://gov.tools](https://gov.tools) |
| Environment | URL | Network |
| :---------- | :----------------------------------------------------------------------------------------------------------------------- | :------ |
| Development | [https://p80-z78acf3c2-zded6a792-gtw.z937eb260.rustrocks.fr](https://p80-z78acf3c2-zded6a792-gtw.z937eb260.rustrocks.fr) | Preview |
| QA | [https://govtool.cardanoapi.io](https://govtool.cardanoapi.io) | Preview |
| Preview | [https://preview.gov.tools](https://preview.gov.tools) | Preview |
| Pre-Prod | [https://pre-prod.gov.tools](https://pre-prod.gov.tools) | Preprod |
| Mainnet | [https://gov.tools](https://gov.tools) | Mainnet |

---

Expand All @@ -66,16 +66,21 @@ npx playwright install
### Blockfrost API Key

- To generate a Blockfrost API key (Project ID):
1. Follow the instructions in the [Blockfrost documentation](https://blockfrost.dev/overview/getting-started).

1. Follow the instructions in the [Blockfrost documentation](https://blockfrost.dev/overview/getting-started) 📚.
2. The **Project ID** you create there serves as your **Blockfrost API Key**.
3. Copy the **Project ID** and set it as `BLOCKFROST_API_KEY`.

🔐 Note: Ensure you select the correct network for the **Project ID** that matches the host URL from the environment listed above.

### Kuber API Key

- To generate a Kuber API Key:
1. Visit [Kuberide](https://kuberide.com/).
1. Visit [Kuberide](https://kuberide.com/) 🌐.
2. Log in using your Google or GitHub account.
3. Navigate to **API Keys**.
4. Click to **Generate API Key**.
3. Navigate to **API Keys** ⚙️.
4. Click to **Generate API Key** ✨.
5. Copy the API key and set it as `KUBER_API_KEY`

---

Expand Down Expand Up @@ -127,15 +132,26 @@ FAUCET_ADDRESS=<your-wallet-address>

### Step 3: Fund the Wallet

Ensure the wallet address has sufficient funds for your test runs. The required balance depends on the specific tests you plan to execute (refer to the test-specific test run details below).
Ensure your wallet has enough funds for your test runs. The required balance depends on the specific tests you plan to execute (see test-specific details below).

To fund your wallet on the **Preview** or **Preprod** network:

1. Use the Cardano Testnet Faucet:
[https://docs.cardano.org/cardano-testnets/tools/faucet](https://docs.cardano.org/cardano-testnets/tools/faucet) 🌐
**Note**: There is a daily limit of **10,000 ADA** per wallet.

2. If the funded amount is insufficient, transfer additional ADA from another wallet. 💸

To check your wallet balance:

To check the wallet balance, visit:
Visit:

```
https://${network}.cardanoscan.io/address/<your-wallet-address>
```

Replace `${network}` with the appropriate Cardano network (e.g.`preprod`, or `preview`) and `<your-wallet-address>` with the generated address.
- Replace `${network}` with the appropriate network (e.g., `preprod` or `preview`).
- Replace `<your-wallet-address>` with your wallet address. 🔍

**Example**:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ShelleyWallet } from "./lib/helpers/crypto";
console.log("\n🎉 Wallet generated successfully!");
console.log("-----------------------------------");
console.log("💼 Wallet:", walletJson);
console.log(`🔑 Payment Private Key: ${walletJson.payment.private}`);
console.log(`\n🔑 Payment Private Key: ${walletJson.payment.private}`);
console.log(`🔗 Stake Public Key Hash: ${walletJson.stake.pkh}`);
console.log(`🏠 Wallet Address: ${walletJson.address}`);
console.log("-----------------------------------");
Expand Down
1 change: 1 addition & 0 deletions tests/govtool-frontend/playwright/lib/constants/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ export const budgetProposal01AuthFile = ".auth/budgetProposal01.json";
export const budgetProposal02AuthFile = ".auth/budgetProposal02.json";
export const budgetProposal03AuthFile = ".auth/budgetProposal03.json";
export const budgetProposal04AuthFile = ".auth/budgetProposal04.json";
export const budgetProposal05AuthFile = ".auth/budgetProposal05.json";
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const budgetProposal01Wallet: StaticWallet = staticWallets[19];
export const budgetProposal02Wallet: StaticWallet = staticWallets[20];
export const budgetProposal03Wallet: StaticWallet = staticWallets[21];
export const budgetProposal04Wallet: StaticWallet = staticWallets[22];
export const budgetProposal05Wallet: StaticWallet = staticWallets[23];

export const adaHolderWallets = [
adaHolder01Wallet,
Expand Down
21 changes: 21 additions & 0 deletions tests/govtool-frontend/playwright/lib/forms/dRepForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const formErrors = {
],
linkDescription: "max-80-characters-error",
email: "invalid-email-address-error",
image: "invalid-image-url-error",
links: {
url: "link-reference-description-1-error",
description: "link-reference-description-1-error",
Expand Down Expand Up @@ -59,6 +60,9 @@ export default class DRepForm {
readonly motivationsInput = this.form.getByTestId("motivations-input");
readonly qualificationsInput = this.form.getByTestId("qualifications-input");
readonly paymentAddressInput = this.form.getByTestId("payment-address-input");
readonly imageInput = this.form.locator(
"div:nth-child(4) > div:nth-child(2) > input"
); // BUG missing test id
readonly doNotListCheckBox = this.form.getByRole("checkbox");

constructor(private readonly form: Page) {}
Expand Down Expand Up @@ -149,6 +153,7 @@ export default class DRepForm {
await this.motivationsInput.fill(dRepInfo.motivations);
await this.qualificationsInput.fill(dRepInfo.qualifications);
await this.paymentAddressInput.fill(dRepInfo.paymentAddress);
await this.imageInput.fill(dRepInfo.image);
await this.linkRefrenceFirstUrlInput.fill(
dRepInfo.linksReferenceLinks[0].url
);
Expand All @@ -175,6 +180,9 @@ export default class DRepForm {
const motivationsInputText = await this.motivationsInput.textContent();
const qualificationsInputText =
await this.qualificationsInput.textContent();
const isImageErrorVisible = await this.form
.getByTestId(formErrors.image)
.isVisible();
const isReferenceLinkErrorVisible = await this.form
.getByTestId(formErrors.links.url)
.isVisible();
Expand Down Expand Up @@ -202,6 +210,10 @@ export default class DRepForm {
`${dRepInfo.qualifications} is not equal to ${qualificationsInputText}`,
}).toEqual(dRepInfo.qualifications);

await expect(this.form.getByTestId(formErrors.image), {
message: isImageErrorVisible && `${dRepInfo.image} is an invalid image`,
}).toBeHidden();

await expect(this.form.getByTestId(formErrors.links.url), {
message:
isReferenceLinkErrorVisible &&
Expand Down Expand Up @@ -246,6 +258,9 @@ export default class DRepForm {
const motivationsInputText = await this.motivationsInput.textContent();
const qualificationsInputText =
await this.qualificationsInput.textContent();
const isImageErrorVisible = await this.form
.getByTestId(formErrors.image)
.isVisible();
const isReferenceLinkErrorVisible = await this.form
.getByTestId(formErrors.links.url)
.isVisible();
Expand Down Expand Up @@ -284,6 +299,12 @@ export default class DRepForm {
`${dRepInfo.qualifications} is equal to ${qualificationsInputText}`,
}).not.toEqual(dRepInfo.qualifications);

await expect(this.form.getByTestId(formErrors.image), {
message: !isImageErrorVisible && `${dRepInfo.image} is a valid image`,
}).toBeVisible({
timeout: 60_000,
});

await expect(this.form.getByTestId(formErrors.links.url), {
message:
!isReferenceLinkErrorVisible &&
Expand Down
14 changes: 10 additions & 4 deletions tests/govtool-frontend/playwright/lib/helpers/dRep.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import DRepDirectoryPage from "@pages/dRepDirectoryPage";
import { expect, Page } from "@playwright/test";
import { IDRep } from "@types";
import { IDRep, IDRepInfo } from "@types";
import { bech32 } from "bech32";
import * as crypto from "crypto";
import { functionWaitedAssert } from "./waitedLoop";
import { invalid as mockInvalid, valid as mockValid } from "@mock/index";
import {
invalid,
invalid as mockInvalid,
valid as mockValid,
} from "@mock/index";
import { faker } from "@faker-js/faker";
import { ShelleyWallet } from "./crypto";
import environments from "@constants/environments";
Expand Down Expand Up @@ -131,7 +135,7 @@ export function convertDRep(
return { cip129: cip129DRep, cip105: cip105DRep };
}

export async function generateValidDRepInfo() {
export async function generateValidDRepInfo(): Promise<IDRepInfo> {
return {
name: mockValid.name(),
objectives: faker.lorem.paragraph(2),
Expand All @@ -140,6 +144,7 @@ export async function generateValidDRepInfo() {
paymentAddress: (await ShelleyWallet.generate()).addressBech32(
environments.networkId
),
image: faker.image.avatarGitHub(),
linksReferenceLinks: [
{
url: faker.internet.url(),
Expand All @@ -155,13 +160,14 @@ export async function generateValidDRepInfo() {
};
}

export function generateInvalidDRepInfo() {
export function generateInvalidDRepInfo(): IDRepInfo {
return {
name: mockInvalid.name(),
objectives: faker.lorem.paragraph(40),
motivations: faker.lorem.paragraph(40),
qualifications: faker.lorem.paragraph(40),
paymentAddress: faker.string.alphanumeric(45),
image: invalid.url(),
linksReferenceLinks: [
{
url: mockInvalid.url(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default class BudgetDiscussionDetailsPage {
);
readonly verifyIdentityBtn = this.page.getByTestId("verify-identity-button");
readonly readMoreBtn = this.page.getByTestId("read-more-button");
readonly menuButton = this.page.getByTestId("menu-button");

// content
readonly copyLinkText = this.page.getByTestId("copy-link-text");
Expand Down Expand Up @@ -139,7 +140,7 @@ export default class BudgetDiscussionDetailsPage {
async deleteProposal() {
await this.page.waitForTimeout(2_000);

await this.page.getByTestId("menu-button").click();
await this.menuButton.click();
await this.page.getByTestId("delete-proposal").click();
await this.page.getByTestId("delete-proposal-yes-button").click();
}
Expand Down
Loading