Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Use CAIP-10 to specify anchors account
Alexis Sellier committed 4 years ago
commit b644a6e8b21a8aef346e60496547d89da84ac6ab
parent 1bd2c6d23f9823e1f7705ce27243c3fb7b4f9831
8 files changed +36 -21
modified src/Form.svelte
@@ -25,6 +25,7 @@
    handle: /^[a-zA-Z0-9-_]{1,39}$/,
    address: /^0x[a-zA-Z0-9]{40}$/,
    id: /^[a-z0-9]+$/,
+
    caip10: /^[:-a-zA-Z0-9]{5,41}:[a-zA-Z0-9]{1,64}$/,
    // Just make sure there is a TLD at the end.
    domain: /\.[a-z]{2,}$/,
  };
modified src/base/projects/View.svelte
@@ -131,7 +131,7 @@
      <div class="description">{result.project.meta.description}</div>
    </header>
    <Browser {urn} {org} {user} {path}
-
      anchors={result.profile?.projectAnchors ?? org}
+
      anchors={result.profile?.anchorsAccount ?? org}
      profile={result.profile}
      commit={commit || result.project.head}
      config={result.config} />
modified src/base/registrations/View.svelte
@@ -86,9 +86,10 @@
        { name: "seed.id", label: "Seed ID", validate: "id", placeholder: "hynkyndc6w3p8urucakobzncqny7xxtw88...",
          description: "The Device ID of a Radicle Link node that hosts entities associated with this name.",
          value: r.profile.seedId, editable: true },
-
        { name: "project.anchors", label: "Anchors", validate: "address", placeholder: "Ethereum address, eg. 0x4a9cf21...bc91...",
-
          description: "The alternative Ethereum address under which associated project anchors can be found.",
-
          value: r.profile.projectAnchors, editable: true },
