Skip to content

Commit

Permalink
Merge pull request #373 from algorandfoundation/txn-wizard-tweaks
Browse files Browse the repository at this point in the history
tweaks to txn wizard and app lab based on feedback
  • Loading branch information
neilcampbell authored Jan 7, 2025
2 parents fd29116 + 4d8efe5 commit 47f5489
Show file tree
Hide file tree
Showing 14 changed files with 79 additions and 26 deletions.
7 changes: 3 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions src/features/app-interfaces/components/create/deploy-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function CreateAppInterfaceInner() {

if (state.matches('createAppInterface')) {
return (
<div className={cn('relative xl:w-3/4 grid grid-cols-1 lg:grid-cols-2 gap-4')}>
<div className={cn('relative grid grid-cols-1 lg:grid-cols-2 gap-4')}>
<FromAppIdCard machine={machine} />
<FromDeploymentCard machine={machine} />
<Button type="button" variant="outline" className="mr-auto w-24" onClick={back} icon={<ArrowLeft size={16} />}>
Expand All @@ -104,13 +104,13 @@ function CreateAppInterfaceInner() {
)
} else if (state.matches('fromAppId')) {
return (
<div className="relative xl:w-3/4">
<div className="relative">
<FromAppIdWorkflow machine={machine} />
</div>
)
} else if (state.matches('fromAppDeployment')) {
return (
<div className="relative xl:w-3/4">
<div className="relative">
<FromDeploymentWorkflow machine={machine} />
</div>
)
Expand Down
9 changes: 8 additions & 1 deletion src/features/common/components/wallet-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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')
Expand Down
4 changes: 2 additions & 2 deletions src/features/forms/components/address-form-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<>
Expand Down
2 changes: 1 addition & 1 deletion src/features/fund/components/localnet-funding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export function LocalnetFunding() {
</AccountLink>
&nbsp;was created.
<br />
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.
</p>
)}
</AccordionContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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',
Expand Down
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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(),
Expand All @@ -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]
Expand All @@ -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,
Expand Down Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) => (
<div key={`${methodName}-arg-${index}`} className="relative space-y-1.5 text-sm [&_label]:mt-1.5">
<h5 className="text-primary">{`Argument ${index + 1}`}</h5>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ const getTableColumns = ({
return (
<DescriptionList
items={asDescriptionListItems(transaction, transactionPositions, onEditTransaction)}
dtClassName="w-[9.5rem] truncate"
dtClassName="w-[10rem] truncate"
/>
)
},
Expand Down Expand Up @@ -322,7 +322,7 @@ const getSubTransactionsTableColumns = ({
) : (
<DescriptionList
items={asDescriptionListItems(transaction, transactionPositions, onEditTransaction)}
dtClassName="w-[9.5rem] truncate"
dtClassName="w-[10rem] truncate"
/>
)}
<div className="absolute -bottom-2 right-1/2 z-10">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,14 @@ const asAppCallTransaction = (transaction: BuildAppCallTransactionResult): Descr
dt: 'Sender',
dd: <AddressOrNfdLink address={params.sender} />,
},
...(transaction.extraProgramPages !== undefined
? [
{
dt: 'Extra program pages',
dd: transaction.extraProgramPages,
},
]
: []),
...(transaction.args.length > 0
? [
{
Expand Down Expand Up @@ -423,6 +431,14 @@ const asMethodCallTransaction = (
dt: 'Sender',
dd: <AddressOrNfdLink address={params.sender} />,
},
...(transaction.extraProgramPages !== undefined
? [
{
dt: 'Extra program pages',
dd: transaction.extraProgramPages,
},
]
: []),
...(transaction.methodDefinition.arguments.length > 0
? [
{
Expand Down
2 changes: 2 additions & 0 deletions src/features/transaction-wizard/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ type CommonBuildTransactionResult = {
export type BuildAppCallTransactionResult = CommonBuildTransactionResult & {
type: BuildableTransactionType.AppCall
applicationId: ApplicationId
extraProgramPages?: number
args: string[]
accounts?: Address[]
foreignAssets?: AssetId[]
Expand All @@ -98,6 +99,7 @@ export type BuildMethodCallTransactionResult = CommonBuildTransactionResult & {
applicationId: ApplicationId
appSpec: Arc56Contract
methodDefinition: MethodDefinition
extraProgramPages?: number
methodArgs: MethodCallArg[]
accounts?: Address[]
foreignAssets?: AssetId[]
Expand Down
11 changes: 10 additions & 1 deletion src/features/wallet/components/connect-wallet-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
Expand Down

0 comments on commit 47f5489

Please sign in to comment.