mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-02 02:00:31 +08:00
Identify Safe addresses
This commit is contained in:
@@ -57,6 +57,8 @@
|
||||
<a href={explorerLink(address, config)} target="_blank">{addressLabel}</a>
|
||||
{#if addressType === AddressType.Contract}
|
||||
<span class="badge">contract</span>
|
||||
{:else if addressType === AddressType.Safe}
|
||||
<span class="badge">safe</span>
|
||||
{:else if addressType === AddressType.EOA}
|
||||
<!-- Don't show anything for EOAs -->
|
||||
{:else}
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
},
|
||||
"orgFactory": {
|
||||
"address": "0x0000000000000000000000000000000000000000"
|
||||
},
|
||||
"safe": {
|
||||
"api": "https://safe-transaction.gnosis.io/api/v1"
|
||||
}
|
||||
},
|
||||
"ropsten": {
|
||||
@@ -25,6 +28,9 @@
|
||||
"orgs": {
|
||||
"subgraph": "https://api.thegraph.com/subgraphs/name/radicle-dev/radicle-orgs-ropsten",
|
||||
"contractHash": "0xc5bd5bc3cbcb709540df530c5ad2a9d91463ebb891a789286872938d963c12e9"
|
||||
},
|
||||
"safe": {
|
||||
"api": null
|
||||
}
|
||||
},
|
||||
"rinkeby": {
|
||||
@@ -41,6 +47,9 @@
|
||||
"orgs": {
|
||||
"subgraph": "https://api.thegraph.com/subgraphs/name/radicle-dev/radicle-orgs-rinkeby",
|
||||
"contractHash": "0xc5bd5bc3cbcb709540df530c5ad2a9d91463ebb891a789286872938d963c12e9"
|
||||
},
|
||||
"safe": {
|
||||
"api": "https://safe-transaction.rinkeby.gnosis.io/api/v1"
|
||||
}
|
||||
},
|
||||
"seed": {
|
||||
|
||||
@@ -25,6 +25,7 @@ export class Config {
|
||||
provider: ethers.providers.JsonRpcProvider;
|
||||
signer: ethers.Signer & TypedDataSigner | null;
|
||||
seed: { url: string };
|
||||
safe: { api: string | null };
|
||||
|
||||
constructor(
|
||||
network: { name: string, chainId: number },
|
||||
@@ -44,6 +45,7 @@ export class Config {
|
||||
this.radToken = cfg.radToken;
|
||||
this.orgFactory = cfg.orgFactory;
|
||||
this.orgs = cfg.orgs;
|
||||
this.safe = cfg.safe;
|
||||
this.provider = provider;
|
||||
this.signer = signer;
|
||||
this.gasLimits = gasLimits;
|
||||
|
||||
@@ -7,9 +7,16 @@ import { assert } from '@app/error';
|
||||
export enum AddressType {
|
||||
Contract,
|
||||
Org,
|
||||
Safe,
|
||||
EOA,
|
||||
}
|
||||
|
||||
export interface Safe {
|
||||
address: string
|
||||
owners: string[]
|
||||
threshold: number
|
||||
}
|
||||
|
||||
export function formatBalance(n: BigNumber) {
|
||||
return ethers.utils.commify(parseFloat(ethers.utils.formatUnits(n)).toFixed(2));
|
||||
}
|
||||
@@ -127,6 +134,11 @@ export function formatProjectHash(hash: Uint8Array, format: number): string {
|
||||
|
||||
// Identify an address by checking whether it's a contract or an externally-owned address.
|
||||
export async function identifyAddress(address: string, config: Config): Promise<AddressType> {
|
||||
let safe = await getSafe(address, config);
|
||||
if (safe) {
|
||||
return AddressType.Safe;
|
||||
}
|
||||
|
||||
let code = await config.provider.getCode(address);
|
||||
let bytes = ethers.utils.arrayify(code);
|
||||
|
||||
@@ -143,3 +155,26 @@ export async function identifyAddress(address: string, config: Config): Promise<
|
||||
export async function resolveLabel(label: string, config: Config): Promise<string | null> {
|
||||
return config.provider.resolveName(`${label}.${config.registrar.domain}`);
|
||||
}
|
||||
|
||||
// Get a Gnosis Safe at an address.
|
||||
export async function getSafe(address: string, config: Config): Promise<Safe | null> {
|
||||
if (! config.safe.api) return null;
|
||||
|
||||
const response = await fetch(`${config.safe.api}/safes/${address}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
}
|
||||
});
|
||||
|
||||
if (! response.ok) {
|
||||
return null;
|
||||
}
|
||||
const json = await response.json();
|
||||
|
||||
return {
|
||||
address: json.address,
|
||||
owners: json.owners,
|
||||
threshold: json.threshold
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user