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

Support custom MUD system ABI #2296

Merged
merged 4 commits into from
Oct 28, 2024
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
14 changes: 14 additions & 0 deletions lib/api/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ import type {
SmartContract,
SmartContractVerificationConfigRaw,
SmartContractSecurityAudits,
SmartContractMudSystemsResponse,
SmartContractMudSystemInfo,
} from 'types/api/contract';
import type { VerifiedContractsResponse, VerifiedContractsFilters, VerifiedContractsCounters } from 'types/api/contracts';
import type {
Expand Down Expand Up @@ -767,6 +769,16 @@ export const RESOURCES = {
pathParams: [ 'hash' as const, 'table_id' as const, 'record_id' as const ],
},

contract_mud_systems: {
path: '/api/v2/mud/worlds/:hash/systems',
pathParams: [ 'hash' as const ],
},

contract_mud_system_info: {
path: '/api/v2/mud/worlds/:hash/systems/:system_address',
pathParams: [ 'hash' as const, 'system_address' as const ],
},

// arbitrum L2
arbitrum_l2_messages: {
path: '/api/v2/arbitrum/messages/:direction',
Expand Down Expand Up @@ -1195,6 +1207,8 @@ Q extends 'address_mud_tables' ? AddressMudTables :
Q extends 'address_mud_tables_count' ? number :
Q extends 'address_mud_records' ? AddressMudRecords :
Q extends 'address_mud_record' ? AddressMudRecord :
Q extends 'contract_mud_systems' ? SmartContractMudSystemsResponse :
Q extends 'contract_mud_system_info' ? SmartContractMudSystemInfo :
Q extends 'address_epoch_rewards' ? AddressEpochRewardsResponse :
Q extends 'withdrawals' ? WithdrawalsResponse :
Q extends 'withdrawals_counters' ? WithdrawalsCounters :
Expand Down
34 changes: 32 additions & 2 deletions lib/hooks/useContractTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import useSocketChannel from 'lib/socket/useSocketChannel';
import * as stubs from 'stubs/contract';
import ContractCode from 'ui/address/contract/ContractCode';
import ContractMethodsCustom from 'ui/address/contract/methods/ContractMethodsCustom';
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 { divideAbiIntoMethodTypes } from 'ui/address/contract/methods/utils';
import ContentLoader from 'ui/shared/ContentLoader';

const CONTRACT_TAB_IDS = [
'contract_code',
Expand All @@ -24,6 +26,7 @@ const CONTRACT_TAB_IDS = [
'write_contract_rpc',
'write_proxy',
'write_custom_methods',
'mud_system',
] as const;

interface ContractTab {
Expand All @@ -37,7 +40,7 @@ interface ReturnType {
isLoading: boolean;
}

export default function useContractTabs(data: Address | undefined, isPlaceholderData: boolean): ReturnType {
export default function useContractTabs(data: Address | undefined, isPlaceholderData: boolean, hasMudTab?: boolean): ReturnType {
const [ isQueryEnabled, setIsQueryEnabled ] = React.useState(false);

const router = useRouter();
Expand Down Expand Up @@ -65,6 +68,15 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
},
});

const mudSystemsQuery = useApiQuery('contract_mud_systems', {
pathParams: { hash: data?.hash },
queryOptions: {
enabled: isEnabled && isQueryEnabled && hasMudTab,
refetchOnMount: false,
placeholderData: stubs.MUD_SYSTEMS,
},
});

const channel = useSocketChannel({
topic: `addresses:${ data?.hash?.toLowerCase() }`,
isDisabled: !isEnabled,
Expand Down Expand Up @@ -136,8 +148,26 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
/>
),
},
hasMudTab && {
id: 'mud_system' as const,
title: 'MUD System',
component: mudSystemsQuery.isPlaceholderData ?
<ContentLoader/> :
<ContractMethodsMudSystem items={ mudSystemsQuery.data?.items ?? [] }/>,
},
].filter(Boolean),
isLoading: contractQuery.isPlaceholderData,
};
}, [ contractQuery, channel, data?.hash, verifiedImplementations, methods.read, methods.write, methodsCustomAbi.read, methodsCustomAbi.write ]);
}, [
contractQuery,
channel,
data?.hash,
methods.read,
methods.write,
methodsCustomAbi.read,
methodsCustomAbi.write,
verifiedImplementations,
mudSystemsQuery,
hasMudTab,
]);
}
13 changes: 11 additions & 2 deletions stubs/contract.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { SmartContract } from 'types/api/contract';
import type { SmartContract, SmartContractMudSystemsResponse } from 'types/api/contract';
import type { VerifiedContract, VerifiedContractsCounters } from 'types/api/contracts';

import type { SolidityScanReport } from 'lib/solidityScan/schema';

import { ADDRESS_PARAMS } from './addressParams';
import { ADDRESS_PARAMS, ADDRESS_HASH } from './addressParams';

export const CONTRACT_CODE_UNVERIFIED = {
creation_bytecode: '0x60806040526e',
Expand Down Expand Up @@ -98,3 +98,12 @@ export const SOLIDITY_SCAN_REPORT: SolidityScanReport = {
scanner_reference_url: 'https://solidityscan.com/quickscan/0xc1EF7811FF2ebFB74F80ed7423f2AdAA37454be2/blockscout/eth-goerli?ref=blockscout',
},
};

export const MUD_SYSTEMS: SmartContractMudSystemsResponse = {
items: [
{
name: 'sy.AccessManagement',
address: ADDRESS_HASH,
},
],
};
16 changes: 16 additions & 0 deletions types/api/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,19 @@ export type SmartContractSecurityAuditSubmission = {
'audit_publish_date': string;
'comment'?: string;
}

