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

Feature/sep 6 deposit #163

Merged
merged 10 commits into from
May 24, 2021
21 changes: 21 additions & 0 deletions src/components/Balance.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useDispatch } from "react-redux";
import { TextLink } from "components/TextLink";
import { BalanceRow } from "components/BalanceRow";
import { initiateSendAction as initiateSep6SendAction } from "ducks/sep6DepositAsset";
import { initiateSep8SendAction } from "ducks/sep8Send";
import { depositAssetAction } from "ducks/sep24DepositAsset";
import { initiateSendAction } from "ducks/sep31Send";
Expand Down Expand Up @@ -62,6 +63,10 @@ export const Balance = ({
return result;
};

const handleSep6Deposit = (asset: Asset) => {
dispatch(initiateSep6SendAction(asset));
};

const handleSep8Send = (asset: Asset) => {
dispatch(initiateSep8SendAction(asset));
};
Expand Down Expand Up @@ -114,6 +119,22 @@ export const Balance = ({
callback: onSend,
};
break;
case AssetActionId.SEP6_DEPOSIT:
props = {
...defaultProps,
title: `SEP-6 deposit ${balance.assetCode} (with Trusted Asset)`,
description: `Start SEP-6 deposit of trusted asset ${balance.assetCode}?`,
callback: () => handleSep6Deposit(balance),
};
break;
case AssetActionId.SEP6_WITHDRAW:
props = {
...defaultProps,
title: `SEP-6 withdrawal ${balance.assetCode}`,
description: `Start SEP-6 withdrawal of ${balance.assetCode}?`,
callback: () => handleSep24Withdraw(balance),
};
break;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this PR covers SEP-6 deposit of a trusted asset. A follow up PR will cover untrusted assets using claimable balances

case AssetActionId.SEP8_SEND_PAYMENT:
props = {
...defaultProps,
Expand Down
13 changes: 13 additions & 0 deletions src/components/BalanceRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ export const BalanceRow = ({
<option value={AssetActionId.SEND_PAYMENT}>Send payment</option>
)}

{supportedActions?.sep6 && (
<>
<option value={AssetActionId.SEP6_DEPOSIT}>
SEP-6 Deposit
</option>
{!isUntrusted && (
<option value={AssetActionId.SEP6_WITHDRAW}>
SEP-6 Withdraw
</option>
)}
</>
)}

{asset.supportedActions?.sep8 && (
<option value={AssetActionId.SEP8_SEND_PAYMENT}>
SEP-8 Send
Expand Down
200 changes: 200 additions & 0 deletions src/components/Sep6Send.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import React, { useEffect, useMemo, useState } from "react";
import { useDispatch } from "react-redux";
import { Button, InfoBlock, Input, Select } from "@stellar/design-system";
import { Heading2 } from "components/Heading";
import { Modal } from "components/Modal";
import { TextLink } from "components/TextLink";
import { resetActiveAssetAction } from "ducks/activeAsset";
import {
resetSep6DepositAction,
submitSep6DepositFields,
sep6DepositAction,
} from "ducks/sep6DepositAsset";
import { useRedux } from "hooks/useRedux";
import { ActionStatus } from "types/types.d";

export const Sep6Send = () => {
const { sep6DepositAsset } = useRedux("sep6DepositAsset");
const { depositResponse } = sep6DepositAsset;

interface FormData {
depositType: {
type: string;
};
fields: {
[key: string]: string;
};
}

const formInitialState: FormData = {
depositType: {
type: "",
},
fields: {},
};

const [formData, setFormData] = useState<FormData>(formInitialState);
const dispatch = useDispatch();

const depositTypeChoices = useMemo(
() => sep6DepositAsset.data.depositTypes?.type?.choices || [],
[sep6DepositAsset],
);

useEffect(() => {
if (sep6DepositAsset.status === ActionStatus.NEEDS_INPUT) {
setFormData({
depositType: {
type: depositTypeChoices[0],
},
fields: {},
});
}
}, [sep6DepositAsset.status, depositTypeChoices, dispatch]);

useEffect(() => {
if (sep6DepositAsset.status === ActionStatus.CAN_PROCEED) {
dispatch(sep6DepositAction());
}
}, [sep6DepositAsset.status, dispatch]);

const resetLocalState = () => {
setFormData(formInitialState);
};

const handleClose = () => {
dispatch(resetSep6DepositAction());
dispatch(resetActiveAssetAction());
resetLocalState();
};

const handleDepositTypeChange = (
event: React.ChangeEvent<HTMLSelectElement>,
) => {
const { id, value } = event.target;

const updatedState = {
...formData,
depositType: {
...formData.depositType,
[id]: value,
},
};

setFormData(updatedState);
};

const handleFieldChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { id, value } = event.target;

const updatedState = {
...formData,
fields: {
...formData.fields,
[id]: value,
},
};

setFormData(updatedState);
};

const handleSubmit = (
event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
) => {
event.preventDefault();
dispatch(submitSep6DepositFields({ ...formData }));
};

if (sep6DepositAsset.status === ActionStatus.NEEDS_INPUT) {
return (
<Modal visible={true} onClose={handleClose}>
<Heading2
className="ModalHeading"
tooltipText={
<>
These are the fields the receiving anchor requires. The sending
client obtains them from the /customer endpoint.{" "}
<TextLink
href="https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0012.md#customer-get"
isExternal
>
Learn more
</TextLink>
</>
}
>
SEP-6 Required Info
</Heading2>
<div className="ModalBody">
{Object.entries(sep6DepositAsset.data.depositTypes || {}).map(
([id, input]) => (
<>
<Select
label={input.description}
id={id}
key={id}
onChange={handleDepositTypeChange}
>
{depositTypeChoices.map((choice: string) => (
<option key={choice} value={choice}>
{choice}
</option>
))}
</Select>
</>
),
)}
{Object.entries(sep6DepositAsset.data.fields || {}).map(
([id, input]) => (
<Input
key={id}
id={id}
label={input.description}
required
onChange={handleFieldChange}
/>
),
)}
</div>

<div className="ModalButtonsFooter">
<Button onClick={handleSubmit}>Submit</Button>
</div>
</Modal>
);
}

if (sep6DepositAsset.status === ActionStatus.SUCCESS) {
return (
<Modal visible={true} onClose={handleClose}>
<Heading2 className="ModalHeading">SEP-6 Deposit Info</Heading2>

<div className="ModalBody">
<InfoBlock>{depositResponse.how}</InfoBlock>

{depositResponse.extra_info?.message && (
<InfoBlock>{depositResponse.extra_info.message}</InfoBlock>
)}

{depositResponse.max_amount && (
<InfoBlock>
<strong>Max Amount: </strong>

{depositResponse.max_amount}
</InfoBlock>
)}

{depositResponse.min_amount && (
<InfoBlock>
<strong>Min Amount: </strong>

{depositResponse.min_amount}
</InfoBlock>
)}
</div>
</Modal>
);
}

return null;
};
8 changes: 5 additions & 3 deletions src/config/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ import { reducer as allAssets } from "ducks/allAssets";
import { reducer as assetOverrides } from "ducks/assetOverrides";
import { reducer as claimAsset } from "ducks/claimAsset";
import { reducer as claimableBalances } from "ducks/claimableBalances";
import { reducer as sep6DepositAsset } from "ducks/sep6DepositAsset";
import { reducer as sep8Send } from "ducks/sep8Send";
import { reducer as sep24DepositAsset } from "ducks/sep24DepositAsset";
import { reducer as sep24WithdrawAsset } from "ducks/sep24WithdrawAsset";
import { reducer as sep31Send } from "ducks/sep31Send";
import { reducer as logs } from "ducks/logs";
import { reducer as sendPayment } from "ducks/sendPayment";
import { reducer as sep8Send } from "ducks/sep8Send";
import { reducer as sep31Send } from "ducks/sep31Send";
import { reducer as settings } from "ducks/settings";
import { reducer as trustAsset } from "ducks/trustAsset";
import { reducer as untrustedAssets } from "ducks/untrustedAssets";
import { reducer as sep24WithdrawAsset } from "ducks/sep24WithdrawAsset";

const RESET_STORE_ACTION_TYPE = "RESET";
export type RootState = ReturnType<typeof store.getState>;
Expand All @@ -45,6 +46,7 @@ const reducers = combineReducers({
claimableBalances,
logs,
sendPayment,
sep6DepositAsset,
sep8Send,
sep24DepositAsset,
sep24WithdrawAsset,
Expand Down
Loading