diff --git a/src/app/[lang]/txn/compose/components/fields/AssetConfigFields/AssetId.tsx b/src/app/[lang]/txn/compose/components/fields/AssetConfigFields/AssetId.tsx
index 3af5ec2d..a8cae80e 100644
--- a/src/app/[lang]/txn/compose/components/fields/AssetConfigFields/AssetId.tsx
+++ b/src/app/[lang]/txn/compose/components/fields/AssetConfigFields/AssetId.tsx
@@ -95,7 +95,7 @@ export default function AssetId({ t }: { t: TFunction }) {
{t('fields.caid.getting_info')}
>}
{assetInfoSuccess &&
- (retrievedAssetInfo?.name ?? {t('fields.caid.get_info_unknown')})
+ (retrievedAssetInfo?.value?.name ?? {t('fields.caid.get_info_unknown')})
}
{assetInfoFail && <>
diff --git a/src/app/[lang]/txn/compose/components/fields/AssetFreezeFields/AssetId.tsx b/src/app/[lang]/txn/compose/components/fields/AssetFreezeFields/AssetId.tsx
index 340bff1a..614b1905 100644
--- a/src/app/[lang]/txn/compose/components/fields/AssetFreezeFields/AssetId.tsx
+++ b/src/app/[lang]/txn/compose/components/fields/AssetFreezeFields/AssetId.tsx
@@ -91,7 +91,7 @@ export default function AssetId({ t }: { t: TFunction }) {
{t('fields.faid.getting_info')}
>}
{assetInfoSuccess &&
- (retrievedAssetInfo?.name ?? {t('fields.faid.get_info_unknown')})
+ (retrievedAssetInfo?.value?.name ?? {t('fields.faid.get_info_unknown')})
}
{assetInfoFail && <>
diff --git a/src/app/[lang]/txn/compose/components/fields/AssetTransferFields/Amount.tsx b/src/app/[lang]/txn/compose/components/fields/AssetTransferFields/Amount.tsx
index c9a0c8e1..a7ac440f 100644
--- a/src/app/[lang]/txn/compose/components/fields/AssetTransferFields/Amount.tsx
+++ b/src/app/[lang]/txn/compose/components/fields/AssetTransferFields/Amount.tsx
@@ -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 (<>
@@ -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')}
@@ -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 &&
+
+ }
>);
}
diff --git a/src/app/[lang]/txn/compose/components/fields/AssetTransferFields/AssetId.tsx b/src/app/[lang]/txn/compose/components/fields/AssetTransferFields/AssetId.tsx
index bd0c5578..cddc227a 100644
--- a/src/app/[lang]/txn/compose/components/fields/AssetTransferFields/AssetId.tsx
+++ b/src/app/[lang]/txn/compose/components/fields/AssetTransferFields/AssetId.tsx
@@ -84,7 +84,7 @@ export default function AssetId({ t }: { t: TFunction }) {
{t('fields.xaid.getting_info')}
>}
{assetInfoSuccess &&
- (retrievedAssetInfo?.name ?? {t('fields.xaid.get_info_unknown')})
+ (retrievedAssetInfo?.value?.name ?? {t('fields.xaid.get_info_unknown')})
}
{assetInfoFail && <>
diff --git a/src/app/lib/txn-data/atoms.ts b/src/app/lib/txn-data/atoms.ts
index a16f6cf4..ce1dffef 100644
--- a/src/app/lib/txn-data/atoms.ts
+++ b/src/app/lib/txn-data/atoms.ts
@@ -115,7 +115,9 @@ export const close = atomWithValidate('', {
* Retrieved Asset Information
*/
-export const retrievedAssetInfo = atom(undefined);
+export const retrievedAssetInfo = atomWithValidate(undefined, {
+ validate: v => v
+});
/*
* Asset Transfer
diff --git a/src/app/lib/txn-data/field-validation.ts b/src/app/lib/txn-data/field-validation.ts
index 71f48c2a..1454046a 100644
--- a/src/app/lib/txn-data/field-validation.ts
+++ b/src/app/lib/txn-data/field-validation.ts
@@ -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';
@@ -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
diff --git a/src/app/lib/txn-data/stored.ts b/src/app/lib/txn-data/stored.ts
index 476e377f..4fa2632a 100644
--- a/src/app/lib/txn-data/stored.ts
+++ b/src/app/lib/txn-data/stored.ts
@@ -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 = {
@@ -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 = {
@@ -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 = {