+
        { name: "project.anchors", label: "Anchors", validate: "caip10", placeholder: "CAIP-10 ID, eg. eip155:1:0x4a9cf21...",
+
          description: "The alternative address under which associated project anchors can be found. "
+
            + "To point to a Radicle Org on Ethereum, prefix the org address with `eip155:1:`",
+
          value: r.profile.anchorsAccount, editable: true },
      ];
      state = { status: Status.Found, registration: r, owner };
    } else {
modified src/base/registrations/registrar.ts
@@ -20,7 +20,7 @@ export interface EnsProfile {
  address: string | null;
  seedId: string | null;
  seedHost: string | null;
-
  projectAnchors: string | null;
+
  anchorsAccount: string | null;
  url: string | null;
  avatar: string | null;
  twitter: string | null;
@@ -75,12 +75,12 @@ export async function getRegistration(name: string, config: Config, resolver?: E
    resolver.getText('url'),
    resolver.getText('eth.radicle.seed.id'),
    resolver.getText('eth.radicle.seed.host'),
-
    resolver.getText('eth.radicle.project.anchors'),
+
    resolver.getText('eth.radicle.anchors'),
    resolver.getText('com.twitter'),
    resolver.getText('com.github'),
  ]);

-
  const [address, avatar, url, seedId, seedHost, projectAnchors, twitter, github] =
+
  const [address, avatar, url, seedId, seedHost, anchorsAccount, twitter, github] =
    meta.map(r => r.status == "fulfilled" ? r.value : null);

  return {
@@ -91,7 +91,7 @@ export async function getRegistration(name: string, config: Config, resolver?: E
      avatar,
      seedId,
      seedHost,
-
      projectAnchors,
+
      anchorsAccount,
      address,
      twitter,
      github,
@@ -129,14 +129,14 @@ export async function getSeedId(name: string, config: Config, resolver?: EnsReso
  return resolver.getText('eth.radicle.seed.id');
}

-
export async function getProjectAnchorsAddress(name: string, config: Config, resolver?: EnsResolver): Promise<string | null> {
+
export async function getAnchorsAccount(name: string, config: Config, resolver?: EnsResolver): Promise<string | null> {
  name = name.toLowerCase();

  resolver = resolver ?? await config.provider.getResolver(name);
  if (! resolver) {
    return null;
  }
-
  return resolver.getText('eth.radicle.project.anchors');
+
  return resolver.getText('eth.radicle.anchors');
}

export function registrar(config: Config): ethers.Contract {
modified src/base/registrations/resolver.ts
@@ -36,7 +36,7 @@ export async function setRecords(name: string, records: EnsRecord[], resolver: E
        break;
      case "seed.id":
      case "seed.host":
-
      case "project.anchors":
+
      case "anchors":
        calls.push(
          iface.encodeFunctionData("setText", [node, "eth.radicle." + r.name, r.value])
        );
modified src/base/users/View.svelte
@@ -107,9 +107,9 @@
        <div><Address {config} address={profile.address} /></div>
        <div></div>
        <!-- Project anchors -->
-
        {#if profile.projectAnchors}
+
        {#if profile.anchorsAccount}
          <div class="label">Anchors</div>
-
          <div><Address {config} address={profile.projectAnchors} /></div>
+
          <div><Address {config} address={profile.anchorsAccount} /></div>
          <div></div>
        {/if}
        <!-- Profile -->
@@ -123,8 +123,8 @@
        </div>
      </div>
      <div class="projects">
-
        {#if profile.projectAnchors}
-
          {#await Org.get(profile.projectAnchors, config)}
+
        {#if profile.anchorsAccount}
+
          {#await Org.get(profile.anchorsAccount, config)}
            <Loading center fadeIn />
          {:then org}
            {#if org}
modified src/profile.ts
@@ -1,3 +1,4 @@
+
import { AccountID } from 'caip';
import type { EnsProfile } from "@app/base/registrations/registrar";
import type { BasicProfile } from "@ceramicstudio/idx-constants";
import {
@@ -85,8 +86,20 @@ export class Profile {
  }

  // Using undefined as return type if nothing to be returned since it works better with <a href> links
-
  get projectAnchors(): string | undefined {
-
    return this.profile?.ens?.projectAnchors ?? undefined;
+
  get anchorsAccount(): string | undefined {
+
    const addr = this.profile?.ens?.anchorsAccount;
+

+
    if (addr) {
+
      const id = AccountID.parse(addr);
+

+
      // Ethereum address.
+
      if (typeof id.chainId === "object" && id.chainId.namespace === "eip155") {
+
        return id.address;
+
      }
+
      if (typeof id.chainId === "string" && /^eip155/.test(id.chainId)) {
+
        return id.address;
+
      }
+
    }
  }

  // Get the name, and if not available, the address.
modified src/utils.ts
@@ -7,7 +7,7 @@ import type { Config } from '@app/config';
import config from "@app/config.json";
import { assert } from '@app/error';
import type { EnsProfile } from "@app/base/registrations/registrar";
-
import { getAvatar, getSeedHost, getSeedId, getProjectAnchorsAddress, getRegistration } from '@app/base/registrations/registrar';
+
import { getAvatar, getSeedHost, getSeedId, getAnchorsAccount, getRegistration } from '@app/base/registrations/registrar';
import type { BasicProfile } from "@ceramicstudio/idx-constants";
import { ProfileType } from '@app/profile';

@@ -301,13 +301,13 @@ export async function resolveEnsProfile(addressOrName: string, profileType: Prof
      if (profileType === ProfileType.Project) {
        promises.push(getSeedHost(name, config, resolver));
        promises.push(getSeedId(name, config, resolver));
-
        promises.push(getProjectAnchorsAddress(name, config, resolver));
+
        promises.push(getAnchorsAccount(name, config, resolver));
      } else if (profileType === ProfileType.Minimal) {
        promises.push(Promise.resolve(null));
      }

      const project = await Promise.allSettled(promises);
-
      const [avatar, address, seedHost, seedId, projectAnchors] =
+
      const [avatar, address, seedHost, seedId, anchorsAccount] =
        project.map(r => r.status == "fulfilled" ? r.value : null);

      return {
@@ -316,7 +316,7 @@ export async function resolveEnsProfile(addressOrName: string, profileType: Prof
        address,
        seedHost,
        seedId,
-
        projectAnchors,
+
        anchorsAccount,
        url: null,
        twitter: null,
        github: null,