Skip to content

Commit

Permalink
feat(compose_txn): enforce max value for asset amount for asset-trans…
Browse files Browse the repository at this point in the history
…fer transactions

Use the retrieved asset information to set and enforce the maximum possible value for an asset
amount.
  • Loading branch information
No-Cash-7970 committed Dec 27, 2023
1 parent 70a6cbc commit 56b99bb
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default function AssetId({ t }: { t: TFunction }) {
<span className='ms-1 align-middle'>{t('fields.caid.getting_info')}</span>
</>}
{assetInfoSuccess &&
(retrievedAssetInfo?.name ?? <i>{t('fields.caid.get_info_unknown')}</i>)
(retrievedAssetInfo?.value?.name ?? <i>{t('fields.caid.get_info_unknown')}</i>)
}
{assetInfoFail && <>
<IconAlertTriangle size={16} aria-hidden className='inline' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export default function AssetId({ t }: { t: TFunction }) {
<span className='ms-1 align-middle'>{t('fields.faid.getting_info')}</span>
</>}
{assetInfoSuccess &&
(retrievedAssetInfo?.name ?? <i>{t('fields.faid.get_info_unknown')}</i>)
(retrievedAssetInfo?.value?.name ?? <i>{t('fields.faid.get_info_unknown')}</i>)
}
{assetInfoFail && <>
<IconAlertTriangle size={16} aria-hidden className='inline' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import { NumberField } from '@/app/[lang]/components/form';
import { type TFunction } from 'i18next';
import { useAtomValue } from 'jotai';
import {
aamtConditionalMaxAtom,
assetTransferFormControlAtom,
showFormErrorsAtom,
tipBtnClass,
tipContentClass,
txnDataAtoms,
} from '@/app/lib/txn-data';
import { baseUnitsToDecimal } from '@/app/lib/utils';
import FieldErrorMessage from '../FieldErrorMessage';

export default function Amount({ t }: { t: TFunction }) {
const form = useAtomValue(assetTransferFormControlAtom);
const aamtCondMax = useAtomValue(aamtConditionalMaxAtom);
const showFormErrors = useAtomValue(showFormErrorsAtom);
const retrievedAssetInfo = useAtomValue(txnDataAtoms.retrievedAssetInfo);
return (<>
Expand All @@ -29,12 +32,17 @@ export default function Amount({ t }: { t: TFunction }) {
inputInsideLabel={false}
containerId='aamt-field'
containerClass='mt-4 max-w-xs'
inputClass={
((showFormErrors || form.touched.aamt) && form.fieldErrors.aamt) ? 'input-error' : ''
inputClass={((showFormErrors || form.touched.aamt) &&
(form.fieldErrors.aamt || (!aamtCondMax.isValid && aamtCondMax.error))
)
? 'input-error' : ''
}
afterSideLabel={retrievedAssetInfo?.unitName ?? t('unit_other')}
afterSideLabel={retrievedAssetInfo?.value?.unitName ?? t('unit_other')}
min={0}
step={10**-(retrievedAssetInfo?.decimals ?? 0)}
max={
baseUnitsToDecimal(retrievedAssetInfo?.value?.total, retrievedAssetInfo?.value?.decimals)
}
step={10**-(retrievedAssetInfo?.value?.decimals ?? 0)}
value={form.values.aamt ?? ''}
onChange={(e) => form.handleOnChange('aamt')(e.target.value)}
onFocus={form.handleOnFocus('aamt')}
Expand All @@ -46,5 +54,11 @@ export default function Amount({ t }: { t: TFunction }) {
dict={form.fieldErrors.aamt.message.dict}
/>
}
{(showFormErrors || form.touched.aamt) && !aamtCondMax.isValid && aamtCondMax.error &&
<FieldErrorMessage t={t}
i18nkey={(aamtCondMax.error as any).message.key}
dict={(aamtCondMax.error as any).message.dict}
/>
}
</>);
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export default function AssetId({ t }: { t: TFunction }) {
<span className='ms-1 align-middle'>{t('fields.xaid.getting_info')}</span>
</>}
{assetInfoSuccess &&
(retrievedAssetInfo?.name ?? <i>{t('fields.xaid.get_info_unknown')}</i>)
(retrievedAssetInfo?.value?.name ?? <i>{t('fields.xaid.get_info_unknown')}</i>)
}
{assetInfoFail && <>
<IconAlertTriangle size={16} aria-hidden className='inline' />
Expand Down
4 changes: 3 additions & 1 deletion src/app/lib/txn-data/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ export const close = atomWithValidate<string>('', {
* Retrieved Asset Information
*/

export const retrievedAssetInfo = atom<RetrievedAssetInfo|undefined>(undefined);
export const retrievedAssetInfo = atomWithValidate<RetrievedAssetInfo|undefined>(undefined, {
validate: v => v
});

/*
* Asset Transfer
Expand Down
14 changes: 13 additions & 1 deletion src/app/lib/txn-data/field-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import { OnApplicationComplete } from 'algosdk';
import { atom } from 'jotai';
import { atomWithFormControls, atomWithValidate, validateAtoms } from 'jotai-form';
import { baseUnitsToDecimal } from '@/app/lib/utils';
import * as txnDataAtoms from './atoms';
import { ValidationMessage } from './types';
import { RetrievedAssetInfo, ValidationMessage } from './types';
import { Preset, MAX_APP_GLOBALS, MAX_APP_KEY_LENGTH, MAX_APP_LOCALS } from './constants';
import { YupMixed, YupNumber, YupString, addressSchema, idSchema } from './validation-rules';

Expand Down Expand Up @@ -151,6 +152,17 @@ export const acloseConditionalRequireAtom = validateAtoms({
YupString().required().validateSync(values.aclose);
}
});
export const aamtConditionalMaxAtom = validateAtoms({
assetInfo: txnDataAtoms.retrievedAssetInfo,
aamt: txnDataAtoms.aamt,
}, (values) => {
if (values.assetInfo) {
const assetInfo = values.assetInfo as RetrievedAssetInfo;
YupNumber()
.max(parseFloat(baseUnitsToDecimal(assetInfo.total, assetInfo.decimals)))
.validateSync(values.aamt === '' ? undefined : values.aamt);
}
});

/*
* Asset configuration validation form groups
Expand Down
6 changes: 3 additions & 3 deletions src/app/lib/txn-data/stored.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ export function extractTxnDataFromAtoms(
aclose: assetTransferForm.values.aclose || undefined,
};

retrievedAssetInfo = jotaiStore.get(txnDataAtoms.retrievedAssetInfo);
retrievedAssetInfo = jotaiStore.get(txnDataAtoms.retrievedAssetInfo).value;
if (retrievedAssetInfo) {
// Remove asset addresses from asset information
retrievedAssetInfo = {
Expand Down Expand Up @@ -445,7 +445,7 @@ export function extractTxnDataFromAtoms(
apar_rUseSnd: !!assetConfigForm.values.apar_rUseSnd,
};
} else { // Not creating an asset
retrievedAssetInfo = jotaiStore.get(txnDataAtoms.retrievedAssetInfo);
retrievedAssetInfo = jotaiStore.get(txnDataAtoms.retrievedAssetInfo).value;
if (retrievedAssetInfo) {
// Remove asset addresses from asset information
retrievedAssetInfo = {
Expand Down Expand Up @@ -476,7 +476,7 @@ export function extractTxnDataFromAtoms(
afrz: assetFreezeForm.values.afrz,
};

retrievedAssetInfo = jotaiStore.get(txnDataAtoms.retrievedAssetInfo);
retrievedAssetInfo = jotaiStore.get(txnDataAtoms.retrievedAssetInfo).value;
if (retrievedAssetInfo) {
// Remove asset addresses from asset information
retrievedAssetInfo = {
Expand Down

0 comments on commit 56b99bb

Please sign in to comment.