Skip to content

Commit

Permalink
Merge pull request #122 from hyperlane-xyz/main-to-nexus
Browse files Browse the repository at this point in the history
Main to nexus
  • Loading branch information
jmrossy authored Jan 23, 2024
2 parents 2f9e14a + 242963c commit f8e93ef
Show file tree
Hide file tree
Showing 34 changed files with 383 additions and 322 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ coverage.json
/out/

# production
/src/types/
/src/deploy/output
/src/context/*.json
/artifacts
/build
/dist
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@
},
"scripts": {
"clean": "rm -rf dist cache .next",
"dev": "next dev",
"build": "next build",
"dev": "yarn build:configs && next dev",
"build": "yarn build:configs && next build",
"build:configs": "./src/scripts/buildConfigs/build.sh",
"typecheck": "tsc",
"lint": "next lint",
"start": "next start",
"test": "jest",
"test": "yarn build:configs && jest",
"prettier": "prettier --write ./src"
},
"types": "dist/src/index.d.ts",
Expand Down
6 changes: 3 additions & 3 deletions src/consts/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import { ProtocolType } from '@hyperlane-xyz/utils';
export const chains: ChainMap<ChainMetadata & { mailbox?: Address }> = {
// mycustomchain: {
// protocol: ProtocolType.Ethereum,
// chainId: 1234,
// domainId: 1234,
// chainId: 123123,
// domainId: 123123,
// name: 'mycustomchain',
// displayName: 'My Chain',
// nativeToken: { name: 'Ether', symbol: 'ETH', decimals: 18 },
// publicRpcUrls: [{ http: 'https://mycustomchain-rpc.com' }],
// rpcUrls: [{ http: 'https://mycustomchain-rpc.com' }],
// blockExplorers: [
// {
// name: 'MyCustomScan',
Expand Down
2 changes: 1 addition & 1 deletion src/consts/ibcRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IbcRoute, IbcToWarpRoute, RouteType } from '../features/tokens/routes/types';
import { IbcRoute, IbcToWarpRoute, RouteType } from '../features/routes/types';

// Configs for manually-defined IBC-only routes
export const ibcRoutes: Array<IbcRoute | IbcToWarpRoute> = [
Expand Down
4 changes: 4 additions & 0 deletions src/context/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### About

This folder contains pre-validated and processed configs for the the chains, tokens, and routes.
The contents are auto-generated by the `yarn build:configs` command. Changes will be overridden on new builds.
33 changes: 33 additions & 0 deletions src/context/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { ChainMap, ChainMetadata, MultiProtocolProvider } from '@hyperlane-xyz/sdk';

import type { RoutesMap } from '../features/routes/types';
import type { TokenMetadata } from '../features/tokens/types';

import Chains from './_chains.json';
import Routes from './_routes.json';
import Tokens from './_tokens.json';

export interface WarpContext {
chains: ChainMap<ChainMetadata & { mailbox?: Address }>;
tokens: TokenMetadata[];
routes: RoutesMap;
multiProvider: MultiProtocolProvider<{ mailbox?: Address }>;
}

let warpContext: WarpContext;

export function getWarpContext() {
if (!warpContext) {
warpContext = {
chains: Chains as any,
tokens: Tokens as any,
routes: Routes as any,
multiProvider: new MultiProtocolProvider<{ mailbox?: Address }>(Chains as any),
};
}
return warpContext;
}

export function setWarpContext(context: WarpContext) {
warpContext = context;
}
48 changes: 5 additions & 43 deletions src/features/chains/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,21 @@
import type { AssetList, Chain as CosmosChain } from '@chain-registry/types';
import type { Chain as WagmiChain } from '@wagmi/core';
import { z } from 'zod';

import {
ChainMap,
ChainMetadata,
ChainMetadataSchema,
ChainName,
chainMetadata,
chainMetadataToWagmiChain,
} from '@hyperlane-xyz/sdk';
import { ChainName, chainMetadataToWagmiChain } from '@hyperlane-xyz/sdk';
import { ProtocolType } from '@hyperlane-xyz/utils';

import { chains as ChainsTS } from '../../consts/chains';
import ChainsJson from '../../consts/chains.json';
import ChainsYaml from '../../consts/chains.yaml';
import { logger } from '../../utils/logger';

import { cosmosDefaultChain } from './cosmosDefault';

let chainConfigs: ChainMap<ChainMetadata & { mailbox?: Address }>;

export const ChainConfigSchema = z.record(
ChainMetadataSchema.and(z.object({ mailbox: z.string().optional() })),
);

export function getChainConfigs() {
if (!chainConfigs) {
// Chains must include a cosmos chain or CosmosKit throws errors
const result = ChainConfigSchema.safeParse({
cosmoshub: cosmosDefaultChain,
...ChainsJson,
...ChainsYaml,
...ChainsTS,
});
if (!result.success) {
logger.error('Invalid chain config', result.error);
throw new Error(`Invalid chain config: ${result.error.toString()}`);
}
const customChainConfigs = result.data as ChainMap<ChainMetadata & { mailbox?: Address }>;
chainConfigs = { ...chainMetadata, ...customChainConfigs };
}
return chainConfigs;
}
import { getWarpContext } from '../../context/context';

// Metadata formatted for use in Wagmi config
export function getWagmiChainConfig(): WagmiChain[] {
const evmChains = Object.values(getChainConfigs()).filter(
const evmChains = Object.values(getWarpContext().chains).filter(
(c) => !c.protocol || c.protocol === ProtocolType.Ethereum,
);
return evmChains.map(chainMetadataToWagmiChain);
}

export function getCosmosKitConfig(): { chains: CosmosChain[]; assets: AssetList[] } {
const cosmosChains = Object.values(getChainConfigs()).filter(
const cosmosChains = Object.values(getWarpContext().chains).filter(
(c) => c.protocol === ProtocolType.Cosmos,
);
const chains = cosmosChains.map((c) => ({
Expand Down Expand Up @@ -143,7 +105,7 @@ export function getCosmosKitConfig(): { chains: CosmosChain[]; assets: AssetList
}

export function getCosmosChainNames(): ChainName[] {
return Object.values(getChainConfigs())
return Object.values(getWarpContext().chains)
.filter((c) => c.protocol === ProtocolType.Cosmos)
.map((c) => c.name);
}
11 changes: 3 additions & 8 deletions src/features/multiProvider.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { MultiProtocolProvider } from '@hyperlane-xyz/sdk';
import { ProtocolType } from '@hyperlane-xyz/utils';

import { parseCaip2Id } from './caip/chains';
import { getChainConfigs } from './chains/metadata';
import { getWarpContext } from '../context/context';

let multiProvider: MultiProtocolProvider<{ mailbox?: Address }>;
import { parseCaip2Id } from './caip/chains';

export function getMultiProvider() {
if (!multiProvider) {
multiProvider = new MultiProtocolProvider<{ mailbox?: Address }>(getChainConfigs());
}
return multiProvider;
return getWarpContext().multiProvider;
}

export function getEvmProvider(id: ChainCaip2Id) {
Expand Down
19 changes: 19 additions & 0 deletions src/features/routes/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useMemo } from 'react';

import { getChainIdFromToken } from '../caip/tokens';
import { getTokens } from '../tokens/metadata';

import { RoutesMap } from './types';

export function useRouteChains(tokenRoutes: RoutesMap): ChainCaip2Id[] {
return useMemo(() => {
const allCaip2Ids = Object.keys(tokenRoutes) as ChainCaip2Id[];
const collateralCaip2Ids = getTokens().map((t) => getChainIdFromToken(t.tokenCaip19Id));
return allCaip2Ids.sort((c1, c2) => {
// Surface collateral chains first
if (collateralCaip2Ids.includes(c1) && !collateralCaip2Ids.includes(c2)) return -1;
else if (!collateralCaip2Ids.includes(c1) && collateralCaip2Ids.includes(c2)) return 1;
else return c1 > c2 ? 1 : -1;
});
}, [tokenRoutes]);
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { deepCopy } from '@hyperlane-xyz/utils';

import { isNativeToken } from '../../caip/tokens';
import { isNativeToken } from '../caip/tokens';

import { IbcRoute, IbcToWarpRoute, Route, RouteType, RoutesMap, WarpRoute } from './types';

Expand Down Expand Up @@ -83,13 +81,3 @@ export function isIbcOnlyRoute(route: Route): route is IbcRoute {
export function isIbcToWarpRoute(route: Route): route is IbcToWarpRoute {
return route.type === RouteType.IbcNativeToHypSynthetic;
}

export function mergeRoutes(routes: RoutesMap, newRoutes: Route[]) {
const mergedRoutes = deepCopy(routes);
for (const route of newRoutes) {
mergedRoutes[route.originCaip2Id] ||= {};
mergedRoutes[route.originCaip2Id][route.destCaip2Id] ||= [];
mergedRoutes[route.originCaip2Id][route.destCaip2Id].push(route);
}
return mergedRoutes;
}
8 changes: 4 additions & 4 deletions src/features/tokens/AdapterFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import { Address, ProtocolType, convertToProtocolAddress } from '@hyperlane-xyz/
import { parseCaip2Id } from '../caip/chains';
import { AssetNamespace, getChainIdFromToken, isNativeToken, parseCaip19Id } from '../caip/tokens';
import { getMultiProvider } from '../multiProvider';

import { getToken } from './metadata';
import { Route } from './routes/types';
import { Route } from '../routes/types';
import {
isIbcRoute,
isIbcToWarpRoute,
Expand All @@ -35,7 +33,9 @@ import {
isRouteToCollateral,
isRouteToSynthetic,
isWarpRoute,
} from './routes/utils';
} from '../routes/utils';

import { getToken } from './metadata';

export class AdapterFactory {
static NativeAdapterFromChain(
Expand Down
4 changes: 2 additions & 2 deletions src/features/tokens/SelectOrInputTokenIds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { useFormikContext } from 'formik';

import { TextField } from '../../components/input/TextField';
import { AssetNamespace, getCaip19Id } from '../caip/tokens';
import { RouteType, RoutesMap } from '../routes/types';
import { getTokenRoute, isWarpRoute } from '../routes/utils';
import { TransferFormValues } from '../transfer/types';
import { useAccountAddressForChain } from '../wallet/hooks/multiProtocol';

import { SelectTokenIdField } from './SelectTokenIdField';
import { useContractSupportsTokenByOwner, useIsSenderNftOwner } from './balances';
import { RouteType, RoutesMap } from './routes/types';
import { getTokenRoute, isWarpRoute } from './routes/utils';

export function SelectOrInputTokenIds({
disabled,
Expand Down
4 changes: 2 additions & 2 deletions src/features/tokens/TokenListModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { config } from '../../consts/config';
import InfoIcon from '../../images/icons/info-circle.svg';
import { getAssetNamespace, getTokenAddress, isNativeToken } from '../caip/tokens';
import { getChainDisplayName } from '../chains/utils';
import { RoutesMap } from '../routes/types';
import { hasTokenRoute } from '../routes/utils';

import { getTokens } from './metadata';
import { RoutesMap } from './routes/types';
import { hasTokenRoute } from './routes/utils';
import { TokenMetadata } from './types';

export function TokenListModal({
Expand Down
4 changes: 2 additions & 2 deletions src/features/tokens/TokenSelectField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { useEffect, useState } from 'react';
import { TokenIcon } from '../../components/icons/TokenIcon';
import ChevronIcon from '../../images/icons/chevron-down.svg';
import { isNonFungibleToken } from '../caip/tokens';
import { RoutesMap } from '../routes/types';
import { getTokenRoutes } from '../routes/utils';
import { TransferFormValues } from '../transfer/types';

import { TokenListModal } from './TokenListModal';
import { getToken } from './metadata';
import { RoutesMap } from './routes/types';
import { getTokenRoutes } from './routes/utils';
import { TokenMetadata } from './types';

type Props = {
Expand Down
4 changes: 2 additions & 2 deletions src/features/tokens/approval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { logger } from '../../utils/logger';
import { getProtocolType } from '../caip/chains';
import { getTokenAddress, isNativeToken, isNonFungibleToken } from '../caip/tokens';
import { getEvmProvider } from '../multiProvider';
import { Route } from '../routes/types';
import { isRouteFromCollateral, isWarpRoute } from '../routes/utils';
import { useAccountAddressForChain } from '../wallet/hooks/multiProtocol';

import { getErc20Contract, getErc721Contract } from './contracts/evmContracts';
import { Route } from './routes/types';
import { isRouteFromCollateral, isWarpRoute } from './routes/utils';

export function useIsApproveRequired(
tokenCaip19Id: TokenCaip19Id,
Expand Down
4 changes: 2 additions & 2 deletions src/features/tokens/balances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import { logger } from '../../utils/logger';
import { getProtocolType } from '../caip/chains';
import { parseCaip19Id, tryGetChainIdFromToken } from '../caip/tokens';
import { getEvmProvider } from '../multiProvider';
import { RoutesMap } from '../routes/types';
import { getTokenRoute, isIbcOnlyRoute, isIbcRoute, isRouteFromNative } from '../routes/utils';
import { useStore } from '../store';
import { TransferFormValues } from '../transfer/types';
import { useAccountAddressForChain } from '../wallet/hooks/multiProtocol';

import { AdapterFactory } from './AdapterFactory';
import { getHypErc721Contract } from './contracts/evmContracts';
import { RoutesMap } from './routes/types';
import { getTokenRoute, isIbcOnlyRoute, isIbcRoute, isRouteFromNative } from './routes/utils';

export function useOriginBalance(
{ originCaip2Id, destinationCaip2Id, tokenCaip19Id }: TransferFormValues,
Expand Down
Loading

0 comments on commit f8e93ef

Please sign in to comment.