diff --git a/.github/workflows/scratch-deploy-local.yml b/.github/workflows/scratch-deploy-local.yml new file mode 100644 index 000000000..af13cbf1e --- /dev/null +++ b/.github/workflows/scratch-deploy-local.yml @@ -0,0 +1,55 @@ +name: Scratch deploy on local clean anvil + +on: + pull_request: + branches: [master, develop] + +jobs: + do-scratch-deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Start anvil in background + # For the port see port in scripts/scratch/dao-local-deploy.sh in RPC_URL env var + run: anvil -p 8555 --mnemonic "test test test test test test test test test test test junk" & + + - name: Setup node.js version + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT + + - name: Cache yarn cache + id: cache-yarn-cache + uses: actions/cache@v3 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: yarn-${{ hashFiles('**/yarn.lock') }} + + - name: Cache node_modules + id: cache-node-modules + uses: actions/cache@v3 + with: + path: '**/node_modules' + key: node_modules-${{ hashFiles('**/yarn.lock') }} + restore-keys: node_modules-${{ hashFiles('**/yarn.lock') }} + + - name: Install modules + run: yarn + if: | + steps.cache-yarn-cache.outputs.cache-hit != 'true' || + steps.cache-node-modules.outputs.cache-hit != 'true' + + - name: Run local deploy script + run: bash scripts/scratch/dao-local-deploy.sh diff --git a/.gitignore b/.gitignore index 488417b46..e90d847e4 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ foundry/out/ # Extracted ABI files lib/abi/*.json +# Sensitive data .env accounts.json deployed-local.json diff --git a/apps/simple-dvt/README.md b/apps/simple-dvt/README.md new file mode 100644 index 000000000..994a366dc --- /dev/null +++ b/apps/simple-dvt/README.md @@ -0,0 +1,80 @@ +# StakingRouter Aragon App + +This directory contains source files for the [StakingRouter Aragon frontend app](https://mainnet.lido.fi/#/lido-dao/0x55032650b14df07b85bf18a3a3ec8e0af2e028d5/). + +## Verifying source code + +To verify that the StakingRouter app frontend was built from this source code, please follow instructions below. + +### Prerequisites + +- git +- Node.js 16.14.2 +- ipfs 0.19.0 + +### 1. Replicating IPFS hash and content URI + +Clone the Lido DAO repo, + +```bash +git clone https://github.com/lidofinance/lido-dao.git +``` + +Go into the directory, + +```bash +cd lido-dao +``` + +Checkout [this commit](https://github.com/lidofinance/lido-dao/commit/34f5d0d428fcb51aae74f0cb7387b9bd59916817) (the latest `yarn.lock` update for the StakingRouter app), + +```bash +git checkout 34f5d0d428fcb51aae74f0cb7387b9bd59916817 +``` + +Install dependencies **without updating the lockfile**. This will make sure that you're using the same versions of the dependencies that were used to develop the app, + +```bash +yarn install --immutable +``` + +Build the static assets for the app, + +```bash +# legacy app name +export APPS=simple-dvt +npx hardhat run scripts/build-apps-frontend.js +``` + +Get the IPFS hash of the build folder, + +```bash +ipfs add -qr --only-hash apps/simple-dvt/dist/ | tail -n 1 +``` + +This command should output `QmaSSujHCGcnFuetAPGwVW5BegaMBvn5SCsgi3LSfvraSo`. + +Now we have to obtain the content URI, which is this hash encoded for Aragon. + +Now we run the script, + +```bash +export IPFS_HASH=QmaSSujHCGcnFuetAPGwVW5BegaMBvn5SCsgi3LSfvraSo +npx hardhat run scripts/helpers/getContentUri.js +``` + +This command should print `0x697066733a516d54346a64693146684d454b5576575351316877786e33365748394b6a656743755a7441684a6b6368526b7a70`, which is our content URI. + +### 2. Verifying on-chain StakingRouter App content URI + +Open the [NodeOperatorsRegistry App Repo](https://etherscan.io/address/0x0D97E876ad14DB2b183CFeEB8aa1A5C788eB1831#readProxyContract) and scroll down to `getLatest` method, open the dropdown and click "Query". This will give you the NodeOperatorsRegistry app version, contract address and the content URI. Now check that the content URI that you've obtained in the previous step matches the one that Etherscan fetched for you from the contract. + +### 3. Verifying client-side resources + +Now that we have the IPFS hash and content URI, let's see that it is, in fact, the one that's used on the DAO website. + +Open the [StakingRouter app](https://mainnet.lido.fi/#/lido-dao/0x55032650b14df07b85bf18a3a3ec8e0af2e028d5/) in your browser, then open the network inspector and refresh the page to track all of the network requests that the website makes. + +You will find that one of the two HTML files has, in fact, been loaded from `https://ipfs.mainnet.fi/ipfs/QmaSSujHCGcnFuetAPGwVW5BegaMBvn5SCsgi3LSfvraSo/index.html`. + +You are done! ✨ diff --git a/apps/simple-dvt/app/.babelrc b/apps/simple-dvt/app/.babelrc new file mode 100644 index 000000000..13d2b95a1 --- /dev/null +++ b/apps/simple-dvt/app/.babelrc @@ -0,0 +1,30 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "modules": false, + "targets": { + "browsers": [ + "> 1%", + "last 3 versions", + "ie >= 9", + "ios >= 8", + "android >= 4.2" + ] + }, + "useBuiltIns": "entry", + "corejs": 3, + "shippedProposals": true, + } + ] + ], + "plugins": [ + [ + "styled-components", + { + "displayName": true + } + ] + ] +} diff --git a/apps/simple-dvt/app/.eslintrc b/apps/simple-dvt/app/.eslintrc new file mode 100644 index 000000000..0f19e1dc6 --- /dev/null +++ b/apps/simple-dvt/app/.eslintrc @@ -0,0 +1,21 @@ +{ + "env": { + "browser": true, + "es6": true + }, + "extends": [ + "standard", + "standard-react", + "plugin:prettier/recommended", + "prettier/react" + ], + "parser": "babel-eslint", + "plugins": ["prettier", "react", "react-hooks"], + "rules": { + "valid-jsdoc": "error", + "react/prop-types": 0, + "linebreak-style": ["error", "unix"], + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn" + } +} diff --git a/apps/simple-dvt/app/.gitignore b/apps/simple-dvt/app/.gitignore new file mode 100644 index 000000000..383b8ed65 --- /dev/null +++ b/apps/simple-dvt/app/.gitignore @@ -0,0 +1,31 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# cache +.cache + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build +/dist + +# misc +.env +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# built assets +/public/aragon-ui +/public/script.js +/public/script.map diff --git a/apps/simple-dvt/app/.prettierrc b/apps/simple-dvt/app/.prettierrc new file mode 100644 index 000000000..5824bbabb --- /dev/null +++ b/apps/simple-dvt/app/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": true, + "semi": false, + "trailingComma": "es5", + "bracketSpacing": true, + "jsxBracketSameLine": false +} diff --git a/apps/simple-dvt/app/index.html b/apps/simple-dvt/app/index.html new file mode 100644 index 000000000..07f0586fb --- /dev/null +++ b/apps/simple-dvt/app/index.html @@ -0,0 +1,16 @@ + + + + + + + Aragon App + + + +
+ + + diff --git a/apps/simple-dvt/app/package.json b/apps/simple-dvt/app/package.json new file mode 100644 index 000000000..ddc3692cc --- /dev/null +++ b/apps/simple-dvt/app/package.json @@ -0,0 +1,50 @@ +{ + "name": "simple-dvt-frontend", + "version": "1.0.0", + "main": "src/index.js", + "dependencies": { + "@aragon/api": "^2.0.0", + "@aragon/api-react": "^2.0.0", + "@aragon/ui": "^1.7.0", + "core-js": "^3.6.5", + "formik": "^2.2.0", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "regenerator-runtime": "^0.13.7", + "styled-components": "^5.2.0", + "yup": "^0.29.3" + }, + "devDependencies": { + "@babel/core": "^7.21.0", + "@babel/preset-env": "^7.11.5", + "@babel/preset-react": "^7.10.1", + "babel-eslint": "^10.1.0", + "babel-plugin-styled-components": "^1.11.1", + "copyfiles": "^2.3.0", + "eslint": "^8.34.0", + "eslint-config-prettier": "^8.6.0", + "eslint-config-standard": "^17.0.0", + "eslint-config-standard-react": "^9.2.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.20.6", + "eslint-plugin-react-hooks": "^4.1.2", + "eslint-plugin-standard": "^5.0.0", + "parcel-bundler": "^1.12.4", + "prettier": "^2.8.4" + }, + "scripts": { + "build": "yarn sync-assets && yarn build:app && yarn build:script", + "build:app": "parcel build index.html -d ../dist/ --public-url \".\" --no-cache", + "build:script": "parcel build src/script.js --out-dir ../dist/ --no-cache", + "watch:script": "parcel watch src/script.js --out-dir ../dist/ --no-hmr", + "serve": "parcel serve index.html --out-dir ../dist/ --no-cache", + "watch": "yarn watch:script", + "sync-assets": "copy-aragon-ui-assets ../dist && copyfiles -u 1 './public/**/*' ../dist", + "start": "yarn sync-assets && yarn watch:script & yarn serve", + "dev": "yarn sync-assets && yarn watch:script & yarn serve -- --port 3012", + "dev-fallback": "bash -c 'yarn sync-assets && yarn watch:script & yarn serve --port 3012'" + } +} diff --git a/apps/simple-dvt/app/public/meta/details.md b/apps/simple-dvt/app/public/meta/details.md new file mode 100644 index 000000000..d62d03083 --- /dev/null +++ b/apps/simple-dvt/app/public/meta/details.md @@ -0,0 +1,7 @@ +An application for Aragon. + +**Features** + +- Feature \#1. +- Feature \#2. +- Feature \#3. diff --git a/apps/simple-dvt/app/public/meta/icon.svg b/apps/simple-dvt/app/public/meta/icon.svg new file mode 100644 index 000000000..546d85afe --- /dev/null +++ b/apps/simple-dvt/app/public/meta/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/simple-dvt/app/public/meta/screenshot-1.png b/apps/simple-dvt/app/public/meta/screenshot-1.png new file mode 100644 index 000000000..b7f817650 Binary files /dev/null and b/apps/simple-dvt/app/public/meta/screenshot-1.png differ diff --git a/apps/simple-dvt/app/sample.env b/apps/simple-dvt/app/sample.env new file mode 100644 index 000000000..a756aa37d --- /dev/null +++ b/apps/simple-dvt/app/sample.env @@ -0,0 +1,3 @@ +SK_LIMIT=20 +SUBGRAPH_ENDPOINT=https://holesky.lido.fi/key-checker/api/subgraph +SIGNATURE_VERIFY_ENDPOINT=https://holesky.lido.fi/key-checker/api/signature diff --git a/apps/simple-dvt/app/src/App.js b/apps/simple-dvt/app/src/App.js new file mode 100644 index 000000000..b8132766f --- /dev/null +++ b/apps/simple-dvt/app/src/App.js @@ -0,0 +1,36 @@ +import React from 'react' +import { useAragonApi, useGuiStyle } from '@aragon/api-react' +import { + Button, + Header, + Main, + Split, + SyncIndicator, + useTheme, +} from '@aragon/ui' +import { ThemeProvider } from 'styled-components' +import { SimpleDVTPrimary, SimpleDVTSecondary } from './components/SimpleDVT' + +const App = () => { + const { appState } = useAragonApi() + const { appearance } = useGuiStyle() + const { isSyncing } = appState + + console.log(appState) + + const theme = useTheme() + + return ( +
+ + +
+ } secondary={} /> + +
+ ) +} + +export default App diff --git a/apps/simple-dvt/app/src/components/AddNodeOperatorSidePanel.js b/apps/simple-dvt/app/src/components/AddNodeOperatorSidePanel.js new file mode 100644 index 000000000..f705fba8b --- /dev/null +++ b/apps/simple-dvt/app/src/components/AddNodeOperatorSidePanel.js @@ -0,0 +1,76 @@ +import { Button, GU, SidePanel } from '@aragon/ui' +import React from 'react' +import { Formik, Field } from 'formik' +import * as yup from 'yup' +import TextField from './TextField' + +const initialValues = { + name: '', + address: '', +} + +const validationSchema = yup.object().shape({ + name: yup.string().required().min(1), + address: yup.string().required().min(1), +}) + +function PanelContent({ addNodeOperatorApi, onClose }) { + const onSubmit = ({ name, address }) => { + addNodeOperatorApi(name, address) + .catch(console.error) + .finally(() => { + onClose() + }) + } + + return ( + + {({ submitForm, isSubmitting, errors, values }) => { + return ( +
{ + e.preventDefault() + submitForm() + }} + > +
+              {JSON.stringify(errors, null, 2)}
+              {JSON.stringify(values, null, 2)}
+            
+ + + +