Skip to content

Commit

Permalink
Merge branch 'main' into eclipse
Browse files Browse the repository at this point in the history
  • Loading branch information
jmrossy committed Aug 21, 2023
2 parents 30f7a02 + 0faea83 commit a5f960b
Show file tree
Hide file tree
Showing 34 changed files with 355 additions and 273 deletions.
8 changes: 4 additions & 4 deletions src/components/buttons/ConnectAwareSubmitButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import { useTimeout } from '../../utils/timeout';
import { SolidButton } from './SolidButton';

interface Props {
caip2Id: Caip2Id;
chainCaip2Id: ChainCaip2Id;
text: string;
classes?: string;
}

export function ConnectAwareSubmitButton<FormValues = any>({ caip2Id, text, classes }: Props) {
const protocol = tryGetProtocolType(caip2Id) || ProtocolType.Ethereum;
export function ConnectAwareSubmitButton<FormValues = any>({ chainCaip2Id, text, classes }: Props) {
const protocol = tryGetProtocolType(chainCaip2Id) || ProtocolType.Ethereum;
const connectFns = useConnectFns();
const connectFn = connectFns[protocol];

const account = useAccountForChain(caip2Id);
const account = useAccountForChain(chainCaip2Id);
const isAccountReady = account?.isReady;

const { errors, setErrors, touched, setTouched } = useFormikContext<FormValues>();
Expand Down
12 changes: 6 additions & 6 deletions src/components/icons/ChainLogo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import { logger } from '../../utils/logger';
import { isNumeric } from '../../utils/string';

type Props = Omit<ComponentProps<typeof ChainLogoInner>, 'chainId' | 'chainName'> & {
caip2Id?: Caip2Id;
chainCaip2Id?: ChainCaip2Id;
};

export function ChainLogo(props: Props) {
const { caip2Id, ...rest } = props;
const { chainCaip2Id, ...rest } = props;
const { chainId, chainName, icon } = useMemo(() => {
if (!caip2Id) return {};
if (!chainCaip2Id) return {};
try {
const { reference } = parseCaip2Id(caip2Id);
const { reference } = parseCaip2Id(chainCaip2Id);
const chainId = isNumeric(reference) ? parseInt(reference, 10) : undefined;
const chainName = getChainDisplayName(caip2Id);
const chainName = getChainDisplayName(chainCaip2Id);
const logoUri = getMultiProvider().tryGetChainMetadata(reference)?.logoURI;
const icon = logoUri
? (props: { width: number; height: number; title?: string }) => (
Expand All @@ -36,7 +36,7 @@ export function ChainLogo(props: Props) {
logger.error('Failed to parse caip2 id', error);
return {};
}
}, [caip2Id]);
}, [chainCaip2Id]);

return <ChainLogoInner {...rest} chainId={chainId} chainName={chainName} icon={icon} />;
}
4 changes: 3 additions & 1 deletion src/components/icons/TokenIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ function _TokenIcon({ token, size = 32 }: Props) {
const fontSize = Math.floor(size / 2);

const bgColorSeed =
token && !imageSrc ? (Buffer.from(getTokenAddress(token.caip19Id)).at(0) || 0) % 5 : undefined;
token && !imageSrc
? (Buffer.from(getTokenAddress(token.tokenCaip19Id)).at(0) || 0) % 5
: undefined;

return (
<Circle size={size} bgColorSeed={bgColorSeed} title={title}>
Expand Down
12 changes: 6 additions & 6 deletions src/components/toast/TxSuccessToast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,25 @@ import { toast } from 'react-toastify';
import { parseCaip2Id } from '../../features/caip/chains';
import { getMultiProvider } from '../../features/multiProvider';

export function toastTxSuccess(msg: string, txHash: string, caip2Id: Caip2Id) {
toast.success(<TxSuccessToast msg={msg} txHash={txHash} caip2Id={caip2Id} />, {
export function toastTxSuccess(msg: string, txHash: string, chainCaip2Id: ChainCaip2Id) {
toast.success(<TxSuccessToast msg={msg} txHash={txHash} chainCaip2Id={chainCaip2Id} />, {
autoClose: 12000,
});
}

export function TxSuccessToast({
msg,
txHash,
caip2Id,
chainCaip2Id,
}: {
msg: string;
txHash: string;
caip2Id: Caip2Id;
chainCaip2Id: ChainCaip2Id;
}) {
const url = useMemo(() => {
const { reference } = parseCaip2Id(caip2Id);
const { reference } = parseCaip2Id(chainCaip2Id);
return getMultiProvider().tryGetExplorerTxUrl(reference, { hash: txHash });
}, [caip2Id, txHash]);
}, [chainCaip2Id, txHash]);

return (
<div>
Expand Down
28 changes: 28 additions & 0 deletions src/consts/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,34 @@ export const chains: ChainMap<ChainMetadataWithArtifacts> = {
// Including configs for some Solana chains by default
solana: {
...solana,
rpcUrls: [
{
http: process.env.NEXT_PUBLIC_SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com',
},
],
// TODO move up to SDK
blockExplorers: [
{
name: 'Solana Explorer',
url: 'https://explorer.solana.com',
apiUrl: 'https://explorer.solana.com',
family: ExplorerFamily.Other,
},
],
mailbox: 'TODO',
interchainGasPaymaster: '',
validatorAnnounce: '',
},
solanatestnet: {
...solanatestnet,
blockExplorers: [
{
name: 'Solana Explorer',
url: 'https://explorer.solana.com',
apiUrl: 'https://explorer.solana.com',
family: ExplorerFamily.Other,
},
],
mailbox: 'TODO',
interchainGasPaymaster: '',
validatorAnnounce: '',
Expand Down Expand Up @@ -91,3 +113,9 @@ export const chains: ChainMap<ChainMetadataWithArtifacts> = {
validatorAnnounce: '0xEEea93d0d0287c71e47B3f62AFB0a92b9E8429a1',
},
};

export const solanaChainToClusterName = {
solana: 'mainnet-beta',
solanatestnet: 'testnet',
solanadevnet: 'devnet',
};
5 changes: 4 additions & 1 deletion src/consts/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ const isDevMode = process?.env?.NODE_ENV === 'development';
const version = process?.env?.NEXT_PUBLIC_VERSION ?? null;
const explorerApiKeys = JSON.parse(process?.env?.EXPLORER_API_KEYS || '{}');
const walletConnectProjectId = process?.env?.NEXT_PUBLIC_WALLET_CONNECT_ID || '';
const withdrawalWhitelist = process?.env?.NEXT_PUBLIC_BLOCK_WITHDRAWAL_WHITELIST || '';

interface Config {
debug: boolean; // Enables some debug features in the app
version: string | null; // Matches version number in package.json
explorerApiKeys: Record<string, string>; // Optional map of API keys for block explorer
showTipBox: boolean; // Show/Hide the blue tip box above the main form
showDisabledTokens: boolean; // Show/Hide invalid token options in the selection modal
walletConnectProjectId: string;
walletConnectProjectId: string; // Project ID provided by walletconnect
withdrawalWhitelist: string; // comma-separated list of CAIP2 domains to which transfers are supported
}

export const config: Config = Object.freeze({
Expand All @@ -19,4 +21,5 @@ export const config: Config = Object.freeze({
showTipBox: false,
showDisabledTokens: false,
walletConnectProjectId,
withdrawalWhitelist,
});
16 changes: 8 additions & 8 deletions src/features/caip/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { logger } from '../../utils/logger';

// Based mostly on https://chainagnostic.org/CAIPs/caip-2
// But uses different naming for the protocol
export function getCaip2Id(protocol: ProtocolType, reference: string | number): Caip2Id {
export function getCaip2Id(protocol: ProtocolType, reference: string | number): ChainCaip2Id {
if (!Object.values(ProtocolType).includes(protocol)) {
throw new Error(`Invalid chain environment: ${protocol}`);
}
Expand All @@ -14,7 +14,7 @@ export function getCaip2Id(protocol: ProtocolType, reference: string | number):
return `${protocol}:${reference}`;
}

export function parseCaip2Id(id: Caip2Id) {
export function parseCaip2Id(id: ChainCaip2Id) {
const [_protocol, reference] = id.split(':');
const protocol = _protocol as ProtocolType;
if (!Object.values(ProtocolType).includes(protocol)) {
Expand All @@ -26,7 +26,7 @@ export function parseCaip2Id(id: Caip2Id) {
return { protocol, reference };
}

export function tryParseCaip2Id(id: Caip2Id) {
export function tryParseCaip2Id(id: ChainCaip2Id) {
if (!id) return undefined;
try {
return parseCaip2Id(id);
Expand All @@ -36,25 +36,25 @@ export function tryParseCaip2Id(id: Caip2Id) {
}
}

export function getProtocolType(id: Caip2Id) {
export function getProtocolType(id: ChainCaip2Id) {
const { protocol } = parseCaip2Id(id);
return protocol;
}

export function tryGetProtocolType(id: Caip2Id) {
export function tryGetProtocolType(id: ChainCaip2Id) {
return tryParseCaip2Id(id)?.protocol;
}

export function getChainReference(id: Caip2Id) {
export function getChainReference(id: ChainCaip2Id) {
const { reference } = parseCaip2Id(id);
return reference;
}

export function tryGetChainReference(id: Caip2Id) {
export function tryGetChainReference(id: ChainCaip2Id) {
return tryParseCaip2Id(id)?.reference;
}

export function getEthereumChainId(id: Caip2Id): number {
export function getEthereumChainId(id: ChainCaip2Id): number {
const { protocol, reference } = parseCaip2Id(id);
if (protocol !== ProtocolType.Ethereum) {
throw new Error(`Protocol type must be ethereum: ${id}`);
Expand Down
32 changes: 16 additions & 16 deletions src/features/caip/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,36 @@ export enum AssetNamespace {
// Based mostly on https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-19.md
// But uses simpler asset namespace naming for native tokens
export function getCaip19Id(
caip2Id: Caip2Id,
chainCaip2Id: ChainCaip2Id,
namespace: AssetNamespace,
address: Address,
tokenId?: string | number,
): Caip19Id {
): TokenCaip19Id {
if (!Object.values(AssetNamespace).includes(namespace)) {
throw new Error(`Invalid asset namespace: ${namespace}`);
}
if (!isValidAddress(address)) {
throw new Error(`Invalid address: ${address}`);
}
return `${caip2Id}/${namespace}:${address}${tokenId ? `/${tokenId}` : ''}`;
return `${chainCaip2Id}/${namespace}:${address}${tokenId ? `/${tokenId}` : ''}`;
}

export function parseCaip19Id(id: Caip19Id) {
export function parseCaip19Id(id: TokenCaip19Id) {
const segments = id.split('/');
if (segments.length >= 2) {
const caip2Id = segments[0] as Caip2Id;
const chainCaip2Id = segments[0] as ChainCaip2Id;
const [namespace, address] = segments[1].split(':') as [AssetNamespace, Address];
if (!caip2Id || !namespace || !address) {
if (!chainCaip2Id || !namespace || !address) {
throw new Error(`Invalid caip19 id: ${id}`);
}
const tokenId = segments.length > 2 ? segments[2] : undefined;
return { caip2Id, namespace, address, tokenId };
return { chainCaip2Id, namespace, address, tokenId };
} else {
throw new Error(`Invalid caip19 id: ${id}`);
}
}

export function tryParseCaip19Id(id: Caip19Id) {
export function tryParseCaip19Id(id: TokenCaip19Id) {
if (!id) return undefined;
try {
return parseCaip19Id(id);
Expand All @@ -56,23 +56,23 @@ export function tryParseCaip19Id(id: Caip19Id) {
}
}

export function getCaip2FromToken(id: Caip19Id): Caip2Id {
return parseCaip19Id(id).caip2Id;
export function getChainIdFromToken(id: TokenCaip19Id): ChainCaip2Id {
return parseCaip19Id(id).chainCaip2Id;
}

export function tryGetCaip2FromToken(id: Caip19Id): Caip2Id | undefined {
return tryParseCaip19Id(id)?.caip2Id;
export function tryGetChainIdFromToken(id: TokenCaip19Id): ChainCaip2Id | undefined {
return tryParseCaip19Id(id)?.chainCaip2Id;
}

export function getAssetNamespace(id: Caip19Id): AssetNamespace {
export function getAssetNamespace(id: TokenCaip19Id): AssetNamespace {
return parseCaip19Id(id).namespace as AssetNamespace;
}

export function getTokenAddress(id: Caip19Id): Address {
export function getTokenAddress(id: TokenCaip19Id): Address {
return parseCaip19Id(id).address;
}

export function isNativeToken(id: Caip19Id): boolean {
export function isNativeToken(id: TokenCaip19Id): boolean {
const { namespace } = parseCaip19Id(id);
return namespace === AssetNamespace.native;
}
Expand All @@ -87,7 +87,7 @@ export function getNativeTokenAddress(protocol: ProtocolType): Address {
}
}

export function isNonFungibleToken(id: Caip19Id): boolean {
export function isNonFungibleToken(id: TokenCaip19Id): boolean {
const { namespace } = parseCaip19Id(id);
return namespace === AssetNamespace.erc721;
}
Expand Down
16 changes: 8 additions & 8 deletions src/features/chains/ChainSelectField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ import { getChainDisplayName } from './utils';
type Props = {
name: string;
label: string;
caip2Ids: Caip2Id[];
onChange?: (id: Caip2Id) => void;
chainCaip2Ids: ChainCaip2Id[];
onChange?: (id: ChainCaip2Id) => void;
disabled?: boolean;
};

export function ChainSelectField({ name, label, caip2Ids, onChange, disabled }: Props) {
const [field, , helpers] = useField<Caip2Id>(name);
export function ChainSelectField({ name, label, chainCaip2Ids, onChange, disabled }: Props) {
const [field, , helpers] = useField<ChainCaip2Id>(name);
const { setFieldValue } = useFormikContext<TransferFormValues>();

const handleChange = (newChainId: Caip2Id) => {
const handleChange = (newChainId: ChainCaip2Id) => {
helpers.setValue(newChainId);
// Reset other fields on chain change
setFieldValue('tokenCaip19Id', '');
Expand All @@ -40,7 +40,7 @@ export function ChainSelectField({ name, label, caip2Ids, onChange, disabled }:
<div className="flex flex-col items-center">
<div className="flex flex-col items-center justify-center rounded-full bg-gray-100 h-[5.5rem] w-[5.5rem] p-1.5">
<div className="flex items-end h-11">
<ChainLogo caip2Id={field.value} size={34} />
<ChainLogo chainCaip2Id={field.value} size={34} />
</div>
<label htmlFor={name} className="mt-2 mb-1 text-sm text-gray-500 uppercase">
{label}
Expand All @@ -53,15 +53,15 @@ export function ChainSelectField({ name, label, caip2Ids, onChange, disabled }:
onClick={onClick}
>
<div className="flex items-center">
<ChainLogo caip2Id={field.value} size={14} />
<ChainLogo chainCaip2Id={field.value} size={14} />
<span className="ml-2">{getChainDisplayName(field.value, true)}</span>
</div>
<Image src={ChevronIcon} width={12} height={8} alt="" />
</button>
<ChainSelectListModal
isOpen={isModalOpen}
close={() => setIsModalOpen(false)}
caip2Ids={caip2Ids}
chainCaip2Ids={chainCaip2Ids}
onSelect={handleChange}
/>
</div>
Expand Down
14 changes: 7 additions & 7 deletions src/features/chains/ChainSelectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,31 @@ import { getChainDisplayName } from './utils';
export function ChainSelectListModal({
isOpen,
close,
caip2Ids,
chainCaip2Ids,
onSelect,
}: {
isOpen: boolean;
close: () => void;
caip2Ids: Caip2Id[];
onSelect: (caip2Id: Caip2Id) => void;
chainCaip2Ids: ChainCaip2Id[];
onSelect: (chainCaip2Id: ChainCaip2Id) => void;
}) {
const onSelectChain = (caip2Id: Caip2Id) => {
const onSelectChain = (chainCaip2Id: ChainCaip2Id) => {
return () => {
onSelect(caip2Id);
onSelect(chainCaip2Id);
close();
};
};

return (
<Modal isOpen={isOpen} title="Select Chain" close={close}>
<div className="mt-2 flex flex-col space-y-1">
{caip2Ids.map((c) => (
{chainCaip2Ids.map((c) => (
<button
key={c}
className="py-1.5 px-2 text-sm flex items-center rounded hover:bg-gray-100 active:bg-gray-200 transition-all duration-200"
onClick={onSelectChain(c)}
>
<ChainLogo caip2Id={c} size={16} background={false} />
<ChainLogo chainCaip2Id={c} size={16} background={false} />
<span className="ml-2">{getChainDisplayName(c, true)}</span>
</button>
))}
Expand Down
Loading

0 comments on commit a5f960b

Please sign in to comment.