diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..bc81fb1 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,24 @@ +name: Build + +on: push + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout 🛎️ + uses: actions/checkout@master + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: "yarn" + + - name: Install project dependencies + shell: bash + run: yarn + + - name: Build 🏗️ + run: yarn build diff --git a/.github/actions/publish.yml b/.github/workflows/publish.yml similarity index 76% rename from .github/actions/publish.yml rename to .github/workflows/publish.yml index 31e9280..8b3b321 100644 --- a/.github/actions/publish.yml +++ b/.github/workflows/publish.yml @@ -13,8 +13,11 @@ jobs: - name: Checkout 🛎️ uses: actions/checkout@master - - name: Install 🔧 - run: yarn install + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: "yarn" - name: Build 🏗️ run: yarn build diff --git a/src/app.ts b/src/app.ts deleted file mode 100644 index 90fcb31..0000000 --- a/src/app.ts +++ /dev/null @@ -1,304 +0,0 @@ -import Safe, { - ContractNetworksConfig, - EthersAdapter, - SafeFactory, -} from "@safe-global/protocol-kit"; -import Toastify from "toastify-js"; -import { ethers } from "ethers"; -import { parseEther } from "ethers/lib/utils"; -import "@zoralabs/zorb/dist/component.umd"; -import "toastify-js/src/toastify.css"; -import { contractNetworks } from "./chains"; - -function log(text: string) { - console.log(text); - Toastify({ - text: text, - }).showToast(); - const log = document.querySelector("#log"); - if (!log) { - return; - } - log.innerHTML += `
  • ${text}
  • `; -} - -async function getSigner() { - await (window as any).ethereum.enable(); - - return new ethers.providers.Web3Provider( - (window as any).ethereum - ).getSigner(); -} - -async function getSafeSDK(safeAddress: string) { - const signer = await getSigner(); - - const ethAdapter = new EthersAdapter({ - ethers, - signerOrProvider: signer, - }); - - log(`ChainId: ${await ethAdapter.getChainId()}`); - - const safeSdk: Safe = await Safe.create({ - ethAdapter: ethAdapter, - safeAddress, - contractNetworks, - }); - - const safeSdk2 = await safeSdk.connect({ - ethAdapter: new EthersAdapter({ ethers, signerOrProvider: signer }), - safeAddress, - contractNetworks, - }); - return { safeSdk, safeSdk2, signer }; -} - -async function runit(operation, safeAddress, transaction) { - try { - const { safeSdk, safeSdk2 } = await getSafeSDK(safeAddress); - - log(`creating txn for ${safeAddress.toString()}`); - const txn = await safeSdk.createTransaction({ - safeTransactionData: transaction, - }); - - if (operation === "execute") { - const execute = await safeSdk2.executeTransaction(txn); - log(`publishing approval tx ${execute.hash}`); - await execute.transactionResponse?.wait(); - log("executed"); - } - - if (operation === "sign") { - const txHash = await safeSdk2.getTransactionHash(txn); - log(`has safe tx hash ${txHash}`); - - const approveTxResponse = await safeSdk2.approveTransactionHash(txHash); - log(`publishing approval tx ${approveTxResponse.hash}`); - await approveTxResponse.transactionResponse?.wait(); - log("transaction has been confirmed"); - } - } catch (err) { - log(err.toString()); - } -} - -async function create(threshold: string, signers: string[]) { - try { - const signer = new ethers.providers.Web3Provider( - (window as any).ethereum - ).getSigner(); - const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer }); - const adapter = await SafeFactory.create({ ethAdapter, contractNetworks }); - const sdk = await adapter.deploySafe({ - safeAccountConfig: { - owners: signers, - threshold: parseInt(threshold, 10), - }, - }); - log(`deployed new safe: ${await sdk.getAddress()}`); - } catch (err) { - log(err.toString()); - throw err; - } -} - -async function getSafeData(safeAddress: string) { - try { - const { safeSdk, signer } = await getSafeSDK(safeAddress); - const owners = await safeSdk.getOwners(); - const threshold = await safeSdk.getThreshold(); - const chainId = await signer.getChainId(); - - return { owners, threshold, chainId }; - } catch (err) { - log(err.toString()); - throw err; - } -} - -async function getSafeTxnApprovals(safeAddress: string, txnData: any) { - const { safeSdk, safeSdk2 } = await getSafeSDK(safeAddress); - const txn = await safeSdk.createTransaction({ - safeTransactionData: txnData, - }); - const hash = await safeSdk2.getTransactionHash(txn); - return await safeSdk2.getOwnersWhoApprovedTx(hash); -} - -function formDataAsDict(form: HTMLFormElement) { - const data = {}; - const formData = new FormData(form); - for (const pair of formData.entries()) { - data[pair[0]] = pair[1]; - } - return data; -} - -document.addEventListener("DOMContentLoaded", () => { - (window as any).ethereum.on("chainChanged", (networkId) => { - document.querySelector("#network-id")!.innerHTML = parseInt( - networkId, - 16 - ).toString(); - }); - (window as any).ethereum.on("accountsChanged", (accounts) => { - log(`Switched account to ${accounts[0]}`); - document.querySelector("#user-account")!.innerHTML = - accounts[0]; - }); - (window as any).ethereum.on("connect", async (connectInfo: any) => { - const accounts = await (window as any).ethereum.send("eth_requestAccounts"); - const firstAccount = accounts.result[0]; - document.querySelector("#user-account")!.innerHTML = - firstAccount; - document.querySelector("#connect-section")!.style.display = - "none"; - const network = parseInt(connectInfo.chainId, 16).toString(); - document.querySelector("#network-id")!.innerHTML = network; - log(`Switched connected to ${network} with ${firstAccount}`); - }); -}); - -function setInput(name: string, value: string | null) { - if (value === null) { - value = ""; - } - - const safeAddress = document.querySelector( - `input[name=${name}]` - ) as HTMLInputElement; - safeAddress.value = value; -} - -const getNetwork = async () => - (await (await getSigner()).getChainId()).toString(); - -function app() { - const signForm = document.querySelector("#sign"); - - async function getSafeInfo() { - const data = formDataAsDict(signForm as HTMLFormElement); - const safeData = await getSafeData(data["safeAddress"]); - document.querySelector("#safe-result")!.innerHTML = JSON.stringify( - safeData, - null, - 2 - ); - } - - document.addEventListener("DOMContentLoaded", async () => { - const params = new URLSearchParams(window.location.search); - if (params.get("network")) { - let network = params.get("network")!; - if (network.startsWith("0x")) { - network = parseInt(network, 16).toString(); - } - - const currentNetwork = await getNetwork(); - console.log({ currentNetwork, network }); - if (currentNetwork !== network) { - console.log("changing network"); - await (window as any).ethereum.request({ - method: "wallet_switchEthereumChain", - params: [{ chainId: `0x${parseInt(network, 10).toString(16)}` }], - }); - } - } - if (params.get("safe")) { - console.log("has safe!"); - console.log(params.get("safe")); - setInput("safeAddress", params.get("safe")); - setInput("to", params.get("to")); - setInput("value", params.get("value")); - setInput("data", params.get("data")); - getSafeInfo(); - ( - document.querySelector("summary.have-safe") as any - ).parentElement.setAttribute("open", "1"); - } - }); - - if (signForm) { - document - .querySelector("#connect") - ?.addEventListener("click", async (evt) => { - evt.preventDefault(); - (window as any).ethereum.send("eth_requestAccounts"); - }); - document - .querySelector("button.share-txn") - ?.addEventListener("click", async (evt) => { - evt.preventDefault(); - const params = new URLSearchParams(); - const data: any = formDataAsDict(signForm as HTMLFormElement); - params.set("safe", data["safeAddress"]); - params.set("to", data["to"]); - params.set("data", data["data"]); - params.set("value", data["value"]); - params.set("network", await getNetwork()); - let location = window.location.href; - if (location.indexOf("?") !== -1) { - location = location.substring(0, location.indexOf("?")); - } - const url = `${location}?${params.toString()}`; - (navigator as any).clipboard.writeText(url); - }); - document - .querySelector("#safe-info") - ?.addEventListener("click", async (evt) => { - evt.preventDefault(); - getSafeInfo(); - }); - signForm.addEventListener("submit", (evt) => { - evt.preventDefault(); - const data = formDataAsDict(signForm as HTMLFormElement); - try { - const txn = { - to: data["to"], - value: parseEther(data["value"] || "0").toString(), - data: data["data"] || "0x", - }; - console.log({ txn }); - runit(data["operation"], data["safeAddress"], txn); - } catch (e) { - log(e); - alert(e.toString()); - return; - } - }); - signForm.addEventListener("change", async () => { - const data: any = formDataAsDict(signForm as HTMLFormElement); - if (data.safeAddress && data.to && data.value && data.data) { - const txn = { - to: data["to"], - value: parseEther(data["value"] || "0").toString(), - data: data["data"] || "0x", - }; - console.log({ txn, data }); - const approvals = await getSafeTxnApprovals(data["safeAddress"], txn); - const approvalsHtml = document.querySelector("#txn-approvals")!; - approvalsHtml.innerHTML = `${ - approvals.length - } approvals for this txn [${approvals.join(", ")}]`; - } - }); - } - const executeForm = document.querySelector("#create"); - if (executeForm) { - executeForm.addEventListener("submit", (evt) => { - evt.preventDefault(); - const data = formDataAsDict(executeForm as HTMLFormElement); - // do execute - try { - create(data["threshold"], data["signers"].split("\n")); - } catch (e: any) { - log(e.toString()); - console.error(e); - } - }); - } -} - -app(); diff --git a/src/index-legacy.html b/src/index-legacy.html deleted file mode 100644 index e1b2244..0000000 --- a/src/index-legacy.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - zora signer - - - - - -
    -
    -

    smol-safe //

    -
    - -
    -
    -
    - Connected to chainid: - none -
    -
    Account:
    -
    -
    Connect Metamask/Injected Wallet
    - -
    -
    - -
    - I have a safe - -
    -
    -

    Load existing safe:

    - - -
    
    -            
    -
    -
    - OPERATION: - - -
    -
    - operations 1: - - - - - - -
    - -
    -
    -
    -
    - -
    - I am creating a safe -
    -

    create a SAFE on the current network

    - - - -
    -
    - -
      -
      - - diff --git a/tsconfig.json b/tsconfig.json index 8b407fc..2e0e11d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,7 @@ /* Linting */ "strict": true, - "noUnusedLocals": true, + "noUnusedLocals": false, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "types": []