diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f889017f..7e8052a6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,6 +17,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v3 + with: + submodules: recursive - name: Setup Node uses: actions/setup-node@v3 diff --git a/.gitmodules b/.gitmodules index a3706a83..3d81c6bd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,7 @@ [submodule "lib/permit2"] path = lib/permit2 url = https://github.com/Uniswap/permit2 +[submodule "lib/ubiquibot"] + path = lib/ubiquibot + url = https://github.com/ubiquity/ubiquibot + shallow = true diff --git a/lib/ubiquibot b/lib/ubiquibot new file mode 160000 index 00000000..8afd7cfa --- /dev/null +++ b/lib/ubiquibot @@ -0,0 +1 @@ +Subproject commit 8afd7cfa13e9731fb49b5f5a03f605258458d649 diff --git a/static/onboarding.html b/static/onboarding.html index 9ab078a9..23953483 100644 --- a/static/onboarding.html +++ b/static/onboarding.html @@ -33,11 +33,6 @@

Onboarding

-
- - - -
diff --git a/static/scripts/onboarding/onboarding.ts b/static/scripts/onboarding/onboarding.ts index edf013ee..fa2f7f72 100644 --- a/static/scripts/onboarding/onboarding.ts +++ b/static/scripts/onboarding/onboarding.ts @@ -1,13 +1,15 @@ -import _sodium from "libsodium-wrappers"; -import { Octokit } from "@octokit/rest"; +import { JsonRpcSigner } from "@ethersproject/providers"; import { createOrUpdateTextFile } from "@octokit/plugin-create-or-update-text-file"; -import YAML from "yaml"; -import { ethers } from "ethers"; +import { Octokit } from "@octokit/rest"; import { PERMIT2_ADDRESS } from "@uniswap/permit2-sdk"; -import { JsonRpcSigner, Network } from "@ethersproject/providers"; +import { ethers } from "ethers"; import { parseUnits } from "ethers/lib/utils"; -import { NetworkIds, Tokens, getNetworkName, networkNames } from "../rewards/constants"; +import _sodium from "libsodium-wrappers"; +import YAML from "yaml"; +import { DefaultConfig } from "../../../lib/ubiquibot/src/configs/ubiquibot-config-default"; +import { MergedConfig } from "../../../lib/ubiquibot/src/types"; import { erc20Abi } from "../rewards/abis/erc20Abi"; +import { getNetworkName, NetworkIds, Tokens } from "../rewards/constants"; const classes = ["error", "warn", "success"]; const inputClasses = ["input-warn", "input-error", "input-success"]; @@ -22,107 +24,23 @@ const chainIdSelect = document.getElementById("chainId") as HTMLSelectElement; const loader = document.querySelector(".loader-wrap") as HTMLElement; const APP_ID = 236521; -const DEFAULT_ORG = "ubiquity"; const REPO_NAME = "ubiquibot-config"; -const DEFAULT_REPO = "ubiquibot"; const KEY_PATH = ".github/ubiquibot-config.yml"; -const DEFAULT_PATH = "ubiquibot-config-default.json"; -const KEY_NAME = "private-key-encrypted"; +const PRIVATE_ENCRYPTED_KEY_NAME = "privateKeyEncrypted"; +const EVM_NETWORK_KEY_NAME = "evmNetworkId"; const KEY_PREFIX = "HSK_"; const X25519_KEY = "5ghIlfGjz_ChcYlBDOG7dzmgAgBPuTahpvTMBipSH00"; let encryptedValue = ""; -interface ConfLabel { - name: string; -} - -interface CommandLabel { - name: string; - enabled: boolean; -} - -interface IIncentive { - comment: { - elements: Record; - totals: { - word: number; - }; - }; -} - -interface IControl { - label: boolean; - organization: boolean; -} - -interface IConf { - "private-key-encrypted"?: string; - "safe-address"?: string; - "base-multiplier"?: number; - "auto-pay-mode"?: boolean; - "analytics-mode"?: boolean; - "max-concurrent-bounties"?: number; - "incentive-mode"?: boolean; - "evm-network-id"?: number; - "price-multiplier"?: number; - "issue-creator-multiplier"?: number; - "payment-permit-max-price"?: number; - "max-concurrent-assigns"?: number; - "assistive-pricing"?: boolean; - "disable-analytics"?: boolean; - "comment-incentives"?: boolean; - "register-wallet-with-verification"?: boolean; - "promotion-comment"?: string; - "default-labels"?: string[]; - "time-labels"?: ConfLabel[]; - "priority-labels"?: ConfLabel[]; - "command-settings"?: CommandLabel[]; - incentives?: IIncentive; - "enable-access-control"?: IControl; -} - -let defaultConf: IConf = { - "private-key-encrypted": "", - "safe-address": "", - "base-multiplier": 1, - "auto-pay-mode": false, - "analytics-mode": false, - "max-concurrent-bounties": 1, - "incentive-mode": false, - "evm-network-id": 1, - "price-multiplier": 1, - "issue-creator-multiplier": 1, - "payment-permit-max-price": 1, - "max-concurrent-assigns": 1, - "assistive-pricing": false, - "disable-analytics": false, - "comment-incentives": false, - "register-wallet-with-verification": false, - "promotion-comment": "", - "default-labels": [], - "time-labels": [], - "priority-labels": [], - "command-settings": [], - incentives: { - comment: { - elements: {}, - totals: { - word: 0, - }, - }, - }, - "enable-access-control": { - label: false, - organization: true, - }, -}; +let defaultConf = DefaultConfig; -export const parseYAML = async (data: any): Promise => { +export const parseYAML = async (data: string | undefined) => { + if (!data) return undefined; try { const parsedData = await YAML.parse(data); if (parsedData !== null) { - return parsedData; + return parsedData as T; } else { return undefined; } @@ -131,10 +49,10 @@ export const parseYAML = async (data: any): Promise => { } }; -export const parseJSON = async (data: any): Promise => { +export const parseJSON = async (data: string) => { try { const parsedData = await JSON.parse(data); - return parsedData; + return parsedData as T; } catch (error) { return undefined; } @@ -142,13 +60,13 @@ export const parseJSON = async (data: any): Promise => { export const YAMLStringify = (value: any) => YAML.stringify(value, { defaultKeyType: "PLAIN", defaultStringType: "QUOTE_DOUBLE", lineWidth: 0 }); -export const getConf = async (initial: boolean = false): Promise => { +export const getConf = async (): Promise => { try { const octokit = new Octokit({ auth: githubPAT.value }); const { data } = await octokit.rest.repos.getContent({ - owner: initial ? DEFAULT_ORG : orgName.value, - repo: initial ? DEFAULT_REPO : REPO_NAME, - path: initial ? DEFAULT_PATH : KEY_PATH, + owner: orgName.value, + repo: REPO_NAME, + path: KEY_PATH, mediaType: { format: "raw", }, @@ -227,9 +145,8 @@ const sodiumEncryptedSeal = async (publicKey: string, secret: string) => { const binsec = sodium.from_string(secret); const encBytes = sodium.crypto_box_seal(binsec, binkey); const output = sodium.to_base64(encBytes, sodium.base64_variants.URLSAFE_NO_PADDING); - defaultConf[KEY_NAME] = output; - defaultConf["evm-network-id"] = Number(chainIdSelect.value); - defaultConf["safe-address"] = safeAddressInput.value; + defaultConf[PRIVATE_ENCRYPTED_KEY_NAME] = output; + defaultConf[EVM_NETWORK_KEY_NAME] = Number(chainIdSelect.value); outKey.value = YAMLStringify(defaultConf); outKey.style.height = getTextBox(outKey.value); encryptedValue = output; @@ -304,10 +221,9 @@ const setConfig = async () => { const conf = await getConf(); const updatedConf = defaultConf; - const parsedConf: IConf | undefined = await parseYAML(conf); - updatedConf[KEY_NAME] = encryptedValue; - updatedConf["evm-network-id"] = Number(chainIdSelect.value); - updatedConf["safe-address"] = safeAddressInput.value; + const parsedConf = await parseYAML(conf); + updatedConf[PRIVATE_ENCRYPTED_KEY_NAME] = encryptedValue; + updatedConf[EVM_NETWORK_KEY_NAME] = Number(chainIdSelect.value); // combine configs (default + remote org wide) const combinedConf = Object.assign(updatedConf, parsedConf); @@ -472,18 +388,6 @@ const step1Handler = async () => { singleToggle("warn", `Warn: GitHub PAT is not set.`, githubPAT); return; } - if (!safeAddressInput.value.startsWith("0x")) { - singleToggle("warn", `Warn: Safe Address must start with 0x.`, safeAddressInput); - return; - } - if (!isHex(safeAddressInput.value.substring(2))) { - singleToggle("warn", `Warn: Safe Address is not a valid hex string.`, safeAddressInput); - return; - } - if (safeAddressInput.value.length !== 42) { - singleToggle("warn", `Warn: Safe Address must be 20 bytes long.`, safeAddressInput); - return; - } await sodiumEncryptedSeal(X25519_KEY, `${KEY_PREFIX}${walletPrivateKey.value}`); setConfig(); @@ -550,12 +454,9 @@ const step2Handler = async () => { }; const init = async () => { - let conf = await getConf(true); - if (conf !== undefined) { + if (defaultConf !== undefined) { try { - conf = JSON.parse(conf); - defaultConf = conf as IConf; - defaultConf["private-key-encrypted"] = ""; + defaultConf[PRIVATE_ENCRYPTED_KEY_NAME] = undefined; setInputListeners(); setBtn.addEventListener("click", async () => {