Skip to content

Commit

Permalink
Merge pull request #137 from algorandfoundation/develop
Browse files Browse the repository at this point in the history
release: Build a Bull voting
  • Loading branch information
PhearZero authored Dec 11, 2023
2 parents 184e34a + 3b893ff commit 4db2bdb
Show file tree
Hide file tree
Showing 19 changed files with 257 additions and 471 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ jobs:
secrets:
chromatic-token: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
npm-auth-token: ${{ secrets.GITHUB_TOKEN }}
build-event-dapp:
name: Events Dapp
uses: ./.github/workflows/node-ci.yml
with:
working-directory: ./src/build-a-bull
audit-script: npm run audit --audit-level=high
secrets:
npm-auth-token: ${{ secrets.GITHUB_TOKEN }}
build-api:
name: Api
uses: ./.github/workflows/node-ci.yml
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ jobs:
pre-run-script: cd ../dapp && npm ci
compile-script: npm run typecheck
audit-script: npm run audit --audit-level=high
ci-events-dapp:
name: CI Events Dapp
uses: ./.github/workflows/node-ci.yml
with:
working-directory: ./src/build-a-bull
compile-script: npm run typecheck
audit-script: npm run audit --audit-level=high
ci-api:
name: CI API
uses: ./.github/workflows/node-ci.yml
Expand Down Expand Up @@ -75,6 +82,18 @@ jobs:
needs:
- ci-xgov-dapp
- ci-algorand
build-events-dapp:
name: Build Events Dapp
uses: ./.github/workflows/node-build-zip.yml
with:
working-directory: ./src/build-a-bull
build-path: dist
artifact-name: build-a-bull
static-site: true
static-site-env-prefix: VITE
needs:
- ci-events-dapp
- ci-algorand
build-api:
name: Build API
uses: ./.github/workflows/node-build-zip.yml
Expand All @@ -101,6 +120,7 @@ jobs:
needs:
- build-dapp
- build-xgov-dapp
- build-events-dapp
- build-infrastructure
- build-api
steps:
Expand All @@ -114,6 +134,7 @@ jobs:
BASE_DOMAIN: algorand.foundation
WEBSITE_BUILD_PATH: ${{ github.workspace }}/dapp/dist
WEBSITE_BUILD_PATH_XGOV: ${{ github.workspace }}/xgov-dapp/dist
WEBSITE_BUILD_PATH_BAB: ${{ github.workspace }}/build-a-bull/dist
API_BUILD_PATH: ${{ github.workspace }}/api/build
WEB3_STORAGE_API_TOKEN: ${{ secrets.WEB3_STORAGE_API_TOKEN }}
NODE_ENV: production
Expand All @@ -123,6 +144,7 @@ jobs:
app-artifact-unzips: |-
dapp:dapp/dist
xgov-dapp:xgov-dapp/dist
build-a-bull:build-a-bull/dist
api:api/build
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_ACCESS_KEY_SECRET }}
Expand All @@ -141,6 +163,7 @@ jobs:
VITE_NFT_EXPLORER_URL: ${{ vars.NFT_EXPLORER_URL }}
VITE_IS_TESTNET: ${{ vars.IS_TESTNET }}
VITE_XGOV_CREATOR_ALLOW_LIST: ${{ vars.XGOV_CREATOR_ALLOW_LIST_ADDRESSES }}
VITE_HACKATHON_CREATOR_ALLOW_LIST: ${{ vars.HACKATHON_CREATOR_ALLOW_LIST_ADDRESSES }}
VITE_CREATOR_ALLOW_LIST: ${{ vars.CREATOR_ALLOW_LIST_ADDRESSES }}
VITE_HIDDEN_VOTING_ROUND_IDS: ${{ vars.HIDDEN_VOTING_ROUND_IDS }}
VITE_XGOV_GOVENERS_URL: ${{ vars.XGOV_GOVENERS_URL }}
Expand All @@ -155,6 +178,7 @@ jobs:
needs:
- build-dapp
- build-xgov-dapp
- build-events-dapp
- build-infrastructure
- build-api
steps:
Expand All @@ -168,6 +192,7 @@ jobs:
BASE_DOMAIN: algorand.foundation
WEBSITE_BUILD_PATH: ${{ github.workspace }}/dapp/dist
WEBSITE_BUILD_PATH_XGOV: ${{ github.workspace }}/xgov-dapp/dist
WEBSITE_BUILD_PATH_BAB: ${{ github.workspace }}/build-a-bull/dist
API_BUILD_PATH: ${{ github.workspace }}/api/build
WEB3_STORAGE_API_TOKEN: ${{ secrets.WEB3_STORAGE_API_TOKEN }}
NODE_ENV: production
Expand All @@ -177,6 +202,7 @@ jobs:
app-artifact-unzips: |-
dapp:dapp/dist
xgov-dapp:xgov-dapp/dist
build-a-bull:build-a-bull/dist
api:api/build
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_ACCESS_KEY_SECRET }}
Expand All @@ -195,6 +221,7 @@ jobs:
VITE_NFT_EXPLORER_URL: ${{ vars.NFT_EXPLORER_URL }}
VITE_IS_TESTNET: ${{ vars.IS_TESTNET }}
VITE_XGOV_CREATOR_ALLOW_LIST: ${{ vars.XGOV_CREATOR_ALLOW_LIST_ADDRESSES }}
VITE_HACKATHON_CREATOR_ALLOW_LIST: ${{ vars.HACKATHON_CREATOR_ALLOW_LIST_ADDRESSES }}
VITE_CREATOR_ALLOW_LIST: ${{ vars.CREATOR_ALLOW_LIST_ADDRESSES }}
VITE_HIDDEN_VOTING_ROUND_IDS: ${{ vars.HIDDEN_VOTING_ROUND_IDS }}
VITE_XGOV_GOVENERS_URL: ${{ vars.XGOV_GOVENERS_URL }}
Expand Down
66 changes: 46 additions & 20 deletions infrastructure/bin/infrastructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const deployer = new CDKDeployer({
const appDomainName = deployer.getEnvPrefixedDomainName(`voting.${process.env.BASE_DOMAIN}`)
const apiDomainName = `api.${appDomainName}`
const xGovAppDomainName = deployer.getEnvPrefixedDomainName(`xgov.${process.env.BASE_DOMAIN}`)
const eventsAppDomainName = deployer.getEnvPrefixedDomainName(`bab.${process.env.BASE_DOMAIN}`)

const apiCertificateRequest: CertificateRequest = {
isWildCard: false,
Expand All @@ -25,30 +26,44 @@ const apiCertificateRequest: CertificateRequest = {

const dns = appDomainName
? deployer.deploy(
DnsStack,
'dns-web',
{
domainName: appDomainName,
generateCertificate: true,
parameterRegions: [deployer.defaultRegion],
certificateRequests: [DnsStack.ROOT_CERT_REQUEST, apiCertificateRequest],
},
'us-east-1',
)
DnsStack,
'dns-web',
{
domainName: appDomainName,
generateCertificate: true,
parameterRegions: [deployer.defaultRegion],
certificateRequests: [DnsStack.ROOT_CERT_REQUEST, apiCertificateRequest],
},
'us-east-1',
)
: undefined

const xGovDns = xGovAppDomainName
? deployer.deploy(
DnsStack,
'dns-xgovweb',
{
domainName: xGovAppDomainName,
generateCertificate: true,
parameterRegions: [deployer.defaultRegion],
certificateRequests: [DnsStack.ROOT_CERT_REQUEST],
},
'us-east-1',
)
DnsStack,
'dns-xgovweb',
{
domainName: xGovAppDomainName,
generateCertificate: true,
parameterRegions: [deployer.defaultRegion],
certificateRequests: [DnsStack.ROOT_CERT_REQUEST],
},
'us-east-1',
)
: undefined

const eventsDns = eventsAppDomainName
? deployer.deploy(
DnsStack,
'dns-eventsweb',
{
domainName: eventsAppDomainName,
generateCertificate: true,
parameterRegions: [deployer.defaultRegion],
certificateRequests: [DnsStack.ROOT_CERT_REQUEST],
},
'us-east-1',
)
: undefined

const responseHeaders: ResponseHeadersPolicyProps = {
Expand Down Expand Up @@ -119,6 +134,13 @@ const xGovApp = deployer.deploy(StaticWebsiteStack, 'xgovweb', {
responseHeaders: responseHeaders,
})

const eventsApp = deployer.deploy(StaticWebsiteStack, 'eventweb', {
websiteFolder: process.env.WEBSITE_BUILD_PATH_BAB ?? path.join(__dirname, '..', '..', 'src', 'build-a-bull', 'dist'),
websiteNpmBuildCommand: 'build-events-dapp',
customDomain: eventsDns?.getDefaultCustomDomainProps(deployer.defaultRegion, eventsAppDomainName),
responseHeaders: responseHeaders,
})

if (dns) {
app.addDependency(dns)
api.addDependency(dns)
Expand All @@ -127,3 +149,7 @@ if (dns) {
if (xGovDns) {
xGovApp.addDependency(xGovDns)
}

if (eventsDns) {
eventsApp.addDependency(eventsDns)
}
13 changes: 7 additions & 6 deletions infrastructure/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@
"build": "npm run clean && tsc && copyfiles package.json package-lock.json cdk.json build && cd build && npm ci --omit=dev && json -I -f cdk.json -e \"this.app='node bin/infrastructure.js'\"",
"clean": "rimraf build",
"cdk": "cdk",
"bootstrap:local": "dotenv -e .env -e ../src/dapp/.env -e ../src/xgov-dapp/.env -e ../src/voting-metadata-api/.env -- npm run bootstrap",
"bootstrap:local": "dotenv -e .env -e ../src/dapp/.env -e ../src/xgov-dapp/.env -e ../src/build-a-bull/.env -e ../src/voting-metadata-api/.env -- npm run bootstrap",
"bootstrap": "cross-env-shell npm run cdk -- bootstrap aws://$CDK_DEFAULT_ACCOUNT/$AWS_DEFAULT_REGION && cross-env-shell npm run cdk -- bootstrap aws://$CDK_DEFAULT_ACCOUNT/us-east-1",
"diff:local": "dotenv -e .env -e ../src/dapp/.env -e ../src/xgov-dapp/.env -e ../src/voting-metadata-api/.env -- npm run diff",
"diff:local": "dotenv -e .env -e ../src/dapp/.env -e ../src/xgov-dapp/.env -e ../src/build-a-bull/.env -e ../src/voting-metadata-api/.env -- npm run diff",
"diff": "npm run cdk -- diff",
"deploy:local": "dotenv -e .env -e ../src/dapp/.env -e ../src/xgov-dapp/.env -e ../src/voting-metadata-api/.env -- npm run deploy && npm run set-secrets:local",
"deploy:local": "dotenv -e .env -e ../src/dapp/.env -e ../src/xgov-dapp/.env -e ../src/build-a-bull/.env -e ../src/voting-metadata-api/.env -- npm run deploy && npm run set-secrets:local",
"deploy": "npm run cdk -- deploy \"*\" --ci --require-approval never --outputs-file ./cdk-outputs.json",
"destroy:local": "dotenv -e .env -e ../src/dapp/.env -e ../src/xgov-dapp/.env -e ../src/voting-metadata-api/.env -- npm run cdk -- destroy --all",
"graph:local": "cross-env NO_BUILD=true dotenv -e .env -e ../src/xgov-dapp/.env -e ../src/dapp/.env -e ../src/voting-metadata-api/.env -- npm run graph && move-cli diagram.png ../docs/stack.png",
"destroy:local": "dotenv -e .env -e ../src/dapp/.env -e ../src/xgov-dapp/.env -e ../src/build-a-bull/.env -e ../src/voting-metadata-api/.env -- npm run cdk -- destroy --all",
"graph:local": "cross-env NO_BUILD=true dotenv -e .env -e ../src/xgov-dapp/.env -e ../src/build-a-bull/.env -e ../src/dapp/.env -e ../src/voting-metadata-api/.env -- npm run graph && move-cli diagram.png ../docs/stack.png",
"graph": "npm run cdk -- synth --context environment=env && npx cdk-dia",
"set-secrets:local": "dotenv -e .env -e ../src/dapp/.env -e ../src/xgov-dapp/.env -e ../src/voting-metadata-api/.env -- ts-node lib/set-aws-secrets.ts",
"set-secrets:local": "dotenv -e .env -e ../src/dapp/.env -e ../src/xgov-dapp/.env -e ../src/build-a-bull/.env -e ../src/voting-metadata-api/.env -- ts-node lib/set-aws-secrets.ts",
"set-secrets": "node lib/set-aws-secrets.js",
"build-dapp": "cd ../src/dapp/ && npm run build",
"build-xgov-dapp": "cd ../src/xgov-dapp/ && npm run build",
"build-events-dapp": "cd ../src/build-a-bull/ && npm run build",
"build-api": "cd ../src/voting-metadata-api && npm run build",
"format": "prettier --write .",
"audit:resolve": "resolve-audit",
Expand Down
2 changes: 1 addition & 1 deletion src/build-a-bull/src/components/siteHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import algorandFoundationLogo from '../assets/algorand-foundation-logo.svg'
import { useConnectedWallet, useCreatorAddresses, useSetShowConnectWalletModal } from '../features/wallet/state'
import { getWalletLabel } from '../shared/wallet'
import { MenuIcon, XIcon } from './icons'
import { forwardRef } from "react";
import { forwardRef } from 'react'

interface Link {
name: string
Expand Down
2 changes: 1 addition & 1 deletion src/build-a-bull/src/features/rounds/VotingRoundTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export const VotingRoundTile = ({ globalState, votingRoundStatus }: VotingRoundT
/>
</div>
<div>
<VotingStats isLoading={isLoadingSnapshot} votingRoundGlobalState={globalState} snapshot={snapshot} />
<VotingStats votingRoundGlobalState={globalState} isLoading={isLoadingMetadata || isLoadingVotingRoundResults} />
</div>
<div>
<VotingTime globalState={globalState} loading={false} className="lg:visible" />
Expand Down
6 changes: 3 additions & 3 deletions src/build-a-bull/src/features/rounds/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,23 @@ const VotingRounds = () => {
const openRounds = globalStates
? getRounds(
globalStates,
(r) => getHasVoteStarted(r) && !getHasVoteEnded(r) && r.vote_type == VoteType.PARTITIONED_WEIGHTING,
(r) => getHasVoteStarted(r) && !getHasVoteEnded(r) && r.vote_type == VoteType.NO_SNAPSHOT,
(r: VotingRoundGlobalState) => r.end_time,
)
: []

const upcomingRounds = globalStates
? getRounds(
globalStates,
(r) => !getHasVoteStarted(r) && !getHasVoteEnded(r) && r.vote_type == VoteType.PARTITIONED_WEIGHTING,
(r) => !getHasVoteStarted(r) && !getHasVoteEnded(r) && r.vote_type == VoteType.NO_SNAPSHOT,
(r: VotingRoundGlobalState) => r.start_time,
)
: []

const closedRounds = globalStates
? getRounds(
globalStates,
(r) => getHasVoteEnded(r) && r.vote_type == VoteType.PARTITIONED_WEIGHTING,
(r) => getHasVoteEnded(r) && r.vote_type == VoteType.NO_SNAPSHOT,
(r: VotingRoundGlobalState) => r.end_time,
)
: []
Expand Down
69 changes: 0 additions & 69 deletions src/build-a-bull/src/features/vote-creation/RoundInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { ValidatedForm, z, zfd } from '@makerx/forms-mui'
import { Typography } from '@mui/material'
import { decodeAddress } from 'algosdk'
import dayjs from 'dayjs'
import Papa from 'papaparse'
import { useNavigate } from 'react-router-dom'
import { SnapshotRow } from '@/shared/csvSigner'
import { useRoundInfo, useSetRoundInfo } from './state'

export type Proposal = {
Expand All @@ -23,9 +21,7 @@ const formSchema = zfd.formData({
voteInformationUrl: zfd.text(z.string().trim().url().optional()),
start: zfd.text(),
end: zfd.text(),
communityGrantAllocation: zfd.numeric(z.number().positive().min(1, 'Must be at least 1')),
proposalFile: zfd.text(z.string().trim().min(1, 'Required').superRefine(validateProposalCsv)),
snapshotFile: zfd.text(z.string().trim().min(1, 'Required').superRefine(validateSnapshotCsv)),
})

function validateProposalCsv(value: string, ctx: z.RefinementCtx) {
Expand Down Expand Up @@ -69,59 +65,6 @@ function validateProposalCsv(value: string, ctx: z.RefinementCtx) {
})
}

function validateSnapshotCsv(value: string, ctx: z.RefinementCtx) {
const parsed = Papa.parse<SnapshotRow>(value, { header: true, delimiter: ',' })
const requiredFields = ['address', 'weight']
if (parsed.errors.length > 0) {
parsed.errors.forEach((error) => {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `${error.message} ` + `on row: ${error.row + 1}`,
})
})
}
if (parsed.meta.fields) {
if (
!requiredFields.every((field) => {
return parsed.meta.fields && parsed.meta.fields.includes(field)
})
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `The csv must have a header row with the following fields: ${requiredFields.join(', ')}`,
})
}
}
if (parsed.data.length <= 0) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'No addresses found',
})
}
parsed.data.forEach((row, index) => {
try {
decodeAddress(row.address)
} catch (e) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `The address on row: ${index + 1} is not valid`,
})
}
if (!row.weight) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `The address on row: ${index + 1} has no weight associated with it`,
})
}
if (isNaN(Number(row.weight)) || Number(row.weight) === 0) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `The address on row: ${index + 1} has an invalid weight associated with it`,
})
}
})
}

export type Fields = z.infer<typeof formSchema>

export default function RoundInfo() {
Expand Down Expand Up @@ -169,25 +112,13 @@ export default function RoundInfo() {
fromISO: (date) => dayjs(date) as unknown as Date,
})}
</div>
{helper.textField({
label: 'Community grant allocation',
field: 'communityGrantAllocation',
hint: 'Amount of microALGO to allocate to the community grant pool',
})}
{helper.textFileFormField({
label: 'Proposals',
field: 'proposalFile',
hint: 'Upload a .csv file',
longHint:
'Upload a CSV file with 5 columns containing the proposals. The headers should be "title", "description", "link", "category", "threshold"',
})}
{helper.textFileFormField({
label: 'Allowlist snapshot file',
field: 'snapshotFile',
hint: 'Upload snapshot .csv file',
longHint:
'Upload a CSV file with 2 columns containing the addresses and weights for the allowlist. The headers should be "address" and "weight".',
})}
<div className="text-right">{helper.submitButton({ label: 'Next', className: 'mt-8' })}</div>
</>
)}
Expand Down
Loading

0 comments on commit 4db2bdb

Please sign in to comment.