// MUD SYSTEM

export interface SmartContractMudSystemsResponse {
items: Array<SmartContractMudSystemItem>;
}

export interface SmartContractMudSystemItem {
address: string;
name: string;
}

export interface SmartContractMudSystemInfo {
name: string;
abi: Abi;
}
4 changes: 3 additions & 1 deletion ui/address/contract/methods/ContractAbi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ interface Props {
abi: Array<SmartContractMethod>;
addressHash: string;
tab: string;
sourceAddress?: string;
}

const ContractAbi = ({ abi, addressHash, tab }: Props) => {
const ContractAbi = ({ abi, addressHash, sourceAddress, tab }: Props) => {
const [ expandedSections, setExpandedSections ] = React.useState<Array<number>>(abi.length === 1 ? [ 0 ] : []);
const [ id, setId ] = React.useState(0);

Expand Down Expand Up @@ -61,6 +62,7 @@ const ContractAbi = ({ abi, addressHash, tab }: Props) => {
id={ id }
index={ index }
addressHash={ addressHash }
sourceAddress={ sourceAddress }
tab={ tab }
onSubmit={ handleFormSubmit }
/>
Expand Down
6 changes: 4 additions & 2 deletions ui/address/contract/methods/ContractAbiItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ interface Props {
index: number;
id: number;
addressHash: string;
sourceAddress?: string;
tab: string;
onSubmit: FormSubmitHandler;
}

const ContractAbiItem = ({ data, index, id, addressHash, tab, onSubmit }: Props) => {
const ContractAbiItem = ({ data, index, id, addressHash, sourceAddress, tab, onSubmit }: Props) => {
const [ attempt, setAttempt ] = React.useState(0);

const url = React.useMemo(() => {
Expand All @@ -36,10 +37,11 @@ const ContractAbiItem = ({ data, index, id, addressHash, tab, onSubmit }: Props)
query: {
hash: addressHash ?? '',
tab,
...(sourceAddress ? { source_address: sourceAddress } : {}),
},
hash: data.method_id,
});
}, [ addressHash, data, tab ]);
}, [ addressHash, data, tab, sourceAddress ]);

const handleCopyLinkClick = React.useCallback((event: React.MouseEvent) => {
event.stopPropagation();
Expand Down
66 changes: 0 additions & 66 deletions ui/address/contract/methods/ContractImplementationAddress.tsx

This file was deleted.

8 changes: 5 additions & 3 deletions ui/address/contract/methods/ContractMethods.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ interface Props {
isLoading?: boolean;
isError?: boolean;
type: MethodType;
sourceAddress?: string;
}

const ContractMethods = ({ abi, isLoading, isError, type }: Props) => {
const ContractMethods = ({ abi, isLoading, isError, type, sourceAddress }: Props) => {

const router = useRouter();

Expand All @@ -32,10 +33,11 @@ const ContractMethods = ({ abi, isLoading, isError, type }: Props) => {
}

if (abi.length === 0) {
return <span>No public { type } functions were found for this contract.</span>;
const typeText = type === 'all' ? '' : type;
return <span>No public { typeText } functions were found for this contract.</span>;
}

return <ContractAbi abi={ abi } tab={ tab } addressHash={ addressHash }/>;
return <ContractAbi abi={ abi } tab={ tab } addressHash={ addressHash } sourceAddress={ sourceAddress }/>;
};

export default React.memo(ContractMethods);
68 changes: 68 additions & 0 deletions ui/address/contract/methods/ContractMethodsMudSystem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Box } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';

import type { SmartContractMudSystemItem } from 'types/api/contract';

import useApiQuery from 'lib/api/useApiQuery';
import getQueryParamString from 'lib/router/getQueryParamString';

import ContractConnectWallet from './ContractConnectWallet';
import ContractMethods from './ContractMethods';
import type { Item } from './ContractSourceAddressSelector';
import ContractSourceAddressSelector from './ContractSourceAddressSelector';
import { enrichWithMethodId, isMethod } from './utils';

interface Props {
items: Array<SmartContractMudSystemItem>;
}

const ContractMethodsMudSystem = ({ items }: Props) => {

const router = useRouter();

const addressHash = getQueryParamString(router.query.hash);
const contractAddress = getQueryParamString(router.query.source_address);

const [ selectedItem, setSelectedItem ] = React.useState(items.find((item) => item.address === contractAddress) || items[0]);

const systemInfoQuery = useApiQuery('contract_mud_system_info', {
pathParams: { hash: addressHash, system_address: selectedItem.address },
queryOptions: {
enabled: Boolean(selectedItem?.address),
refetchOnMount: false,
},
});

const handleItemSelect = React.useCallback((item: Item) => {
setSelectedItem(item as SmartContractMudSystemItem);
}, []);

if (items.length === 0) {
return <span>No MUD System found for this contract.</span>;
}

const abi = systemInfoQuery.data?.abi?.filter(isMethod).map(enrichWithMethodId) || [];

return (
<Box>
<ContractConnectWallet/>
<ContractSourceAddressSelector
items={ items }
selectedItem={ selectedItem }
onItemSelect={ handleItemSelect }
label="System address"
/>
<ContractMethods
key={ selectedItem.address }
abi={ abi }
isLoading={ systemInfoQuery.isPending }
isError={ systemInfoQuery.isError }
sourceAddress={ selectedItem.address }
type="all"
/>
</Box>
);
};

export default React.memo(ContractMethodsMudSystem);
Loading
Loading