Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Identify Safe addresses
Alexis Sellier committed 4 years ago
commit ef1c285712ccb1bc1878e89e8cf0a4978747c48d
parent 8d91e480c5bb7723de369ad13ad6527e372a0433
4 files changed +48 -0
modified src/Address.svelte
@@ -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}
modified src/config.json
@@ -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": {
modified src/config.ts
@@ -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;
modified src/utils.ts
@@ -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
+
  };
+
}