Skip to content
This repository has been archived by the owner on Aug 1, 2022. It is now read-only.

Commit

Permalink
feat: integrate org ENS name registration
Browse files Browse the repository at this point in the history
Co-Authored-By: Jason Efstathiou <j@jason-e.dev>
Co-Authored-By: Rūdolfs Ošiņš <rudolfs@osins.org>
Co-Authored-By: Thomas Scholtes <geigerzaehler@axiom.fm>

Signed-off-by: Jason Efstathiou <j@jason-e.dev>
Signed-off-by: Rūdolfs Ošiņš <rudolfs@osins.org>
Signed-off-by: Thomas Scholtes <geigerzaehler@axiom.fm>
  • Loading branch information
efstajas authored and rudolfs committed Aug 30, 2021
1 parent f68cff8 commit 3fd6112
Show file tree
Hide file tree
Showing 28 changed files with 1,876 additions and 65 deletions.
2 changes: 2 additions & 0 deletions ui/App.svelte
Expand Up @@ -122,12 +122,14 @@
<NetworkDiagnostics activeTab={$activeRouteStore.activeTab} />
{:else if $activeRouteStore.type === "singleSigOrg"}
<SingleSigOrg
registration={$activeRouteStore.registration}
address={$activeRouteStore.address}
owner={$activeRouteStore.owner}
projectCount={$activeRouteStore.projectCount}
anchors={$activeRouteStore.anchors} />
{:else if $activeRouteStore.type === "multiSigOrg"}
<Org
registration={$activeRouteStore.registration}
activeTab={$activeRouteStore.view}
address={$activeRouteStore.address}
gnosisSafeAddress={$activeRouteStore.gnosisSafeAddress}
Expand Down
3 changes: 3 additions & 0 deletions ui/DesignSystem/Modal.svelte
Expand Up @@ -51,6 +51,9 @@
gap: 1.5rem;
justify-content: flex-end;
}
h1 {
text-align: center;
}
</style>

<div class="container" data-cy={dataCy}>
Expand Down
3 changes: 2 additions & 1 deletion ui/DesignSystem/ProjectAnchorPopover.svelte
Expand Up @@ -104,14 +104,15 @@
size="small"
style="margin: 0 0.5rem 0 0.5rem;"
variant="square"
imageUrl={anchor.registration?.avatar || undefined}
avatarFallback={radicleAvatar.generate(
anchor.orgAddress,
radicleAvatar.Usage.Any
)} />
<p
class="typo-text-bold org"
style="color: var(--color-foreground-level-6);overflow: ellipsed">
{anchor.orgAddress}
{anchor.registration?.domain || anchor.orgAddress}
</p>
{/if}
</div>
Expand Down
3 changes: 2 additions & 1 deletion ui/DesignSystem/Sidebar/OrgList.svelte
Expand Up @@ -35,7 +35,7 @@

