Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Account] create and parse muxed account #794

Merged
merged 18 commits into from
Mar 29, 2024
12 changes: 7 additions & 5 deletions src/app/(sidebar)/account/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function CreateAccount() {
const generateKeypair = () => {
let keypair = Keypair.random();

account.update(keypair.publicKey());
account.updatePublicKey(keypair.publicKey());
setSecretKey(keypair.secret());
};

Expand Down Expand Up @@ -54,10 +54,12 @@ export default function CreateAccount() {
</div>

<ExpandBox isExpanded={Boolean(account.publicKey)} offsetTop="xl">
<GenerateKeypair
publicKey={account.publicKey}
secretKey={secretKey}
/>
<div className="Account__result">
<GenerateKeypair
publicKey={account.publicKey}
secretKey={secretKey}
/>
</div>
</ExpandBox>
</div>
</Card>
Expand Down
7 changes: 4 additions & 3 deletions src/app/(sidebar)/account/fund/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { useEffect, useState } from "react";
import { Alert, Card, Input, Text, Button } from "@stellar/design-system";

import { shortenStellarAddress } from "@/helpers/shortenStellarAddress";
import { validatePublicKey } from "@/helpers/validatePublicKey";
import { useFriendBot } from "@/query/useFriendBot";
import { useStore } from "@/store/useStore";

import { validate } from "@/validate";

import "../styles.scss";

export default function FundAccount() {
Expand Down Expand Up @@ -52,8 +53,8 @@ export default function FundAccount() {
onChange={(e) => {
setGeneratedPublicKey(e.target.value);

const error = validatePublicKey(e.target.value);
jeesunikim marked this conversation as resolved.
Show resolved Hide resolved
setInlineErrorMessage(error);
const error = validate.publicKey(e.target.value);
setInlineErrorMessage(error || "");
}}
placeholder="Ex: GCEXAMPLE5HWNK4AYSTEQ4UWDKHTCKADVS2AHF3UI2ZMO3DPUSM6Q4UG"
error={inlineErrorMessage}
Expand Down
181 changes: 180 additions & 1 deletion src/app/(sidebar)/account/muxed-create/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,184 @@
"use client";

import { useState } from "react";
import { Alert, Button, Card, Input, Text } from "@stellar/design-system";

import { useStore } from "@/store/useStore";

import { ExpandBox } from "@/components/ExpandBox";
import { MuxedAccountResult } from "@/components/MuxedAccountResult";
import { PubKeyPicker } from "@/components/FormElements/PubKeyPicker";
import { SdsLink } from "@/components/SdsLink";

import { muxedAccount } from "@/helpers/muxedAccount";

import { validate } from "@/validate";

import "../styles.scss";

export default function CreateMuxedAccount() {
return <div>Create Muxed Account</div>;
const { account } = useStore();

const [baseAddress, setBaseAddress] = useState<string>(
account.generatedMuxedAccountInput?.baseAddress || "",
);
const [muxedId, setMuxedId] = useState<string>(
account.generatedMuxedAccountInput?.id || "",
);
const [baseFieldErrorMessage, setBaseFieldErrorMessage] =
useState<string>("");
const [muxedFieldError, setMuxedFieldError] = useState<string>("");
const [sdkError, setSdkError] = useState<string>("");

const [isReset, setReset] = useState<boolean>(false);

const generateMuxedAccount = () => {
const result = muxedAccount.generate({
baseAddress,
muxedAccountId: muxedId,
});

const { error, muxedAddress } = result;

if (muxedAddress) {
setReset(false);
account.updateGeneratedMuxedAccount({
id: muxedId,
baseAddress,
muxedAddress,
});

account.updateGeneratedMuxedAccountInput({
id: muxedId,
baseAddress,
});

setSdkError("");
return;
}

if (error) {
setSdkError(error);
return;
}
};

return (
<div className="Account">
<Card>
<div className="Account__card">
<div className="CardText">
<Text size="lg" as="h1" weight="medium">
Create Multiplexed Account
</Text>

<Text size="sm" as="p">
A muxed (or multiplexed) account (defined in{" "}
<SdsLink href="https://github.com/stellar/stellar-protocol/blob/master/core/cap-0027.md">
CAP-27
</SdsLink>{" "}
and briefly{" "}
<SdsLink href="https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md">
SEP-23
</SdsLink>
) is one that resolves a single Stellar G...account to many
different underlying IDs.
</Text>
</div>

<PubKeyPicker
id="muxed-public-key"
label="Base Account G Address"
value={baseAddress}
onChange={(e) => {
setReset(true);
setBaseAddress(e.target.value);

let error = "";

if (!e.target.value.startsWith("G")) {
error = "Base account address should start with G";
} else {
error = validate.publicKey(e.target.value) || "";
}

setBaseFieldErrorMessage(error);
}}
error={baseFieldErrorMessage}
copyButton={{
position: "right",
}}
/>

<Input
id="muxed-account-iD"
fieldSize="md"
placeholder="Ex: 1"
label="Muxed Account ID"
value={muxedId}
onChange={(e) => {
setReset(true);
setMuxedId(e.target.value);

const error = validate.positiveInt(e.target.value);
setMuxedFieldError(error || "");
}}
error={muxedFieldError}
copyButton={{
position: "right",
}}
/>

<div className="Account__CTA">
<Button
disabled={
!baseAddress ||
!muxedId ||
Boolean(baseFieldErrorMessage || muxedFieldError)
}
size="md"
variant={"secondary"}
onClick={generateMuxedAccount}
>
Create
</Button>
</div>

<ExpandBox
jeesunikim marked this conversation as resolved.
Show resolved Hide resolved
offsetTop="xl"
isExpanded={
!isReset && Boolean(account.generatedMuxedAccount.muxedAddress)
}
>
<MuxedAccountResult
baseAddress={account.generatedMuxedAccount.baseAddress ?? ""}
muxedAddress={account.generatedMuxedAccount.muxedAddress ?? ""}
muxedId={account.generatedMuxedAccount.id ?? ""}
/>
</ExpandBox>
</div>
</Card>

<Alert
placement="inline"
variant="warning"
title="Muxed accounts are uncommon"
>
Don’t use in a production environment unless you know what you’re doing.
</Alert>

{Boolean(sdkError) && (
<Alert
placement="inline"
variant="error"
onClose={() => {
setSdkError("");
}}
title={sdkError}
>
{""}
</Alert>
)}
</div>
);
}
142 changes: 141 additions & 1 deletion src/app/(sidebar)/account/muxed-parse/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,145 @@
"use client";

import { useState } from "react";
import { Alert, Card, Text, Button } from "@stellar/design-system";

import { useStore } from "@/store/useStore";

import { ExpandBox } from "@/components/ExpandBox";
import { PubKeyPicker } from "@/components/FormElements/PubKeyPicker";
import { MuxedAccountResult } from "@/components/MuxedAccountResult";

import { muxedAccount } from "@/helpers/muxedAccount";

import { validate } from "@/validate";

import "../styles.scss";

export default function ParseMuxedAccount() {
return <div>Parse Muxed Account</div>;
const { account } = useStore();
const parsedMuxedAccount = account.parsedMuxedAccount;

const [muxedAddress, setMuxedAddress] = useState<string>(
account.parsedMuxedAccountInput || "",
);

const [muxedFieldError, setMuxedFieldError] = useState<string>("");
const [sdkError, setSdkError] = useState<string>("");

const [isReset, setReset] = useState<boolean>(false);

const parseMuxedAccount = () => {
const result = muxedAccount.parse({
muxedAddress,
});

const { error, id, baseAddress } = result;

if (baseAddress && id) {
setReset(false);
account.updateParsedMuxedAccount({
id,
baseAddress,
muxedAddress,
});
account.updateParsedMuxedAccountInput(muxedAddress);

setSdkError("");
return;
}

if (error) {
setSdkError(error);
return;
}
};

return (
<div className="Account">
<Card>
<div className="Account__card">
<div className="CardText">
<Text size="lg" as="h1" weight="medium">
Get Muxed Account from M address
</Text>
</div>

<PubKeyPicker
id="muxed-account-address"
label="Muxed Account M Address"
placeholder="Ex: MBRWSVNURRYVIYSWLRFQ5AAAUWPKOZZNZVVVIXHFGUSGIRVKLVIDYAAAAAAAAAAD5GJ4U"
value={muxedAddress}
error={muxedFieldError}
copyButton={{
position: "right",
}}
onChange={(e) => {
setReset(true);
setMuxedAddress(e.target.value);

let error = "";

if (!e.target.value.startsWith("M")) {
error = "Muxed account address should start with M";
} else {
error = validate.publicKey(e.target.value) || "";
}

setMuxedFieldError(error);
}}
/>

<div className="Account__CTA">
<Button
disabled={!muxedAddress || Boolean(muxedFieldError)}
size="md"
variant={"secondary"}
onClick={parseMuxedAccount}
>
Parse
</Button>
</div>

<ExpandBox
offsetTop="xl"
isExpanded={
!isReset &&
Boolean(
parsedMuxedAccount?.baseAddress &&
parsedMuxedAccount?.id &&
parsedMuxedAccount?.muxedAddress,
)
}
>
<MuxedAccountResult
baseAddress={parsedMuxedAccount.baseAddress ?? ""}
muxedId={parsedMuxedAccount.id ?? ""}
muxedAddress={parsedMuxedAccount.muxedAddress ?? ""}
/>
</ExpandBox>
</div>
</Card>

<Alert
placement="inline"
variant="warning"
title="Muxed accounts are uncommon"
>
Don’t use in a production environment unless you know what you’re doing.
</Alert>

{Boolean(sdkError) && (
<Alert
placement="inline"
variant="error"
onClose={() => {
setSdkError("");
}}
title={sdkError}
>
{""}
</Alert>
)}
</div>
);
}
9 changes: 9 additions & 0 deletions src/app/(sidebar)/account/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,13 @@
cursor: pointer;
}
}

&__result {
display: flex;
flex-direction: column;
gap: pxToRem(16px);
background-color: var(--sds-clr-gray-03);
border-radius: pxToRem(8px);
padding: pxToRem(16px);
}
}
Loading
Loading