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

feat: show more info about contract calls #1749

Merged
merged 19 commits into from
Jan 2, 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
6 changes: 6 additions & 0 deletions .changeset/popular-mirrors-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fuel-wallet/types": minor
"fuels-wallet": minor
---

Add contract logos and names to the transaction screen for better UX.
2 changes: 1 addition & 1 deletion packages/app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ VITE_CRX_NAME="Fuel Wallet Development"
VITE_CRX_VERSION_API="https://fuellabs.github.io/fuels-wallet/latest.json"
VITE_FUEL_PROVIDER_URL=http://localhost:4000/v1/graphql
VITE_FUEL_FAUCET_URL=http://localhost:4040
VITE_EXPLORER_URL=https://app.fuel.network/
VITE_ECOSYSTEM_PROJECTS_URL=https://fuellabs.github.io/fuel-ecosystem/projects.json
VITE_MNEMONIC_WORDS=12
GENESIS_SECRET=0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298
VITE_AUTO_LOCK_IN_MINUTES=1
Expand Down
2 changes: 1 addition & 1 deletion packages/app/.env.production
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ VITE_CRX_VERSION_API="https://fuellabs.github.io/fuels-wallet/latest.json"
VITE_CRX_RELEASE=true
VITE_FUEL_PROVIDER_URL=https://testnet.fuel.network/v1/graphql
VITE_FUEL_FAUCET_URL=https://faucet-testnet.fuel.network/
VITE_EXPLORER_URL=https://app.fuel.network/
VITE_ECOSYSTEM_PROJECTS_URL=https://fuellabs.github.io/fuel-ecosystem/projects.json
VITE_MNEMONIC_WORDS=12
VITE_AUTO_LOCK_IN_MINUTES=2880
VITE_SENTRY_DSN=https://f9a5b923067f4f789fb40ed7eccd6486@o4505280621707264.ingest.sentry.io/4505280648577024
1 change: 1 addition & 0 deletions packages/app/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ declare namespace NodeJS {
VITE_DATABASE_VERSION: string;
readonly VITE_FUEL_PROVIDER_URL: string;
readonly VITE_FUEL_FAUCET_URL: string;
readonly VITE_ECOSYSTEM_PROJECTS_URL: string;
readonly VITE_MNEMONIC_WORDS: string;
readonly VITE_CRX_NAME: string;
readonly VITE_CRX_VERSION_API: string;
Expand Down
2 changes: 0 additions & 2 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"@sentry/react": "8.33.1",
"@storybook/addon-viewport": "7.4.6",
"@storybook/jest": "0.2.3",
"@tanstack/react-query": "5.28.4",
"@xstate/react": "3.2.2",
"compare-versions": "6.1.0",
"cross-fetch": "4.0.0",
Expand Down Expand Up @@ -84,7 +83,6 @@
"@storybook/react-webpack5": "7.4.6",
"@storybook/testing-library": "0.2.2",
"@storybook/theming": "7.4.6",
"@tanstack/react-query-devtools": "5.28.4",
"@testing-library/react": "14.0.0",
"@types/chrome": "0.0.246",
"@types/lodash.debounce": "4.0.7",
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ export const {
VITE_CRX_VERSION_API,
VITE_AUTO_LOCK_IN_MINUTES,
VITE_SENTRY_DSN,
VITE_EXPLORER_URL,
VITE_ECOSYSTEM_PROJECTS_URL,
NODE_ENV,
} = import.meta.env;

export const EXPLORER_URL = VITE_EXPLORER_URL;
export const ECOSYSTEM_PROJECTS_URL = VITE_ECOSYSTEM_PROJECTS_URL;
export const WALLET_NAME = VITE_CRX_NAME;
export const APP_VERSION = VITE_APP_VERSION;
export const DATABASE_VERSION = Number(VITE_DATABASE_VERSION);
Expand Down
18 changes: 10 additions & 8 deletions packages/app/src/networks.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import type { NetworkData } from '@fuel-wallet/types';
import { CHAIN_IDS } from 'fuels';

export const IGNITION_NETWORK: NetworkData = {
name: 'Ignition',
url: 'https://mainnet.fuel.network/v1/graphql',
chainId: CHAIN_IDS.fuel.mainnet,
explorerUrl: 'https://app.fuel.network',
bridgeUrl: 'https://app.fuel.network/bridge',
isSelected: true,
};

export const DEFAULT_NETWORKS: Array<
NetworkData & { faucetUrl?: string; bridgeUrl?: string; hidden?: boolean }
> = [
{
name: 'Ignition',
url: 'https://mainnet.fuel.network/v1/graphql',
chainId: CHAIN_IDS.fuel.mainnet,
explorerUrl: 'https://app.fuel.network',
bridgeUrl: 'https://app.fuel.network/bridge',
isSelected: true,
},
IGNITION_NETWORK,
{
name: 'Fuel Sepolia Testnet',
url: 'https://testnet.fuel.network/v1/graphql',
Expand Down
22 changes: 22 additions & 0 deletions packages/app/src/systems/Contract/hooks/useContractMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Contract } from '@fuel-wallet/types';
import { Services, store } from '~/store';
import type { ContractsMachineState } from '../machines/contractsMachine';

const selectors = {
contract(id: string) {
return (state: ContractsMachineState): Contract | undefined => {
return state.context.contracts?.find(
(contract) => contract.contractId === id
);
};
},
};

export const useContractMetadata = (id: string): Contract | undefined => {
const contract = store.useSelector(
Services.contracts,
selectors.contract(id)
);

return contract;
};
81 changes: 81 additions & 0 deletions packages/app/src/systems/Contract/machines/contractsMachine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { Contract, EcosystemProject } from '@fuel-wallet/types';
import type { InterpreterFrom, StateFrom } from 'xstate';
import { assign, createMachine } from 'xstate';
import { FetchMachine } from '~/systems/Core';

import { EcosystemService } from '~/systems/Ecosystem/services/ecosystem';
import { ContractService } from '../services/contracts';

export type MachineContext = {
contracts?: Contract[];
};

type MachineServices = {
fetchProjects: {
data: EcosystemProject[];
};
};

export const contractsMachine = createMachine(
{
predictableActionArguments: true,

tsTypes: {} as import('./contractsMachine.typegen').Typegen0,
schema: {
context: {} as MachineContext,
services: {} as MachineServices,
},
id: '(machine)',
initial: 'fetching',
states: {
fetching: {
invoke: {
src: 'fetchProjects',
onDone: [
{
target: 'failure',
cond: FetchMachine.hasError,
},
{
target: 'success',
actions: ['assignContracts'],
},
],
},
},
failure: {
after: {
10000: 'fetching',
},
},
success: {
type: 'final',
},
},
},
{
actions: {
assignContracts: assign({
contracts: (_, ev) => {
return ContractService.formatContractsFromEcosystem(ev.data);
},
}),
},
services: {
fetchProjects: FetchMachine.create<
null,
MachineServices['fetchProjects']['data']
>({
showError: false,
maxAttempts: 1,
async fetch() {
return EcosystemService.fetchProjects();
},
}),
},
}
);

export type ContractsMachine = typeof contractsMachine;
export type ContractsMachineState = StateFrom<ContractsMachine>;
export type ContractsMachineService = InterpreterFrom<ContractsMachine>;
24 changes: 24 additions & 0 deletions packages/app/src/systems/Contract/services/contracts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Contract, EcosystemProject } from '@fuel-wallet/types';
import { CHAIN_IDS } from 'fuels';

// biome-ignore lint/complexity/noStaticOnlyClass: <explanation>
export class ContractService {
static formatContractsFromEcosystem(
projects: EcosystemProject[]
): Contract[] {
return projects.flatMap((project) => {
if (!project.contracts?.mainnet) {
return [];
}

return project.contracts.mainnet.map((contract) => {
return {
chainId: CHAIN_IDS.fuel.mainnet,
contractId: contract.id,
name: contract.name,
image: project.image,
};
});
});
}
}
6 changes: 3 additions & 3 deletions packages/app/src/systems/Core/utils/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import type {
import Dexie, { type DbEvents, type PromiseExtended, type Table } from 'dexie';
import 'dexie-observable';
import type { AssetFuel } from 'fuels';
import { IS_LOGGED_KEY } from '~/config';
import { createParallelDb } from '~/systems/Core/utils/databaseNoDexie';
import { Storage } from '~/systems/Core/utils/storage';
import type { TransactionCursor } from '~/systems/Transaction';
import { chromeStorage } from '../services/chromeStorage';
import { applyDbVersioning } from './databaseVersioning';
import { createParallelDb } from '~/systems/Core/utils/databaseNoDexie';
import { IS_LOGGED_KEY } from '~/config';
import { Storage } from '~/systems/Core/utils/storage';
import { saveToOPFS } from './opfs';

type FailureEvents = Extract<keyof DbEvents, 'close' | 'blocked'>;
Expand Down
16 changes: 16 additions & 0 deletions packages/app/src/systems/Ecosystem/services/ecosystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { EcosystemProject } from '@fuel-wallet/types';
import { ECOSYSTEM_PROJECTS_URL } from '~/config';

// biome-ignore lint/complexity/noStaticOnlyClass: <explanation>
export class EcosystemService {
static async fetchProjects() {
const res = await fetch(ECOSYSTEM_PROJECTS_URL);

if (res.ok) {
const data: EcosystemProject[] = await res.json();
return data;
}

return [];
}
}
9 changes: 9 additions & 0 deletions packages/app/src/systems/Ecosystem/utils/getProjectImage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IGNITION_NETWORK } from '~/networks';
import { urlJoin } from '~/systems/Core';

export const getProjectImage = (image: string) => {
return urlJoin(
IGNITION_NETWORK.explorerUrl,
`/api/ecosystem/asset/${image}/image`
);
};
2 changes: 2 additions & 0 deletions packages/app/src/systems/Store/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { overlayEvents } from '../Overlay/events';
import { unlockMachine } from '../Unlock';
import { unlockEvents } from '../Unlock/events';

import { contractsMachine } from '../Contract/machines/contractsMachine';
import type { StoreMachines } from './types';
import { Services } from './types';

Expand All @@ -33,6 +34,7 @@ export const store = store$
.addMachine(Services.accounts, () => accountsMachine)
.addMachine(Services.networks, () => networksMachine)
.addMachine(Services.assets, () => assetsMachine)
.addMachine(Services.contracts, () => contractsMachine)
.addMachine(Services.unlock, () => unlockMachine)
.addMachine(Services.msgRequest, () => messageRequestMachine)
.addMachine(Services.connectRequest, () => connectRequestMachine)
Expand Down
3 changes: 3 additions & 0 deletions packages/app/src/systems/Store/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { StoreClass } from '@fuels/react-xstore';

import type { AccountsMachine } from '../Account';
import type { AssetsMachine } from '../Asset';
import type { ContractsMachine } from '../Contract/machines/contractsMachine';
import type {
AddAssetMachine,
ConnectRequestMachine,
Expand All @@ -19,6 +20,7 @@ export enum Services {
accounts = 'accounts',
networks = 'networks',
assets = 'assets',
contracts = 'contracts',
overlay = 'overlay',
unlock = 'unlock',
txRequest = 'txRequest',
Expand All @@ -33,6 +35,7 @@ export type StoreMachines = {
accounts: AccountsMachine;
networks: NetworksMachine;
assets: AssetsMachine;
contracts: ContractsMachine;
overlay: OverlayMachine;
unlock: UnlockMachine;
txRequest: TransactionRequestMachine;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { cssObj } from '@fuel-ui/css';
import { Avatar, Box, Card, Heading, Icon, Text } from '@fuel-ui/react';
import { Avatar, Box, Card, Heading, Icon, Image, Text } from '@fuel-ui/react';
import type { OperationTransactionAddress } from 'fuels';
import { Address, AddressType, ChainName, isB256, isBech32 } from 'fuels';
import type { FC } from 'react';
import { type FC, useMemo } from 'react';
import { EthAddress, FuelAddress, useAccounts } from '~/systems/Account';

import { useContractMetadata } from '~/systems/Contract/hooks/useContractMetadata';
import { TxRecipientCardLoader } from './TxRecipientCardLoader';
import { TxRecipientContractLogo } from './TxRecipientContractLogo';

export type TxRecipientCardProps = {
recipient?: OperationTransactionAddress;
Expand All @@ -29,8 +31,16 @@ export const TxRecipientCard: TxRecipientCardComponent = ({
const isContract = recipient?.type === AddressType.contract;
const isEthChain = recipient?.chain === ChainName.ethereum;
const isNetwork = address === 'Network';
const name =
accounts?.find((a) => a.address === fuelAddress)?.name || 'unknown';

const contract = useContractMetadata(address);

const name = useMemo<string>(() => {
if (isContract) {
return contract?.name || 'unknown';
}

return accounts?.find((a) => a.address === fuelAddress)?.name || 'unknown';
}, [isContract, contract, accounts, fuelAddress]);

return (
<Card
Expand Down Expand Up @@ -72,7 +82,11 @@ export const TxRecipientCard: TxRecipientCardComponent = ({
)}
{isContract && !isNetwork && (
<Box css={styles.iconWrapper}>
<Icon icon={Icon.is('Code')} size={20} />
<TxRecipientContractLogo
name={contract?.name}
image={contract?.image}
size={56}
/>
</Box>
)}
<Box.Flex css={styles.info}>
Expand Down Expand Up @@ -133,6 +147,7 @@ const styles = {
alignItems: 'center',
background: '$intentsBase3',
borderRadius: '$full',
overflow: 'hidden',
}),
info: cssObj({
flexDirection: 'column',
Expand Down
Loading
Loading