Skip to content

Commit

Permalink
Change sorting of smart-contract methods to ignore case (#2409)
Browse files Browse the repository at this point in the history
Fixes #2388
  • Loading branch information
tom2drum authored Nov 25, 2024
1 parent 90b760e commit 9a08b89
Show file tree
Hide file tree
Showing 11 changed files with 42 additions and 37 deletions.
16 changes: 8 additions & 8 deletions ui/address/AddressContract.pw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ test.describe('ABI functionality', () => {

await expect(component.getByRole('button', { name: 'Connect wallet' })).toBeVisible();
await component.getByText('setReserveInterestRateStrategyAddress').click();
await expect(component.getByLabel('4.').getByRole('button', { name: 'Simulate' })).toBeEnabled();
await expect(component.getByLabel('4.').getByRole('button', { name: 'Write' })).toBeEnabled();
await expect(component.getByLabel('9.').getByRole('button', { name: 'Simulate' })).toBeEnabled();
await expect(component.getByLabel('9.').getByRole('button', { name: 'Write' })).toBeEnabled();

await component.getByText('pause').click();
await expect(component.getByLabel('7.').getByRole('button', { name: 'Simulate' })).toBeHidden();
await expect(component.getByLabel('7.').getByRole('button', { name: 'Write' })).toBeEnabled();
await expect(component.getByLabel('5.').getByRole('button', { name: 'Simulate' })).toBeHidden();
await expect(component.getByLabel('5.').getByRole('button', { name: 'Write' })).toBeEnabled();
});

test('write, no wallet client', async({ render, createSocket, mockEnvs }) => {
Expand All @@ -86,11 +86,11 @@ test.describe('ABI functionality', () => {

await expect(component.getByRole('button', { name: 'Connect wallet' })).toBeHidden();
await component.getByText('setReserveInterestRateStrategyAddress').click();
await expect(component.getByLabel('4.').getByRole('button', { name: 'Simulate' })).toBeEnabled();
await expect(component.getByLabel('4.').getByRole('button', { name: 'Write' })).toBeDisabled();
await expect(component.getByLabel('9.').getByRole('button', { name: 'Simulate' })).toBeEnabled();
await expect(component.getByLabel('9.').getByRole('button', { name: 'Write' })).toBeDisabled();

await component.getByText('pause').click();
await expect(component.getByLabel('7.').getByRole('button', { name: 'Simulate' })).toBeHidden();
await expect(component.getByLabel('7.').getByRole('button', { name: 'Write' })).toBeDisabled();
await expect(component.getByLabel('5.').getByRole('button', { name: 'Simulate' })).toBeHidden();
await expect(component.getByLabel('5.').getByRole('button', { name: 'Write' })).toBeDisabled();
});
});
9 changes: 2 additions & 7 deletions ui/address/contract/methods/ContractMethodsCustom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import ContractCustomAbiAlert from './ContractCustomAbiAlert';
import ContractMethodsContainer from './ContractMethodsContainer';
import ContractMethodsFilters from './ContractMethodsFilters';
import useMethodsFilters from './useMethodsFilters';
import { enrichWithMethodId, isMethod } from './utils';
import { formatAbi } from './utils';

interface Props {
isLoading?: boolean;
Expand Down Expand Up @@ -52,12 +52,7 @@ const ContractMethodsCustom = ({ isLoading: isLoadingProp }: Props) => {
contract_address_hash: addressHash,
} : undefined);

const abi = React.useMemo(() => {
return currentInfo?.abi
.filter(isMethod)
.map(enrichWithMethodId) ?? [];
}, [ currentInfo ]);

const abi = React.useMemo(() => formatAbi(currentInfo?.abi || []), [ currentInfo ]);
const filters = useMethodsFilters({ abi });

const updateButton = React.useMemo(() => {
Expand Down
7 changes: 2 additions & 5 deletions ui/address/contract/methods/ContractMethodsMudSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import ContractConnectWallet from './ContractConnectWallet';
import ContractMethodsContainer from './ContractMethodsContainer';
import ContractMethodsFilters from './ContractMethodsFilters';
import useMethodsFilters from './useMethodsFilters';
import { enrichWithMethodId, isMethod } from './utils';
import { formatAbi } from './utils';

interface Props {
items: Array<SmartContractMudSystemItem>;
Expand Down Expand Up @@ -42,10 +42,7 @@ const ContractMethodsMudSystem = ({ items }: Props) => {
setSelectedItem(item as SmartContractMudSystemItem);
}, []);

const abi = React.useMemo(() => {
return systemInfoQuery.data?.abi?.filter(isMethod).map(enrichWithMethodId) || [];
}, [ systemInfoQuery.data?.abi ]);

const abi = React.useMemo(() => formatAbi(systemInfoQuery.data?.abi || []), [ systemInfoQuery.data?.abi ]);
const filters = useMethodsFilters({ abi });

return (
Expand Down
7 changes: 2 additions & 5 deletions ui/address/contract/methods/ContractMethodsProxy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import ContractConnectWallet from './ContractConnectWallet';
import ContractMethodsContainer from './ContractMethodsContainer';
import ContractMethodsFilters from './ContractMethodsFilters';
import useMethodsFilters from './useMethodsFilters';
import { enrichWithMethodId, isMethod } from './utils';
import { formatAbi } from './utils';

interface Props {
implementations: Array<AddressImplementation>;
Expand All @@ -36,10 +36,7 @@ const ContractMethodsProxy = ({ implementations, isLoading: isInitialLoading }:
},
});

const abi = React.useMemo(() => {
return contractQuery.data?.abi?.filter(isMethod).map(enrichWithMethodId) || [];
}, [ contractQuery.data?.abi ]);

const abi = React.useMemo(() => formatAbi(contractQuery.data?.abi || []), [ contractQuery.data?.abi ]);
const filters = useMethodsFilters({ abi });

return (
Expand Down
13 changes: 7 additions & 6 deletions ui/address/contract/methods/ContractMethodsRegular.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Flex } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';

import type { SmartContractMethod } from './types';
import type { Abi } from 'viem';

import getQueryParamString from 'lib/router/getQueryParamString';

Expand All @@ -11,9 +10,10 @@ import ContractConnectWallet from './ContractConnectWallet';
import ContractMethodsContainer from './ContractMethodsContainer';
import ContractMethodsFilters from './ContractMethodsFilters';
import useMethodsFilters from './useMethodsFilters';
import { formatAbi } from './utils';

interface Props {
abi: Array<SmartContractMethod>;
abi: Abi;
isLoading?: boolean;
}

Expand All @@ -24,7 +24,8 @@ const ContractMethodsRegular = ({ abi, isLoading }: Props) => {
const tab = getQueryParamString(router.query.tab);
const addressHash = getQueryParamString(router.query.hash);

const filters = useMethodsFilters({ abi });
const formattedAbi = React.useMemo(() => formatAbi(abi), [ abi ]);
const filters = useMethodsFilters({ abi: formattedAbi });

return (
<Flex flexDir="column" rowGap={ 6 }>
Expand All @@ -35,8 +36,8 @@ const ContractMethodsRegular = ({ abi, isLoading }: Props) => {
onChange={ filters.onChange }
isLoading={ isLoading }
/>
<ContractMethodsContainer isLoading={ isLoading } isEmpty={ abi.length === 0 } type={ filters.methodType }>
<ContractAbi abi={ abi } tab={ tab } addressHash={ addressHash } visibleItems={ filters.visibleItems }/>
<ContractMethodsContainer isLoading={ isLoading } isEmpty={ formattedAbi.length === 0 } type={ filters.methodType }>
<ContractAbi abi={ formattedAbi } tab={ tab } addressHash={ addressHash } visibleItems={ filters.visibleItems }/>
</ContractMethodsContainer>
</Flex>
);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions ui/address/contract/methods/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@ export const enrichWithMethodId = (method: AbiFunction | AbiFallback | AbiReceiv
}
};

const getNameForSorting = (method: SmartContractMethod | AbiFallback | AbiReceive) => {
if ('name' in method) {
return method.name;
}

return method.type === 'fallback' ? 'fallback' : 'receive';
};

export const formatAbi = (abi: Abi) => {
return abi
.filter(isMethod)
.map(enrichWithMethodId)
.sort((a, b) => {
const aName = getNameForSorting(a);
const bName = getNameForSorting(b);
return aName.localeCompare(bName);
});
};

export const TYPE_FILTER_OPTIONS: Array<{ value: MethodType; title: string }> = [
{ value: 'all', title: 'All' },
{ value: 'read', title: 'Read' },
Expand Down
8 changes: 2 additions & 6 deletions ui/address/contract/useContractTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import ContractMethodsCustom from 'ui/address/contract/methods/ContractMethodsCu
import ContractMethodsMudSystem from 'ui/address/contract/methods/ContractMethodsMudSystem';
import ContractMethodsProxy from 'ui/address/contract/methods/ContractMethodsProxy';
import ContractMethodsRegular from 'ui/address/contract/methods/ContractMethodsRegular';
import { enrichWithMethodId, isMethod } from 'ui/address/contract/methods/utils';
import ContentLoader from 'ui/shared/ContentLoader';

import type { CONTRACT_MAIN_TAB_IDS } from './utils';
Expand Down Expand Up @@ -68,8 +67,6 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
onSocketError: enableQuery,
});

const methods = React.useMemo(() => contractQuery.data?.abi?.filter(isMethod).map(enrichWithMethodId) ?? [], [ contractQuery.data?.abi ]);

const verifiedImplementations = React.useMemo(() => {
return data?.implementations?.filter(({ name, address }) => name && address && address !== data?.hash) || [];
}, [ data?.hash, data?.implementations ]);
Expand All @@ -83,10 +80,10 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
component: <ContractDetails mainContractQuery={ contractQuery } channel={ channel } addressHash={ data.hash }/>,
subTabs: CONTRACT_DETAILS_TAB_IDS as unknown as Array<string>,
},
methods.length > 0 && {
contractQuery.data?.abi && {
id: [ 'read_write_contract' as const, 'read_contract' as const, 'write_contract' as const ],
title: 'Read/Write contract',
component: <ContractMethodsRegular abi={ methods } isLoading={ contractQuery.isPlaceholderData }/>,
component: <ContractMethodsRegular abi={ contractQuery.data.abi } isLoading={ contractQuery.isPlaceholderData }/>,
},
verifiedImplementations.length > 0 && {
id: [ 'read_write_proxy' as const, 'read_proxy' as const, 'write_proxy' as const ],
Expand All @@ -112,7 +109,6 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
data?.hash,
contractQuery,
channel,
methods,
verifiedImplementations,
hasMudTab,
mudSystemsQuery.isPlaceholderData,
Expand Down

0 comments on commit 9a08b89

Please sign in to comment.