diff --git a/composables/useLookup.ts b/composables/useLookup.ts index 54c92f0..bab88e9 100644 --- a/composables/useLookup.ts +++ b/composables/useLookup.ts @@ -1,130 +1,5 @@ import { ethers } from "ethers"; -import { VNode } from "vue"; - -const networks = { - mainnet: "https://rpc.ankr.com/eth", - polygon: "https://rpc.ankr.com/polygon", - avalanche: "https://rpc.ankr.com/avalanche", - fantom: "https://rpc.ankr.com/fantom", - optimism: "https://rpc.ankr.com/optimism", - arbitrum: "https://rpc.ankr.com/arbitrum", -}; - -const gnosisSafeAbi = [ - { - inputs: [], - name: "getOwners", - outputs: [{ internalType: "address[]", name: "", type: "address[]" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "getThreshold", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, -]; - - - -const networkProviderMap = Object.keys(networks).reduce((acc, curr) => { - acc[curr] = new ethers.providers.JsonRpcProvider(networks[curr]); - return acc; -}, {}); - -type TaskCheckResponse = { - status: "success" | "error" | "warning"; - metadata?: object; -}; - -type TaskCheckFun = ({ - address: string, - provider: any, -}) => PromiseLike; - -type Task = { - description: string; - networkResults?: { - [network: string]: TaskCheckResponse; - }; - renderMetadata?: ({ network: string, metadata: object }) => VNode; - renderMetadataValue?: ({ key: string, value: any }) => VNode; - statusStrategy?: "some" | "every"; - check: TaskCheckFun; -}; - -const tasks: Array = [ - { - description: "This is an EOA", - - async check({ address, provider }) { - const code = await provider.getCode(address); - - if (code != "0x") { - return { status: "error" }; - } - - return { status: "success" }; - }, - }, - - { - description: "This is a smart contract address", - - statusStrategy: "some", - - async check({ address, provider }) { - const code = await provider.getCode(address); - - if (code === "0x") { - return { status: "error" }; - } - - return { status: "success" }; - }, - }, - - { - description: "This is a gnosis safe address", - - statusStrategy: "some", - - async check({ address, provider }) { - const contract = new ethers.Contract(address, gnosisSafeAbi, provider); - - try { - const [owners, threshold] = await Promise.all([ - contract.getOwners(), - contract.getThreshold(), - ]); - return { - status: "success", - metadata: { owners, threshold: threshold.toString() }, - }; - } catch (error) { - return { status: "error" }; - } - }, - }, - - { - description: "This address has transactions", - - statusStrategy: "some", - - async check({ address, provider }) { - const count = await provider.getTransactionCount(address); - - if (count === 0) { - return { status: "error" }; - } - - return { status: "success", metadata: { count } }; - }, - }, -]; +import { networkProviderMap, networks, Task, TaskCheckResponse, tasks } from "~~/core"; export function useLookup(addressOrEnsName: string) { diff --git a/core/index.ts b/core/index.ts new file mode 100644 index 0000000..124a498 --- /dev/null +++ b/core/index.ts @@ -0,0 +1,3 @@ +export * from "./web3" +export * from "./tasks" + diff --git a/core/tasks.tsx b/core/tasks.tsx new file mode 100644 index 0000000..cd1e999 --- /dev/null +++ b/core/tasks.tsx @@ -0,0 +1,121 @@ +import { ethers } from "ethers"; +import { VNode } from "vue"; +import { gnosisSafeAbi, networkScanBaseUrl } from "./web3"; + +export type TaskCheckResponse = { + status: "success" | "error" | "warning"; + metadata?: object; +}; + +export type TaskCheckFun = ({ + address: string, + provider: any, +}) => PromiseLike; + +export type Task = { + description: string; + networkResults?: { + [network: string]: TaskCheckResponse; + }; + renderMetadata?: ({ network: Network, metadata: object }) => VNode; + renderMetadataValue?: ({ network: Network, key: string, value: any }) => VNode; + statusStrategy?: "some" | "every"; + check: TaskCheckFun; +}; + +export const tasks: Array = [ + { + description: "This is an EOA", + + async check({ address, provider }) { + const code = await provider.getCode(address); + + if (code != "0x") { + return { status: "error" }; + } + + return { status: "success" }; + }, + }, + + { + description: "This is a smart contract address", + + statusStrategy: "some", + + async check({ address, provider }) { + const code = await provider.getCode(address); + + if (code === "0x") { + return { status: "error" }; + } + + return { status: "success" }; + }, + }, + + { + description: "This is a gnosis safe address", + + statusStrategy: "some", + + async check({ address, provider }) { + const contract = new ethers.Contract(address, gnosisSafeAbi, provider); + + try { + const [owners, threshold] = await Promise.all([ + contract.getOwners(), + contract.getThreshold(), + ]); + return { + status: "success", + metadata: { owners, threshold: threshold.toString() }, + }; + } catch (error) { + return { status: "error" }; + } + }, + + renderMetadataValue({ network, key, value }) { + + if (key === "owners") { + return
+
    + { + value.map((owner) =>
  • + {owner} + +
  • ) + } +
+
+ } + + return {String(value)} + } + }, + + { + description: "This address has transactions", + + statusStrategy: "some", + + async check({ address, provider }) { + const count = await provider.getTransactionCount(address); + + if (count === 0) { + return { status: "error" }; + } + + return { status: "success", metadata: { count } }; + }, + + renderMetadata({ metadata }) { + return {metadata.count} transaction(s) + } + }, +]; diff --git a/core/web3.ts b/core/web3.ts new file mode 100644 index 0000000..25d8745 --- /dev/null +++ b/core/web3.ts @@ -0,0 +1,46 @@ +import { ethers } from "ethers"; + +export const networks = { + mainnet: "https://rpc.ankr.com/eth", + polygon: "https://rpc.ankr.com/polygon", + avalanche: "https://rpc.ankr.com/avalanche", + fantom: "https://rpc.ankr.com/fantom", + optimism: "https://rpc.ankr.com/optimism", + arbitrum: "https://rpc.ankr.com/arbitrum", +}; + + +export const networkScanBaseUrl = { + mainnet: "https://etherscan.io/", + polygon: "https://polygonscan.com/", + avalanche: "https://snowtrace.io/", + fantom: "https://ftmscan.com/", + optimism: "https://optimistic.etherscan.io/", + arbitrum: "https://arbiscan.io/", +}; + +export type Network = keyof typeof networks; + +export const gnosisSafeAbi = [ + { + inputs: [], + name: "getOwners", + outputs: [{ internalType: "address[]", name: "", type: "address[]" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getThreshold", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, +]; + + + +export const networkProviderMap = Object.keys(networks).reduce((acc, curr) => { + acc[curr] = new ethers.providers.JsonRpcProvider(networks[curr]); + return acc; +}, {}); \ No newline at end of file diff --git a/pages/[address].vue b/pages/[address].vue index 5666f50..d07dcf4 100644 --- a/pages/[address].vue +++ b/pages/[address].vue @@ -1,4 +1,5 @@