{#if $wallet.status === Wallet.Status.Connected && ethereum.supportedNetwork($ethereumEnvironment) === $wallet.connected.network}
{#each $orgSidebarStore as org (org.id)}
<Tooltip value={org.id}>
<Tooltip value={org.registration?.domain || org.id}>
<SidebarItem
indicator={true}
onClick={() =>
Expand All @@ -46,6 +46,7 @@
<Avatar
size="regular"
variant="square"
imageUrl={org.registration?.avatar || undefined}
avatarFallback={radicleAvatar.generate(
org.id,
radicleAvatar.Usage.Any
Expand Down
124 changes: 124 additions & 0 deletions ui/Modal/Org/ConfigureEns.svelte
@@ -0,0 +1,124 @@
<!--
Copyright © 2021 The Radicle Upstream Contributors
This file is part of radicle-upstream, distributed under the GPLv3
with Radicle Linking Exception. For full terms see the included
LICENSE file.
-->
<script lang="typescript">
import type * as ethers from "ethers";
import * as ensResolver from "ui/src/org/ensResolver";
import * as modal from "ui/src/modal";
import * as error from "ui/src/error";
import { unreachable } from "ui/src/unreachable";
import Intro from "./ConfigureEns/Intro.svelte";
import LinkOrgToName from "./ConfigureEns/LinkOrgToName.svelte";
import RegisterName from "./ConfigureEns/RegisterName.svelte";
import type * as registerName from "./ConfigureEns/RegisterName.svelte";
import UpdateMetadata from "./ConfigureEns/UpdateMetadata.svelte";
export let orgAddress: string;
export let registration: ensResolver.Registration | undefined = undefined;
export let safeAddress: string | undefined = undefined;
export let fee: ethers.BigNumber;
type State =
| { type: "intro" }
| { type: "registerName"; currentName: string | undefined }
| {
type: "updateMetadata";
registration: ensResolver.Registration;
}
| {
type: "linkOrgToName";
domain: string;
};
let state: State = ((): State => {
if (registration) {
const currentName = registration.domain.replace(
`.${ensResolver.DOMAIN}`,
""
);
return { type: "registerName", currentName };
} else {
return { type: "intro" };
}
})();
async function registrationDone(result: registerName.Result) {
let registration: ensResolver.Registration | undefined;
if (result.registration) {
registration = result.registration;
} else {
const domain = `${result.name}.${ensResolver.DOMAIN}`;
// TODO(thomas): handle exception
registration = await ensResolver.getRegistration(domain);
if (!registration) {
throw new error.Error({
message: "Domain not registered",
details: { domain },
});
}
}
state = {
type: "updateMetadata",
registration,
};
}
function introDone() {
const currentName = registration?.domain.replace(
`.${ensResolver.DOMAIN}`,
""
);
state = {
type: "registerName",
currentName,
};
}
function bindUpdateMetadataDone(domain: string) {
return () => {
// Don't show linkOrgToName step if it is already linked.
if (registration?.address?.toLowerCase() === orgAddress.toLowerCase()) {
modal.hide();
return;
}
state = {
type: "linkOrgToName",
domain,
};
};
}
function linkOrgToNameDone() {
modal.hide();
}
</script>

{#if state.type === "intro"}
<Intro onSubmit={introDone} {fee} />
{:else if state.type === "registerName"}
<RegisterName currentName={state.currentName} {fee} {registrationDone} />
{:else if state.type === "updateMetadata"}
<UpdateMetadata
{orgAddress}
registration={state.registration}
onSubmit={bindUpdateMetadataDone(state.registration.domain)} />
{:else if state.type === "linkOrgToName"}
<LinkOrgToName
domain={state.domain}
{orgAddress}
{safeAddress}
onSubmit={linkOrgToNameDone} />
{:else}
{unreachable(state)}
{/if}
54 changes: 54 additions & 0 deletions ui/Modal/Org/ConfigureEns/BlockTimer.svelte
@@ -0,0 +1,54 @@
<!--
Copyright © 2021 The Radicle Upstream Contributors
This file is part of radicle-upstream, distributed under the GPLv3
with Radicle Linking Exception. For full terms see the included
LICENSE file.
-->
<script lang="typescript">
import { onDestroy } from "svelte";
import * as svelteStore from "ui/src/svelteStore";
import * as wallet from "ui/src/wallet";
export let commitmentBlock: number;
export let minimumCommitmentAge: number;
export let onFinish: () => void;
const walletStore = svelteStore.get(wallet.store);
// There seems to be an off-by-one error in the contract, because if we don't
// wait for that one extra block we get an error saying that the commitment
// isn't old enough.
const requiredBlockCount = minimumCommitmentAge + 1;
let confirmedBlockCount: number = 0;
const onBlock = (currentBlock: number) => {
confirmedBlockCount = currentBlock - commitmentBlock;
if (confirmedBlockCount >= requiredBlockCount) {
onFinish();
walletStore.provider.off("block", onBlock);
// When we resume a saved commitment, it can happen that more blocks have
// been included than the minimum required amount in the mean time.
// We don't want to overflow the counter that we show to the user.
confirmedBlockCount = requiredBlockCount;
}
};
walletStore.provider.on("block", onBlock);
onDestroy(() => {
walletStore.provider.off("block", onBlock);
});
</script>

<style>
p {
color: var(--color-foreground-level-6);
}
</style>

<p class="typo-text-bold">
Confirmed {confirmedBlockCount} out of {requiredBlockCount} blocks.
</p>
117 changes: 117 additions & 0 deletions ui/Modal/Org/ConfigureEns/ConfirmRegistration.svelte
@@ -0,0 +1,117 @@
<!--
Copyright © 2021 The Radicle Upstream Contributors
This file is part of radicle-upstream, distributed under the GPLv3
with Radicle Linking Exception. For full terms see the included
LICENSE file.
-->
<script lang="typescript">
import type * as registerName from "./RegisterName.svelte";
import * as ensRegistrar from "ui/src/org/ensRegistrar";
import * as ensResolver from "ui/src/org/ensResolver";
import * as error from "ui/src/error";
import * as modal from "ui/src/modal";
import * as notification from "ui/src/notification";
import * as transaction from "ui/src/transaction";
import { Button, Modal } from "ui/DesignSystem";
import BlockTimer from "./BlockTimer.svelte";
let confirmButtonDisabled = true;
export let commitment: ensRegistrar.Commitment;
export let commitmentBlock: number;
export let registrationDone: (result: registerName.Result) => void;
async function register() {
confirmButtonDisabled = true;
const registrationNotification = notification.info({
message:
"Waiting for you to confirm the registration transaction in your connected wallet",
showIcon: true,
persist: true,
});
let registrationTx: transaction.ContractTransaction;
try {
registrationTx = await ensRegistrar.register(
commitment.name,
commitment.salt
);
} catch (err) {
confirmButtonDisabled = false;
error.show(
new error.Error({
message: err.message,
source: err,
})
);
// Don't advance flow if the user rejected the tx.
return;
} finally {
registrationNotification.remove();
}
ensRegistrar.clearCommitment();
transaction.add(transaction.registerEnsName(registrationTx));
const txNotification = notification.info({
message: "Waiting for the transaction to be included",
showIcon: true,
persist: true,
});
try {
await registrationTx.wait(1);
} catch (err) {
confirmButtonDisabled = false;
error.show(
new error.Error({
message: err.message,
source: err,
})
);
// Don't advance flow unless we have the tx receipt.
return;
} finally {
txNotification.remove();
}
notification.info({
message: `${commitment.name}.${ensResolver.DOMAIN} has been registered with your wallet`,
showIcon: true,
});
registrationDone({ name: commitment.name, registration: undefined });
}
</script>

<Modal emoji="📇" title="Awaiting registration commitment">
<svelte:fragment slot="description">
The waiting period is required to ensure another person hasn’t tried to
register the same name.
</svelte:fragment>

<div style="display: flex; justify-content: center;">
<BlockTimer
onFinish={() => {
confirmButtonDisabled = false;
}}
{commitmentBlock}
minimumCommitmentAge={commitment.minimumCommitmentAge} />
</div>

<svelte:fragment slot="buttons">
<Button
variant="transparent"
on:click={() => {
modal.hide();
}}>Cancel</Button>
<Button on:click={register} disabled={confirmButtonDisabled}
>Confirm registration</Button>
</svelte:fragment>
</Modal>

0 comments on commit 3fd6112

Please sign in to comment.