Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tweaks to txn wizard and app lab based on feedback #373

Merged
merged 3 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading