Skip to content

Commit

Permalink
Add support for JSON and YAML chain and token configs (#88)
Browse files Browse the repository at this point in the history
- Add support for JSON and YAML chain and token configs
- Update some stale docs
- Cleanup default chain and token const files
  • Loading branch information
jmrossy authored Dec 5, 2023
1 parent c89389a commit ea94576
Show file tree
Hide file tree
Showing 16 changed files with 173 additions and 63 deletions.
4 changes: 2 additions & 2 deletions CUSTOMIZE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ Find below instructions for customizing the token list and branding assets of th

## Token Configs

This app requires a token config list to function. The token list is located at `./src/consts/tokens.ts`. The output token artifacts of a warp route deployment using the [Hyperlane-Deploy](https://docs.hyperlane.xyz/docs/deploy/deploy-hyperlane) tools can be used here.
This app requires a token config list to function. The token list is located in `./src/consts/`. Tokens can be configured using any of the token files there (`.ts`, `.json`, `.yaml`). The output token artifacts of a warp route deployment using the [Hyperlane CLI](https://www.npmjs.com/package/@hyperlane-xyz/cli) can be used here.

## Chain Configs

By default, the app will use only the chains that are included in the Hyperlane SDK and connected to the tokens you specify in the token list (see above).

To add support for additional chains, or to modify the default properties of the SDK's chains (such as RPC URL), add the required chain metadata to `./src/consts/chains.ts`. The same chain config used in the [Hyperlane-Deploy](https://docs.hyperlane.xyz/docs/deploy/deploy-hyperlane) tools will work here. You may also add an optional `logoURI` field to a chain config to show a custom logo image in the app.
To add support for additional chains, or to modify the default properties of the SDK's chains (such as RPC URLs), add the required chain metadata to any of the chains files in `./src/consts/` (`.ts`, `.json`, `.yaml`). The same chain configs used in the [Hyperlane CLI](https://www.npmjs.com/package/@hyperlane-xyz/cli) will work here. You may also add an optional `logoURI` field to a chain config to show a custom logo image in the app.

## Tip Card

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Hyperlane Warp Route UI Template

This repo contains an example web interface for a interchain tokens built with [Hyperlane Warp Route](https://docs.hyperlane.xyz/docs/apis-and-sdks/warp-api). Warp is a framework to permisionlessly bridge tokens to any chain.
This repo contains an example web interface for interchain tokens built with [Hyperlane Warp Route](https://docs.hyperlane.xyz/docs/reference/applications/warp-routes). Warp is a framework to permisionlessly bridge tokens to any chain.

## Architecture

This app is built with Next+React, Wagmi, RainbowKit, and the Hyperlane SDK.

- Constants that you may want to change are in `./src/consts/`, see the following Customization section for details.
- The index page is located at `./src/pages/index.tsx`
- The primary features are implemented in `./src/features/`
- Constants that you may want to change are in `./src/consts/`, see the following Customization section for details.

## Customization

Expand Down Expand Up @@ -63,4 +63,4 @@ The easiest hosting solution for this Next.JS app is to create a project on Verc

## Learn more

For more information, see the [Hyperlane documentation](https://docs.hyperlane.xyz/docs/apis-and-sdks/warp-api).
For more information, see the [Hyperlane documentation](https://docs.hyperlane.xyz/docs/reference/applications/warp-routes).
7 changes: 7 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ const createJestConfig = nextJest({
const customJestConfig = {
// Add more setup options before each test is run
// setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
transform: {
// ... other transforms ...
"\\.yaml$": "jest-transform-yaml",
},
moduleFileExtensions: [
"ts", "txs", "jsx", "js", "json", "yaml"
],
}

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
Expand Down
8 changes: 8 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ const securityHeaders = [
]

const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.ya?ml$/,
use: 'yaml-loader',
});
return config;
},

async headers() {
return [
{
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,14 @@
"eslint-config-next": "^13.4.3",
"eslint-config-prettier": "^8.8.0",
"jest": "^29.6.3",
"jest-transform-yaml": "^1.1.2",
"postcss": "^8.4.23",
"prettier": "^2.8.8",
"tailwindcss": "^3.3.2",
"ts-node": "^10.9.1",
"typescript": "^5.1.6"
"typescript": "^5.1.6",
"yaml": "^2.3.4",
"yaml-loader": "^0.8.0"
},
"homepage": "https://www.hyperlane.xyz",
"license": "Apache-2.0",
Expand Down
1 change: 1 addition & 0 deletions src/consts/chains.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
46 changes: 4 additions & 42 deletions src/consts/chains.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ChainMap, ChainMetadata, chainMetadata } from '@hyperlane-xyz/sdk';
import { ProtocolType } from '@hyperlane-xyz/utils';
import { ChainMap, ChainMetadata } from '@hyperlane-xyz/sdk';

// A map of chain names to ChainMetadata
// Chains can be defined here, in chains.json, or in chains.yaml
// Chains already in the SDK need not be included here unless you want to override some fields
// Schema here: https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/main/typescript/sdk/src/metadata/chainMetadataTypes.ts
export const chains: ChainMap<ChainMetadata & { mailbox?: Address }> = {
// ----------- Add your chains here -----------------
// Chains already in the SDK need not be included here. Example custom chain:
// mycustomchain: {
// protocol: ProtocolType.Ethereum,
// chainId: 1234,
Expand All @@ -28,42 +28,4 @@ export const chains: ChainMap<ChainMetadata & { mailbox?: Address }> = {
// },
// logoURI: '/logo.svg',
// },

// Including configs for some Solana chains by default
solana: {
...chainMetadata.solana,
rpcUrls: [
{
http: process.env.NEXT_PUBLIC_SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com',
},
],
mailbox: 'TODO',
},
solanatestnet: {
...chainMetadata.solanatestnet,
mailbox: 'TODO',
},
solanadevnet: {
...chainMetadata.solanadevnet,
mailbox: '4v25Dz9RccqUrTzmfHzJMsjd1iVoNrWzeJ4o6GYuJrVn',
},
cosmoshub: {
protocol: ProtocolType.Cosmos,
name: 'cosmoshub',
chainId: 'cosmoshub-4',
displayName: 'Cosmos Hub',
domainId: 1234, // TODO
bech32Prefix: 'cosmos',
slip44: 118,
rpcUrls: [
{ http: 'https://rpc-cosmoshub.blockapsis.com' },
{ http: 'https://lcd-cosmoshub.blockapsis.com' },
],
nativeToken: {
name: 'Atom',
symbol: 'ATOM',
decimals: 6,
},
logoURI: '/logos/cosmos.svg',
},
};
20 changes: 20 additions & 0 deletions src/consts/chains.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# A map of chain names to ChainMetadata
# Chains can be defined here, in chains.json, or in chains.ts
# Chains already in the SDK need not be included here unless you want to override some fields
# Schema here: https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/main/typescript/sdk/src/metadata/chainMetadataTypes.ts
---
# Example using local anvil chain:
# anvil1:
# chainId: 31337
# domainId: 31337
# name: anvil1
# protocol: ethereum
# rpcUrls:
# - http: http://127.0.0.1:8545
# anvil2:
# chainId: 31338
# domainId: 31338
# name: anvil2
# protocol: ethereum
# rpcUrls:
# - http: http://127.0.0.1:8555
1 change: 1 addition & 0 deletions src/consts/tokens.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
14 changes: 3 additions & 11 deletions src/consts/tokens.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { WarpTokenConfig } from '../features/tokens/types';

// A list of Warp UI token configs
// Tokens can be defined here, in tokens.json, or in tokens.yaml
// The input here is typically the output of the Hyperlane CLI warp deploy command
export const tokenList: WarpTokenConfig = [
// Example collateral token for an EVM chain
{
Expand All @@ -13,17 +16,6 @@ export const tokenList: WarpTokenConfig = [
logoURI: '/logos/weth.png', // See public/logos/
},

// Example native token for an EVM chain
// {
// type: 'native',
// chainId: 11155111,
// name: 'Ether',
// symbol: 'ETH',
// decimals: 18,
// hypNativeAddress: '0xEa44A29da87B5464774978e6A4F4072A4c048949',
// logoURI: '/logos/weth.png',
// },

// Example NFT (ERC721) token for an EVM chain
{
chainId: 5,
Expand Down
14 changes: 14 additions & 0 deletions src/consts/tokens.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# A list of Warp UI token configs
# Tokens can be defined here, in tokens.json, or in tokens.ts
# The input here is typically the output of the Hyperlane CLI warp deploy command
---
# Replace this [] with your token list
[]
# Example using a native token:
# - type: native
# chainId: 11155111
# name: 'Ether'
# symbol: 'ETH'
# decimals: 18
# hypNativeAddress: '0xEa44A29da87B5464774978e6A4F4072A4c048949'
# logoURI: '/logos/weth.png'
22 changes: 22 additions & 0 deletions src/features/chains/cosmosDefault.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ChainMetadata } from '@hyperlane-xyz/sdk';
import { ProtocolType } from '@hyperlane-xyz/utils';

export const cosmosDefaultChain: ChainMetadata = {
protocol: ProtocolType.Cosmos,
name: 'cosmoshub',
chainId: 'cosmoshub-4',
displayName: 'Cosmos Hub',
domainId: 1234, // TODO
bech32Prefix: 'cosmos',
slip44: 118,
rpcUrls: [
{ http: 'https://rpc-cosmoshub.blockapsis.com' },
{ http: 'https://lcd-cosmoshub.blockapsis.com' },
],
nativeToken: {
name: 'Atom',
symbol: 'ATOM',
decimals: 6,
},
logoURI: '/logos/cosmos.svg',
};
14 changes: 12 additions & 2 deletions src/features/chains/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ import {
} from '@hyperlane-xyz/sdk';
import { ProtocolType } from '@hyperlane-xyz/utils';

import { chains } from '../../consts/chains';
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(
Expand All @@ -23,7 +27,13 @@ export const ChainConfigSchema = z.record(

export function getChainConfigs() {
if (!chainConfigs) {
const result = ChainConfigSchema.safeParse(chains);
// 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()}`);
Expand Down
5 changes: 4 additions & 1 deletion src/features/tokens/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { EvmTokenAdapter, ITokenAdapter, TokenType } from '@hyperlane-xyz/sdk';
import { ProtocolType } from '@hyperlane-xyz/utils';

import { tokenList } from '../../consts/tokens';
import { tokenList as TokensTS } from '../../consts/tokens';
import TokensJson from '../../consts/tokens.json';
import TokensYaml from '../../consts/tokens.yaml';
import { logger } from '../../utils/logger';
import { getCaip2Id } from '../caip/chains';
import { getCaip19Id, getNativeTokenAddress, resolveAssetNamespace } from '../caip/tokens';
Expand All @@ -28,6 +30,7 @@ export function getToken(tokenCaip19Id: TokenCaip19Id) {

export async function parseTokens() {
if (!tokens) {
const tokenList = [...TokensJson, ...TokensYaml, ...TokensTS];
tokens = await parseTokenConfigs(tokenList);
}
return tokens;
Expand Down
5 changes: 5 additions & 0 deletions src/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ declare type Address = string;
declare type DomainId = number;
declare type ChainCaip2Id = `${string}:${string}`; // e.g. ethereum:1 or sealevel:1399811149
declare type TokenCaip19Id = `${string}:${string}/${string}:${string}`; // e.g. ethereum:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f

declare module '*.yaml' {
const data: any;
export default data;
}
Loading

1 comment on commit ea94576

@vercel
Copy link

@vercel vercel bot commented on ea94576 Dec 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.