From ec946d8a89758f0efa94167ad661265ca10981cf Mon Sep 17 00:00:00 2001 From: Neil Campbell Date: Mon, 6 Jan 2025 16:02:20 +0800 Subject: [PATCH 1/3] chore: allow 0 values for payment amount --- package-lock.json | 7 +++---- src/features/forms/components/address-form-item.tsx | 4 ++-- .../components/account-close-transaction-builder.tsx | 4 ++-- .../components/payment-transaction-builder.tsx | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 118503e4c..429ed2855 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10004,16 +10004,15 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, diff --git a/src/features/forms/components/address-form-item.tsx b/src/features/forms/components/address-form-item.tsx index a1e435b53..455cfab12 100644 --- a/src/features/forms/components/address-form-item.tsx +++ b/src/features/forms/components/address-form-item.tsx @@ -49,10 +49,10 @@ export function AddressFormItem({ field, resolvedAddressField, label, ...props } useEffect(() => { if (value && isAddress(value)) { setAddress(value) - } else if (value && !isAddress(value) && !isNfd(value)) { + } else if ((!value && resolvedAddress) || (value && !isAddress(value) && !isNfd(value))) { setAddress('') } - }, [setAddress, value]) + }, [resolvedAddress, setAddress, value]) return ( <> diff --git a/src/features/transaction-wizard/components/account-close-transaction-builder.tsx b/src/features/transaction-wizard/components/account-close-transaction-builder.tsx index f16b65f4b..1410f5b42 100644 --- a/src/features/transaction-wizard/components/account-close-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/account-close-transaction-builder.tsx @@ -28,7 +28,7 @@ const formSchema = z ...senderFieldSchema, closeRemainderTo: addressFieldSchema, receiver: optionalAddressFieldSchema, - amount: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' }).min(0.000001).optional()), + amount: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' }).min(0).optional()), }) .superRefine((data, ctx) => { if (data.amount && data.amount > 0 && (!data.receiver || !data.receiver.resolvedAddress)) { @@ -39,7 +39,7 @@ const formSchema = z }) } - if (data.receiver && data.receiver.resolvedAddress && !data.amount) { + if (data.receiver && data.receiver.resolvedAddress && data.amount == undefined) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Required', diff --git a/src/features/transaction-wizard/components/payment-transaction-builder.tsx b/src/features/transaction-wizard/components/payment-transaction-builder.tsx index f8c09f7ce..b0bf86be8 100644 --- a/src/features/transaction-wizard/components/payment-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/payment-transaction-builder.tsx @@ -24,7 +24,7 @@ const formSchema = { ...commonSchema, ...senderFieldSchema, ...receiverFieldSchema, - amount: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' }).min(0.000001)), + amount: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' }).min(0)), } const formData = zfd.formData(formSchema) From d9c0a9768b6dd56b0434df52b599a3af001f5ff8 Mon Sep 17 00:00:00 2001 From: Neil Campbell Date: Mon, 6 Jan 2025 17:10:07 +0800 Subject: [PATCH 2/3] feat: dont prompt for default kmd wallet passwords --- src/features/common/components/wallet-provider.tsx | 9 ++++++++- src/features/fund/components/localnet-funding.tsx | 2 +- .../wallet/components/connect-wallet-button.tsx | 11 ++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/features/common/components/wallet-provider.tsx b/src/features/common/components/wallet-provider.tsx index 31935f88a..e290e0267 100644 --- a/src/features/common/components/wallet-provider.tsx +++ b/src/features/common/components/wallet-provider.tsx @@ -5,11 +5,14 @@ import { NetworkConfigWithId } from '@/features/network/data/types' import { NetworkId, SupportedWallet, WalletId, WalletIdConfig, WalletManager } from '@txnlab/use-wallet-react' import { DialogBodyProps, useDialogForm } from '../hooks/use-dialog-form' import { PromptForm } from './prompt-form' +import { loraKmdDevWalletName } from '@/features/fund/utils/kmd' type Props = PropsWithChildren<{ networkConfig: NetworkConfigWithId }> +const kmdWalletsWithoutAPassword = [loraKmdDevWalletName, defaultKmdWallet] + export function WalletProvider({ networkConfig, children }: Props) { const selectedKmdWallet = useSelectedKmdWallet() const { open: openKmdPasswordDialog, dialog: kmdPasswordDialog } = useDialogForm({ @@ -31,14 +34,18 @@ export function WalletProvider({ networkConfig, children }: Props) { return networkConfig.walletIds.reduce( (acc, id) => { if (id === WalletId.KMD && networkConfig.kmd) { + const wallet = selectedKmdWallet ?? defaultKmdWallet acc.push({ id, options: { - wallet: selectedKmdWallet ?? defaultKmdWallet, + wallet, baseServer: networkConfig.kmd.server, token: networkConfig.kmd.token ?? '', port: String(networkConfig.kmd.port), promptForPassword: async () => { + if (kmdWalletsWithoutAPassword.includes(wallet)) { + return '' + } const password = await openKmdPasswordDialog({ message: 'Enter KMD Password' }) if (password == null) { throw new Error('No password provided') diff --git a/src/features/fund/components/localnet-funding.tsx b/src/features/fund/components/localnet-funding.tsx index bccf2824a..21b9c22d7 100644 --- a/src/features/fund/components/localnet-funding.tsx +++ b/src/features/fund/components/localnet-funding.tsx @@ -83,7 +83,7 @@ export function LocalnetFunding() {  was created.
- You can use this account by connecting to the KMD '{loraKmdDevWalletName}' wallet and supplying an empty password. + You can use this account by connecting to the KMD '{loraKmdDevWalletName}' wallet.

)} diff --git a/src/features/wallet/components/connect-wallet-button.tsx b/src/features/wallet/components/connect-wallet-button.tsx index 5f567e235..25716f312 100644 --- a/src/features/wallet/components/connect-wallet-button.tsx +++ b/src/features/wallet/components/connect-wallet-button.tsx @@ -137,6 +137,8 @@ function ConnectedWallet({ activeAddress, activeWalletAccounts, wallets }: Conne ) } +const walletsWithLocalPrompt = [WalletId.KMD.toString(), WalletId.MNEMONIC.toString()] + export function ConnectWalletButton() { const { activeAddress, activeWalletAccounts, wallets } = useWallet() const [dialogOpen, setDialogOpen] = useAtom(walletDialogOpenAtom) @@ -152,7 +154,14 @@ export function ConnectWalletButton() { const selectWallet = useCallback( (wallet: Wallet) => async () => { - setTimeout(() => setDialogOpen(false), 1000) + if (walletsWithLocalPrompt.includes(wallet.id)) { + // The connect dialog for wallet providers handled locally is opened immediately, so the selection dialog should be closed immediately. + setDialogOpen(false) + } else { + // Externally handled connect dialogs have an opening delay, hence the selection dialog should remain open until the connect dialog is visible. + setTimeout(() => setDialogOpen(false), 1000) + } + try { if (wallet.isConnected) { wallet.setActive() From 4d8efe55e9ed9b61fbe61ee563ded5825b02b145 Mon Sep 17 00:00:00 2001 From: Neil Campbell Date: Tue, 7 Jan 2025 01:02:53 +0800 Subject: [PATCH 3/3] feat: support extra program pages when deploying an app --- .../components/create/deploy-app.tsx | 12 ++++++------ .../pages/create-app-interface-page.tsx | 6 +++--- .../components/app-call-transaction-builder.tsx | 14 ++++++++++++-- .../method-call-transaction-builder.tsx | 12 +++++++++++- .../components/transactions-table.tsx | 4 ++-- .../mappers/as-description-list-items.tsx | 16 ++++++++++++++++ src/features/transaction-wizard/models/index.ts | 2 ++ 7 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/features/app-interfaces/components/create/deploy-app.tsx b/src/features/app-interfaces/components/create/deploy-app.tsx index b34940632..2f4d6de4e 100644 --- a/src/features/app-interfaces/components/create/deploy-app.tsx +++ b/src/features/app-interfaces/components/create/deploy-app.tsx @@ -21,7 +21,7 @@ import { isArc32AppSpec, isArc56AppSpec } from '@/features/common/utils' import { asAppCallTransactionParams, asMethodCallParams } from '@/features/transaction-wizard/mappers' import { asArc56AppSpec, asMethodDefinitions } from '@/features/applications/mappers' import { Arc32AppSpec, TemplateParamType } from '../../data/types' -import { CreateOnComplete } from '@algorandfoundation/algokit-utils/types/app-factory' +import { CreateOnComplete, CreateSchema } from '@algorandfoundation/algokit-utils/types/app-factory' import { AppClientBareCallParams, AppClientMethodCallParams } from '@algorandfoundation/algokit-utils/types/app-client' import { MethodDefinition } from '@/features/applications/models' import { DescriptionList, DescriptionListItems } from '@/features/common/components/description-list' @@ -71,23 +71,23 @@ export function DeployApp({ machine }: Props) { const appSpec = state.context.appSpec - const asDeployCreateParams = async ( - transaction: BuildTransactionResult - ): Promise<(AppClientMethodCallParams & CreateOnComplete) | (AppClientBareCallParams & CreateOnComplete)> => { + const asDeployCreateParams = async (transaction: BuildTransactionResult) => { if (transaction.type === BuildableTransactionType.MethodCall) { const { appId: _, ...params } = await asMethodCallParams(transaction) return { ...params, method: params.method.name, onComplete: params.onComplete, - } satisfies AppClientMethodCallParams & CreateOnComplete + extraProgramPages: transaction.extraProgramPages, + } satisfies AppClientMethodCallParams & CreateOnComplete & CreateSchema } else if (transaction.type === BuildableTransactionType.AppCall) { const { appId: _, ...params } = asAppCallTransactionParams(transaction) invariant(params.onComplete !== algosdk.OnApplicationComplete.ClearStateOC, 'Clear state is not supported for app creates') return { ...params, onComplete: params.onComplete, - } satisfies AppClientBareCallParams & CreateOnComplete + extraProgramPages: transaction.extraProgramPages, + } satisfies AppClientBareCallParams & CreateOnComplete & CreateSchema } throw new Error('Invalid transaction type') } diff --git a/src/features/app-interfaces/pages/create-app-interface-page.tsx b/src/features/app-interfaces/pages/create-app-interface-page.tsx index 687bba733..4ff88921a 100644 --- a/src/features/app-interfaces/pages/create-app-interface-page.tsx +++ b/src/features/app-interfaces/pages/create-app-interface-page.tsx @@ -94,7 +94,7 @@ function CreateAppInterfaceInner() { if (state.matches('createAppInterface')) { return ( -
+