)
} else if (state.matches('fromAppDeployment')) {
return (
-
+
)
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/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/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/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/app-call-transaction-builder.tsx b/src/features/transaction-wizard/components/app-call-transaction-builder.tsx
index 1feb5f1e3..f7a272926 100644
--- a/src/features/transaction-wizard/components/app-call-transaction-builder.tsx
+++ b/src/features/transaction-wizard/components/app-call-transaction-builder.tsx
@@ -1,5 +1,5 @@
import algosdk from 'algosdk'
-import { bigIntSchema } from '@/features/forms/data/common'
+import { bigIntSchema, numberSchema } from '@/features/forms/data/common'
import { senderFieldSchema, commonSchema, onCompleteFieldSchema, onCompleteOptions } from '@/features/transaction-wizard/data/common'
import { z } from 'zod'
import { zfd } from 'zod-form-data'
@@ -22,6 +22,7 @@ const formData = zfd.formData({
...senderFieldSchema,
...onCompleteFieldSchema,
applicationId: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' })),
+ extraProgramPages: numberSchema(z.number().min(0).max(3).optional()),
args: zfd.repeatableOfType(
z.object({
id: z.string(),
@@ -47,11 +48,12 @@ export function AppCallTransactionBuilder({ mode, transaction, activeAccount, de
type: BuildableTransactionType.AppCall,
applicationId: Number(values.applicationId),
sender: values.sender,
+ onComplete: Number(values.onComplete),
+ extraProgramPages: values.extraProgramPages,
fee: values.fee,
validRounds: values.validRounds,
args: values.args.map((arg) => arg.value),
note: values.note,
- onComplete: Number(values.onComplete),
})
},
[onSubmit, transaction?.id]
@@ -63,6 +65,7 @@ export function AppCallTransactionBuilder({ mode, transaction, activeAccount, de
applicationId: transaction.applicationId !== undefined ? BigInt(transaction.applicationId) : undefined,
sender: transaction.sender,
onComplete: transaction.onComplete.toString(),
+ extraProgramPages: transaction.extraProgramPages,
fee: transaction.fee,
validRounds: transaction.validRounds,
note: transaction.note,
@@ -116,6 +119,13 @@ export function AppCallTransactionBuilder({ mode, transaction, activeAccount, de
label: 'Sender',
helpText: 'Account to call from. Sends the transaction and pays the fee',
})}
+ {defaultValues.applicationId === 0n &&
+ helper.numberField({
+ field: 'extraProgramPages',
+ label: 'Extra program pages',
+ helpText:
+ 'Number of additional pages allocated to the approval and clear state programs. If empty this will be calculated automatically',
+ })}
{helper.arrayField({
field: 'args',
label: 'Arguments',
diff --git a/src/features/transaction-wizard/components/method-call-transaction-builder.tsx b/src/features/transaction-wizard/components/method-call-transaction-builder.tsx
index 45571e241..15c4d0796 100644
--- a/src/features/transaction-wizard/components/method-call-transaction-builder.tsx
+++ b/src/features/transaction-wizard/components/method-call-transaction-builder.tsx
@@ -1,5 +1,5 @@
import algosdk from 'algosdk'
-import { bigIntSchema } from '@/features/forms/data/common'
+import { bigIntSchema, numberSchema } from '@/features/forms/data/common'
import {
commonSchema,
onCompleteFieldSchema,
@@ -46,6 +46,7 @@ const appCallFormSchema = {
...onCompleteFieldSchema,
applicationId: bigIntSchema(z.bigint({ required_error: 'Required', invalid_type_error: 'Required' })),
methodName: zfd.text(),
+ extraProgramPages: numberSchema(z.number().min(0).max(3).optional()),
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const baseFormData = zfd.formData(appCallFormSchema)
@@ -156,6 +157,7 @@ export function MethodCallTransactionBuilder({
methodDefinition: methodDefinition,
onComplete: Number(values.onComplete),
sender: values.sender,
+ extraProgramPages: values.extraProgramPages,
appSpec: appSpec!,
methodArgs: methodArgs,
fee: values.fee,
@@ -188,6 +190,7 @@ export function MethodCallTransactionBuilder({
sender: transaction.sender,
onComplete: transaction.onComplete.toString(),
methodName: transaction.methodDefinition.name,
+ extraProgramPages: transaction.extraProgramPages,
fee: transaction.fee,
validRounds: transaction.validRounds,
note: transaction.note,
@@ -387,6 +390,13 @@ function FormInner({ helper, onAppIdChanged, onMethodNameChanged, methodDefiniti
label: 'Sender',
helpText: 'Account to call from. Sends the transaction and pays the fee',
})}
+ {appId === 0n &&
+ helper.numberField({
+ field: 'extraProgramPages',
+ label: 'Extra program pages',
+ helpText:
+ 'Number of additional pages allocated to the approval and clear state programs. If empty this will be calculated automatically',
+ })}
{abiMethodArgs.map((arg, index) => (
{`Argument ${index + 1}`}
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)
diff --git a/src/features/transaction-wizard/components/transactions-table.tsx b/src/features/transaction-wizard/components/transactions-table.tsx
index 876398b25..81ea93243 100644
--- a/src/features/transaction-wizard/components/transactions-table.tsx
+++ b/src/features/transaction-wizard/components/transactions-table.tsx
@@ -228,7 +228,7 @@ const getTableColumns = ({
return (
)
},
@@ -322,7 +322,7 @@ const getSubTransactionsTableColumns = ({
) : (
)}
diff --git a/src/features/transaction-wizard/mappers/as-description-list-items.tsx b/src/features/transaction-wizard/mappers/as-description-list-items.tsx
index f0e435da5..edc8a52f3 100644
--- a/src/features/transaction-wizard/mappers/as-description-list-items.tsx
+++ b/src/features/transaction-wizard/mappers/as-description-list-items.tsx
@@ -378,6 +378,14 @@ const asAppCallTransaction = (transaction: BuildAppCallTransactionResult): Descr
dt: 'Sender',
dd:
,
},
+ ...(transaction.extraProgramPages !== undefined
+ ? [
+ {
+ dt: 'Extra program pages',
+ dd: transaction.extraProgramPages,
+ },
+ ]
+ : []),
...(transaction.args.length > 0
? [
{
@@ -423,6 +431,14 @@ const asMethodCallTransaction = (
dt: 'Sender',
dd:
,
},
+ ...(transaction.extraProgramPages !== undefined
+ ? [
+ {
+ dt: 'Extra program pages',
+ dd: transaction.extraProgramPages,
+ },
+ ]
+ : []),
...(transaction.methodDefinition.arguments.length > 0
? [
{
diff --git a/src/features/transaction-wizard/models/index.ts b/src/features/transaction-wizard/models/index.ts
index 8a0052ae3..84f231a9f 100644
--- a/src/features/transaction-wizard/models/index.ts
+++ b/src/features/transaction-wizard/models/index.ts
@@ -80,6 +80,7 @@ type CommonBuildTransactionResult = {
export type BuildAppCallTransactionResult = CommonBuildTransactionResult & {
type: BuildableTransactionType.AppCall
applicationId: ApplicationId
+ extraProgramPages?: number
args: string[]
accounts?: Address[]
foreignAssets?: AssetId[]
@@ -98,6 +99,7 @@ export type BuildMethodCallTransactionResult = CommonBuildTransactionResult & {
applicationId: ApplicationId
appSpec: Arc56Contract
methodDefinition: MethodDefinition
+ extraProgramPages?: number
methodArgs: MethodCallArg[]
accounts?: Address[]
foreignAssets?: AssetId[]
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()