Skip to content

Commit

Permalink
feat: send native currency and asas to another account (#37)
Browse files Browse the repository at this point in the history
* feat: add button to open send asset modal

* feat: add network transaction params to storage

* feat: add send input to calculate maximum transaction aount

* feat: add asset select

* feat: add share address modal when clicking the receive button

* feat: add to address and note fields

* feat: add summary page

* feat: add thunk to send transaction

* feat: add toast when error or completion of trnasaction submission

* feat: update account information when confirmation of asset transafer

* fix: account tab selection persists through account selection

* fix: sidebar account address aligns left

* feat: use toast from hook and handle errors in send asset modal

* refactor: account information and account transaction thunk use lists of account ids

* feat: add transaction to send asset toast messages

* feat: shrink inputs to medium size

* build: update manifest version script to omit pre-release suffixes
  • Loading branch information
kieranroneill authored Dec 5, 2023
1 parent 8986938 commit 525727c
Show file tree
Hide file tree
Showing 154 changed files with 3,833 additions and 427 deletions.
9 changes: 7 additions & 2 deletions bin/update_manifest_version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ source "${SCRIPT_DIR}/set_vars.sh"
#
# Returns exit code 0 if successful, or 1 if the semantic version is incorrectly formatted.
function main {
local version

set_vars

if [ -z "${1}" ]; then
Expand All @@ -27,8 +29,11 @@ function main {
exit 1
fi

printf "%b updating manifest.common.json#version to version '%s' \n" "${INFO_PREFIX}" "${1}"
cat <<< $(jq --arg version "${1}" '.version = $version' "${PWD}/src/manifest.common.json") > "${PWD}/src/manifest.common.json"
# for pre release versions, be sure to remove the *-beta.xx that is suffixed to the end of the semantic version
version=${1%-*}

printf "%b updating manifest.common.json#version to version '%s' \n" "${INFO_PREFIX}" "${version}"
cat <<< $(jq --arg version "${version}" '.version = $version' "${PWD}/src/manifest.common.json") > "${PWD}/src/manifest.common.json"

exit 0
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@
"react-markdown": "^8.0.7",
"react-redux": "^8.0.5",
"react-router-dom": "^6.8.2",
"react-select": "^5.8.0",
"scrypt-async": "^2.0.1",
"tweetnacl": "^1.0.3",
"uuid": "^9.0.0",
Expand Down
27 changes: 25 additions & 2 deletions src/common/utils/formatCurrencyUnit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import formatCurrencyUnit from './formatCurrencyUnit';

interface ITestParams {
input: BigNumber;
decimals?: number;
expected: string;
}

Expand Down Expand Up @@ -42,6 +43,16 @@ describe('formatCurrencyUnit()', () => {
input: new BigNumber('612290.716271'),
expected: '612,290.72',
},
{
input: new BigNumber('612290.716271'),
decimals: 5,
expected: '612,290.71627',
},
{
input: new BigNumber('612290.716271'),
decimals: 4,
expected: '612,290.7163',
},
{
input: new BigNumber('12290.716271'),
expected: '12,290.72',
Expand Down Expand Up @@ -72,16 +83,28 @@ describe('formatCurrencyUnit()', () => {
},
{
input: new BigNumber('0.16500'),
decimals: 3,
expected: '0.165',
},
{
input: new BigNumber('0.23100'),
decimals: 2,
expected: '0.23',
},
{
input: new BigNumber('0.23500'),
decimals: 2,
expected: '0.24',
},
{
input: new BigNumber('0.716271'),
decimals: 6,
expected: '0.716271',
},
])(
`should format the unit of $input to $expected`,
({ input, expected }: ITestParams) => {
expect(formatCurrencyUnit(input)).toBe(expected);
({ input, decimals, expected }: ITestParams) => {
expect(formatCurrencyUnit(input, decimals)).toBe(expected);
}
);
});
11 changes: 7 additions & 4 deletions src/common/utils/formatCurrencyUnit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import numbro from 'numbro';
* @param {BigNumber} input - the unit as a BigNumber.
* @returns {string} the formatted unit.
*/
export default function formatCurrencyUnit(input: BigNumber): string {
export default function formatCurrencyUnit(
input: BigNumber,
decimals: number = 2
): string {
if (input.gte(1)) {
// numbers >= 1m+
if (input.decimalPlaces(2).gte(new BigNumber(1000000))) {
if (input.decimalPlaces(decimals).gte(new BigNumber(1000000))) {
return numbro(input.toString()).format({
average: true,
totalLength: 6,
Expand All @@ -19,15 +22,15 @@ export default function formatCurrencyUnit(input: BigNumber): string {

// numbers <= 999,999.99
return numbro(input.toString()).format({
mantissa: 2,
mantissa: decimals,
thousandSeparated: true,
trimMantissa: true,
});
}

// numbers < 1
return numbro(input.toString()).format({
mantissa: 6,
mantissa: decimals,
trimMantissa: true,
});
}
6 changes: 4 additions & 2 deletions src/common/utils/getAlgodClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { Algodv2 } from 'algosdk';
import { IBaseOptions } from '@common/types';
import { INetwork, INode } from '@extension/types';

// utils
import getRandomNode from './getRandomNode';

/**
* Gets a random algod node from the given network.
* @param {INetwork} network - the network to choose the node from.
Expand All @@ -14,8 +17,7 @@ export default function getAlgodClient(
network: INetwork,
{ logger }: IBaseOptions = { logger: undefined }
): Algodv2 {
const algod: INode =
network.algods[Math.floor(Math.random() * network.algods.length)];
const algod: INode = getRandomNode(network.algods);

logger &&
logger.debug(
Expand Down
6 changes: 4 additions & 2 deletions src/common/utils/getIndexerClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { Indexer } from 'algosdk';
import { IBaseOptions } from '@common/types';
import { INetwork, INode } from '@extension/types';

// utils
import getRandomNode from './getRandomNode';

/**
* Gets a random indexer node from the given network.
* @param {INetwork} network - the network to choose the node from.
Expand All @@ -14,8 +17,7 @@ export default function getIndexerClient(
network: INetwork,
{ logger }: IBaseOptions = { logger: undefined }
): Indexer {
const indexer: INode =
network.indexers[Math.floor(Math.random() * network.indexers.length)];
const indexer: INode = getRandomNode(network.indexers);

logger &&
logger.debug(
Expand Down
11 changes: 11 additions & 0 deletions src/common/utils/getRandomNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// types
import { INode } from '@extension/types';

/**
* Convenience function that randomly picks a node from a list.
* @param {INode[]} nodes - a list of nodes.
* @returns {INode} a random node from the list.
*/
export default function getRandomNode(nodes: INode[]): INode {
return nodes[Math.floor(Math.random() * nodes.length)];
}
1 change: 1 addition & 0 deletions src/common/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export { default as createLogger } from './createLogger';
export { default as formatCurrencyUnit } from './formatCurrencyUnit';
export { default as getAlgodClient } from './getAlgodClient';
export { default as getIndexerClient } from './getIndexerClient';
export { default as getRandomNode } from './getRandomNode';
export { default as mapSerializableErrors } from './mapSerializableErrors';
2 changes: 2 additions & 0 deletions src/extension/apps/background/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { reducer as accountsReducer } from '@extension/features/accounts';
import { reducer as assetsReducer } from '@extension/features/assets';
import { reducer as messagesReducer } from '@extension/features/messages';
import { reducer as networksReducer } from '@extension/features/networks';
import { reducer as sendAssetsReducer } from '@extension/features/send-assets';
import { reducer as sessionsReducer } from '@extension/features/sessions';
import { reducer as settingsReducer } from '@extension/features/settings';
import { reducer as systemReducer } from '@extension/features/system';
Expand All @@ -29,6 +30,7 @@ const App: FC<IAppProps> = ({ i18next, initialColorMode }: IAppProps) => {
assets: assetsReducer,
messages: messagesReducer,
networks: networksReducer,
sendAssets: sendAssetsReducer,
sessions: sessionsReducer,
settings: settingsReducer,
system: systemReducer,
Expand Down
2 changes: 2 additions & 0 deletions src/extension/apps/main/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { reducer as accountsReducer } from '@extension/features/accounts';
import { reducer as assetsReducer } from '@extension/features/assets';
import { reducer as messagesReducer } from '@extension/features/messages';
import { reducer as networksReducer } from '@extension/features/networks';
import { reducer as sendAssetsReducer } from '@extension/features/send-assets';
import { reducer as sessionsReducer } from '@extension/features/sessions';
import { reducer as settingsReducer } from '@extension/features/settings';
import {
Expand Down Expand Up @@ -86,6 +87,7 @@ const App: FC<IAppProps> = ({ i18next, initialColorMode }: IAppProps) => {
assets: assetsReducer,
messages: messagesReducer,
networks: networksReducer,
sendAssets: sendAssetsReducer,
sessions: sessionsReducer,
settings: settingsReducer,
system: systemReducer,
Expand Down
60 changes: 25 additions & 35 deletions src/extension/apps/main/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { createStandaloneToast } from '@chakra-ui/react';
import React, { FC, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { NavigateFunction, Outlet, useNavigate } from 'react-router-dom';
Expand All @@ -8,6 +7,7 @@ import ConfirmModal from '@extension/components/ConfirmModal';
import EnableModal from '@extension/components/EnableModal';
import ErrorModal from '@extension/components/ErrorModal';
import MainLayout from '@extension/components/MainLayout';
import SendAssetModal from '@extension/components/SendAssetModal';
import SignBytesModal from '@extension/components/SignBytesModal';
import SignTxnsModal from '@extension/components/SignTxnsModal';
import WalletConnectModal from '@extension/components/WalletConnectModal';
Expand All @@ -17,12 +17,6 @@ import {
fetchAccountsFromStorageThunk,
startPollingForAccountInformationThunk,
} from '@extension/features/accounts';
import {
setConfirm,
setError,
setNavigate,
setToast,
} from '@extension/features/system';
import {
fetchAssetsThunk,
updateAssetInformationThunk,
Expand All @@ -32,12 +26,18 @@ import {
setSignBytesRequest,
setSignTxnsRequest,
} from '@extension/features/messages';
import {
fetchTransactionParamsFromStorageThunk,
startPollingForTransactionsParamsThunk,
} from '@extension/features/networks';
import { reset as resetSendAsset } from '@extension/features/send-assets';
import {
closeWalletConnectModal,
fetchSessionsThunk,
initializeWalletConnectThunk,
} from '@extension/features/sessions';
import { fetchSettings } from '@extension/features/settings';
import { setConfirm, setError, setNavigate } from '@extension/features/system';

// hooks
import useOnMainAppMessage from '@extension/hooks/useOnMainAppMessage';
Expand All @@ -50,9 +50,6 @@ import {
useSelectSelectedNetwork,
} from '@extension/selectors';

// theme
import { theme } from '@extension/theme';

// types
import {
IAccount,
Expand All @@ -73,48 +70,41 @@ const Root: FC = () => {
const accounts: IAccount[] = useSelectAccounts();
const assets: Record<string, IAsset[]> | null = useSelectAssets();
const selectedNetwork: INetwork | null = useSelectSelectedNetwork();
// misc
const { toast, ToastContainer } = createStandaloneToast({
defaultOptions: {
containerStyle: {
margin: '0',
maxWidth: '100%',
minWidth: '100%',
padding: '0.5rem',
width: '100%',
},
duration: 6000,
position: 'top',
},
theme,
});
// handlers
const handleConfirmClose = () => dispatch(setConfirm(null));
const handleEnableModalClose = () => dispatch(setEnableRequest(null));
const handleErrorModalClose = () => dispatch(setError(null));
const handleSendAssetModalClose = () => dispatch(resetSendAsset());
const handleSignBytesModalClose = () => dispatch(setSignBytesRequest(null));
const handleSignTxnsModalClose = () => dispatch(setSignTxnsRequest(null));
const handleWalletConnectModalClose = () =>
dispatch(closeWalletConnectModal());

// 1. fetched required data from storage
useEffect(() => {
dispatch(setNavigate(navigate));
dispatch(setToast(toast));
dispatch(fetchSettings());
dispatch(fetchSessionsThunk());
dispatch(fetchAssetsThunk());
dispatch(initializeWalletConnectThunk());
dispatch(startPollingForAccountInformationThunk());
dispatch(startPollingForTransactionsParamsThunk());
}, []);
// fetch accounts when the selected network has been found and no accounts exist
// 2. when the selected network has been fetched from storage
useEffect(() => {
if (selectedNetwork && accounts.length < 1) {
dispatch(
fetchAccountsFromStorageThunk({
updateAccountInformation: true,
updateAccountTransactions: true,
})
);
if (selectedNetwork) {
// fetch accounts when no accounts exist
if (accounts.length < 1) {
dispatch(
fetchAccountsFromStorageThunk({
updateAccountInformation: true,
updateAccountTransactions: true,
})
);
}

// fetch the most recent transaction params for the selected network
dispatch(fetchTransactionParamsFromStorageThunk());
}
}, [selectedNetwork]);
// whenever the accounts are updated, check if any new assets exist in the account
Expand Down Expand Up @@ -160,8 +150,8 @@ const Root: FC = () => {
<EnableModal onClose={handleEnableModalClose} />
<SignTxnsModal onClose={handleSignTxnsModalClose} />
<SignBytesModal onClose={handleSignBytesModalClose} />
<SendAssetModal onClose={handleSendAssetModalClose} />
<WalletConnectModal onClose={handleWalletConnectModalClose} />
<ToastContainer />
<MainLayout>
<Outlet />
</MainLayout>
Expand Down
23 changes: 2 additions & 21 deletions src/extension/apps/registration/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Center, createStandaloneToast, Flex } from '@chakra-ui/react';
import { Center, Flex } from '@chakra-ui/react';
import React, { FC, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { NavigateFunction, Outlet, useNavigate } from 'react-router-dom';
Expand All @@ -7,46 +7,27 @@ import { NavigateFunction, Outlet, useNavigate } from 'react-router-dom';
import ErrorModal from '@extension/components/ErrorModal';

// features
import { setError, setNavigate, setToast } from '@extension/features/system';
import { setError, setNavigate } from '@extension/features/system';
import { fetchSettings } from '@extension/features/settings';

// theme
import { theme } from '@extension/theme';

// types
import { IAppThunkDispatch } from '@extension/types';

const Root: FC = () => {
const dispatch: IAppThunkDispatch = useDispatch<IAppThunkDispatch>();
const navigate: NavigateFunction = useNavigate();
const { toast, ToastContainer } = createStandaloneToast({
defaultOptions: {
containerStyle: {
margin: '0',
maxWidth: '100%',
minWidth: '100%',
padding: '0.5rem',
width: '100%',
},
duration: 6000,
position: 'top',
},
theme,
});
const handleErrorModalClose = () => {
dispatch(setError(null));
};

useEffect(() => {
dispatch(setNavigate(navigate));
dispatch(setToast(toast));
dispatch(fetchSettings());
}, []);

return (
<>
<ErrorModal onClose={handleErrorModalClose} />
<ToastContainer />
<Center as="main" backgroundColor="var(--chakra-colors-chakra-body-bg)">
<Flex
alignItems="center"
Expand Down
Loading

0 comments on commit 525727c

Please sign in to comment.