This commit is contained in:
Georges KABBOUCHI 2022-06-09 21:10:35 +03:00
parent 078247fca3
commit 78ccb7ae00
5 changed files with 173 additions and 135 deletions

View File

@ -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<TaskCheckResponse>;
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<Task> = [
{
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) {

3
core/index.ts Normal file
View File

@ -0,0 +1,3 @@
export * from "./web3"
export * from "./tasks"

121
core/tasks.tsx Normal file
View File

@ -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<TaskCheckResponse>;
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<Task> = [
{
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 <div class="ml-8 sm:ml-10" >
<ul class="list-decimal">
{
value.map((owner) => <li>
<a
class="hover:underline"
target="_blank"
rel="noopener noreferrer"
href={`${networkScanBaseUrl[network]}address/${owner}`}>{owner}
</a>
</li>)
}
</ul>
</div>
}
return <span class='text-sm'> {String(value)} </span>
}
},
{
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 <span> {metadata.count} transaction(s) </span>
}
},
];

46
core/web3.ts Normal file
View File

@ -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;
}, {});

View File

@ -1,4 +1,5 @@
<script setup lang="ts">
import { networkScanBaseUrl } from "~~/core";
import QrcodeVue from "qrcode.vue";
import {
CheckIcon,
@ -9,15 +10,6 @@ import {
const route = useRoute();
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/",
};
const statusIconBackground = {
success: "bg-green-500",
error: "bg-red-500",
@ -147,6 +139,7 @@ const { address, ens, detectedNetworks, taskResults, error, shortAddress } =
v-if="task.renderMetadataValue"
:is="
task.renderMetadataValue({
network,
key,
value,
})