diff --git a/.changeset/forty-pears-jump.md b/.changeset/forty-pears-jump.md new file mode 100644 index 00000000..b319300e --- /dev/null +++ b/.changeset/forty-pears-jump.md @@ -0,0 +1,5 @@ +--- +"@sei-js/registry": major +--- + +Intitial release of @sei-js/registry which contains exports from the official Sei chain registry as well as the community token list diff --git a/.gitignore b/.gitignore index 2d98b2de..ee08c58b 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ testem.log # System Files .DS_Store Thumbs.db + +packages/registry/chain-registry +packages/registry/community-assetlist diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..029e34bf --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "packages/registry/community-assetlist"] + path = packages/registry/community-assetlist + url = https://github.com/Sei-Public-Goods/sei-assetlist.git +[submodule "packages/registry/chain-registry"] + path = packages/registry/chain-registry + url = https://github.com/sei-protocol/chain-registry.git diff --git a/README.md b/README.md index 9e6f4dcf..ae598f7a 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,12 @@ You can also refer to the [typedoc documentation](https://sei-protocol.github.io SeiJS consists of smaller NPM packages within the @sei-js namespace. For more detailed documentation on each package, please refer to the table below. -| Package | Description | -|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------| -| [@sei-js/cosmjs](packages/cosmjs) | TypeScript library containing helper functions for wallet connection, transaction signing, and RPC querying using cosmjs. | -| [@sei-js/evm](packages/evm) | Typescript library containing helper functions for interacting with the EVM on Sei. | -| [@sei-js/proto](packages/proto) | TypeScript library for Sei protobufs generated using [Telescope](https://github.com/osmosis-labs/telescope) | +| Package | Description | +|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [@sei-js/cosmjs](packages/cosmjs) | TypeScript library containing helper functions for wallet connection, transaction signing, and RPC querying using cosmjs. | +| [@sei-js/evm](packages/evm) | Typescript library containing helper functions for interacting with the EVM on Sei. | +| [@sei-js/proto](packages/proto) | TypeScript library for Sei protobuf generated using [Telescope](https://github.com/osmosis-labs/telescope) | +| [@sei-js/registry](packages/proto) | TypeScript library exporting constants from the [Sei chain-registry](https://github.com/sei-protocol/chain-registry) and the [community asset list](https://github.com/Sei-Public-Goods/sei-assetlist) | ## Development To build all packages and docs, run `yarn install` then `yarn build:all` diff --git a/TYPEDOC-README.md b/TYPEDOC-README.md index faeaae6b..e4ca1b9d 100644 --- a/TYPEDOC-README.md +++ b/TYPEDOC-README.md @@ -9,11 +9,12 @@ ## Packages -| Package | Description | -|--------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [evm](/sei-js/docs/modules/evm.html) | The `/evm` package provides utilities, functions, wrappers, and configurations for seamless interaction with Sei via the Ethereum Virtual Machine (EVM). If you're building smart contracts or integrating Sei with Ethereum-based tooling, or interacting with EVM contacts like ERC20 tokens this package contains all the configs needed. | -| [cosmjs](/sei-js/docs/modules/cosmjs.html) | The `/cosmjs` package offers similar functionality to the `/evm` package but tailored for interactions with Sei via the Cosmos interfaces. It includes utilities, functions, wrappers, and configurations specifically designed for CosmWasm and Rust development. | -| [proto](/sei-js/docs/modules/proto.html) | The `/proto` package contains Sei client libraries and types generated using protocol buffers. If you're working with Sei's protocol buffer definitions or building clients for Sei services, this package will be invaluable. | +| Package | Description | +|------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [evm](/sei-js/docs/modules/evm.html) | The `/evm` package provides utilities, functions, wrappers, and configurations for seamless interaction with Sei via the Ethereum Virtual Machine (EVM). If you're building smart contracts or integrating Sei with Ethereum-based tooling, or interacting with EVM contacts like ERC20 tokens this package contains all the configs needed. | +| [cosmjs](/sei-js/docs/modules/cosmjs.html) | The `/cosmjs` package offers similar functionality to the `/evm` package but tailored for interactions with Sei via the Cosmos interfaces. It includes utilities, functions, wrappers, and configurations specifically designed for CosmWasm and Rust development. | +| [proto](/sei-js/docs/modules/proto.html) | The `/proto` package contains Sei client libraries and types generated using protocol buffers. If you're working with Sei's protocol buffer definitions or building clients for Sei services, this package will be invaluable. | +| [registry](/sei-js/docs/modules/registry.html) | The `/registry` package contains exports data from the [Sei chain-registry](https://github.com/sei-protocol/chain-registry) and the [community asset list](https://github.com/Sei-Public-Goods/sei-assetlist) as constants in typescript. | ## Resources diff --git a/codecov.yml b/codecov.yml index 9a42daa1..691f8e7d 100644 --- a/codecov.yml +++ b/codecov.yml @@ -8,6 +8,9 @@ flags: proto: paths: - packages/proto/** + registry: + paths: + - packages/registry/** coverage: status: @@ -24,3 +27,7 @@ coverage: target: 80% flags: - proto + registry: + target: 80% + flags: + - registry diff --git a/package.json b/package.json index 2ec0f6ee..9d1f55f7 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "build:all": "nx run-many --target=build", "build:since": "nx affected --target=build", "prebuild": "yarn build:since", + "postinstall": "git submodule update --init --recursive", "docs": "npx typedoc", "lint:all": "nx run-many --target=lint", "lint:since": "nx affected --target=lint", @@ -17,7 +18,7 @@ "release": "changeset publish", "postrelease": "git push --follow-tags", "release:internal-evm": "yarn build:all && yarn changeset && yarn changeset version --snapshot internal-evm && yarn changeset publish --no-git-tag --snapshot --tag internal-evm", - "test:all": "nx run-many --target=test", + "test:all": "nx run-many --target=test --skip-nx-cache", "test:since": "nx affected --target=test", "test:coverage": "nx test --all --coverage --skip-nx-cache" }, @@ -64,4 +65,3 @@ "wagmi": "^2.5.17" } } - diff --git a/packages/cosmjs/tsconfig.json b/packages/cosmjs/tsconfig.json index 3cef23f2..5e0610b5 100644 --- a/packages/cosmjs/tsconfig.json +++ b/packages/cosmjs/tsconfig.json @@ -1,7 +1,6 @@ { "extends": "../../tsconfig.base.json", "include": ["src"], - "exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"], "compilerOptions": { "outDir": "./dist/types", }, diff --git a/packages/evm/tsconfig.json b/packages/evm/tsconfig.json index 431669e3..5aa365f8 100644 --- a/packages/evm/tsconfig.json +++ b/packages/evm/tsconfig.json @@ -1,7 +1,6 @@ { "extends": "../../tsconfig.base.json", "include": ["src"], - "exclude": ["node_modules", "dist"], "compilerOptions": { "outDir": "./dist/types" }, diff --git a/packages/proto/tsconfig.json b/packages/proto/tsconfig.json index 4dd1e2f0..7997fca8 100644 --- a/packages/proto/tsconfig.json +++ b/packages/proto/tsconfig.json @@ -1,7 +1,6 @@ { "extends": "../../tsconfig.base.json", "include": ["./src/**/*"], - "exclude": ["node_modules"], "typedocOptions": { "readme": "./README.md", "name": "proto", diff --git a/packages/registry/.eslintignore b/packages/registry/.eslintignore new file mode 100644 index 00000000..f06235c4 --- /dev/null +++ b/packages/registry/.eslintignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/packages/.gitkeep b/packages/registry/.gitkeep similarity index 100% rename from packages/.gitkeep rename to packages/registry/.gitkeep diff --git a/packages/registry/.npmignore b/packages/registry/.npmignore new file mode 100644 index 00000000..6c590f14 --- /dev/null +++ b/packages/registry/.npmignore @@ -0,0 +1,13 @@ +src +node_modules +docs +coverage/ + +.gitkeep +jest.config.ts +tsconfig.json + +yarn-error.log + +.eslintignore +eslintrc.json diff --git a/packages/registry/README.md b/packages/registry/README.md new file mode 100644 index 00000000..33f11e5c --- /dev/null +++ b/packages/registry/README.md @@ -0,0 +1,14 @@ +# @sei-js/registry +This package contains TypeScript typed exports for the Sei registry repository as well as the community asset-list repository. + +## Installation +```bash +yarn add @sei-js/registry +``` + +## Usage +```typescript +import { TOKEN_LIST, NETWORKS, IBC_INFO, GAS_INFO } from '@sei-js/registry' + +const uAtom = TOKEN_LIST.find(asset => asset.denom === 'uatom') +``` diff --git a/packages/registry/RUNBOOK.md b/packages/registry/RUNBOOK.md new file mode 100644 index 00000000..62c2779c --- /dev/null +++ b/packages/registry/RUNBOOK.md @@ -0,0 +1,2 @@ +### Init submodules +`git submodule update --init --recursive` diff --git a/packages/registry/chain-registry b/packages/registry/chain-registry new file mode 160000 index 00000000..71938fc3 --- /dev/null +++ b/packages/registry/chain-registry @@ -0,0 +1 @@ +Subproject commit 71938fc346e65df7458e3458f16faab3faf198aa diff --git a/packages/registry/community-assetlist b/packages/registry/community-assetlist new file mode 160000 index 00000000..831406ba --- /dev/null +++ b/packages/registry/community-assetlist @@ -0,0 +1 @@ +Subproject commit 831406ba8cbe41f3f620c4e7a8ddca67405b5512 diff --git a/packages/registry/eslintrc.json b/packages/registry/eslintrc.json new file mode 100644 index 00000000..a85c7190 --- /dev/null +++ b/packages/registry/eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["../../eslint.base.json", "eslint:recommended", "plugin:@typescript-eslint/recommended"] +} diff --git a/packages/registry/jest.config.ts b/packages/registry/jest.config.ts new file mode 100644 index 00000000..055a5658 --- /dev/null +++ b/packages/registry/jest.config.ts @@ -0,0 +1,8 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/__tests__/**/*.ts?(x)', '**/?(*.)+(spec|test).ts?(x)'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], + modulePathIgnorePatterns: ['/dist/'] +}; diff --git a/packages/registry/package.json b/packages/registry/package.json new file mode 100644 index 00000000..bbeeb9fe --- /dev/null +++ b/packages/registry/package.json @@ -0,0 +1,50 @@ +{ + "name": "@sei-js/registry", + "version": "0.1.0", + "description": "TypeScript library for Sei chain constants and assets", + "main": "./dist/cjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/types/index.d.ts", + "sideEffects": false, + "files": [ + "dist" + ], + "scripts": { + "prebuild": "rimraf dist", + "build": "yarn build:cjs && yarn build:esm && yarn build:prettier && yarn build:types", + "build:cjs": "tsc --outDir dist/cjs --module commonjs", + "build:esm": "tsc --outDir dist/esm --module esnext", + "build:types": "tsc --project ./tsconfig.declaration.json", + "build:prettier": "prettier --write 'dist/**/*.js'", + "docs": "typedoc --out docs", + "test": "jest", + "lint": "eslint --ext .ts" + }, + "homepage": "https://github.com/sei-protocol/sei-js#readme", + "keywords": [ + "sei", + "javascript", + "typescript" + ], + "repository": "git@github.com:sei-protocol/sei-js.git", + "license": "MIT", + "private": false, + "publishConfig": { + "access": "public" + }, + "dependencies": {}, + "peerDependencies": {}, + "devDependencies": { + "@types/jest": "^29.5.5", + "jest": "^29.7.0", + "prettier": "^3.2.5", + "ts-jest": "^29.1.1" + }, + "exports": { + ".": { + "import": "./dist/esm/index.js", + "require": "./dist/cjs/index.js", + "types": "./dist/types/index.d.ts" + } + } +} diff --git a/packages/registry/src/chain-info/__tests__/index.spec.ts b/packages/registry/src/chain-info/__tests__/index.spec.ts new file mode 100644 index 00000000..8d3ca360 --- /dev/null +++ b/packages/registry/src/chain-info/__tests__/index.spec.ts @@ -0,0 +1,19 @@ +import { CHAIN_INFO } from '../index'; + +describe('ChainInfo Tests', () => { + it('has the required properties with correct types', () => { + expect(typeof CHAIN_INFO.chain_name).toBe('string'); + expect(['mainnet', 'testnet', 'devnet']).toContain(CHAIN_INFO.network_type); + expect(typeof CHAIN_INFO.chain_id).toBe('string'); + expect(typeof CHAIN_INFO.daemon_name).toBe('string'); + expect(typeof CHAIN_INFO.bech32_prefix).toBe('string'); + expect(Array.isArray(CHAIN_INFO.key_algos)).toBeTruthy(); + expect(typeof CHAIN_INFO.slip44).toBe('number'); + expect(typeof CHAIN_INFO.fee_token).toBe('string'); + expect(Array.isArray(CHAIN_INFO.supported_wallets)).toBeTruthy(); + }); + + it("includes 'secp256k1' in key_algos", () => { + expect(CHAIN_INFO.key_algos).toContain('secp256k1'); + }); +}); diff --git a/packages/registry/src/chain-info/index.ts b/packages/registry/src/chain-info/index.ts new file mode 100644 index 00000000..f41b6843 --- /dev/null +++ b/packages/registry/src/chain-info/index.ts @@ -0,0 +1,37 @@ +import ChainInfoJSON from '../../chain-registry/chain_info.json'; + +/** + * Represents the essential information about an official Sei network. + */ +export interface ChainInfo { + /** The name of the chain. (Sei) */ + chain_name: string; + /** The type of network, indicating whether it's a mainnet, testnet, or devnet. */ + network_type: 'mainnet' | 'testnet' | 'devnet'; + /** The unique identifier for the Sei network. 'pacific-1' | 'atlantic-2' | 'arctic-1' */ + chain_id: string; + /** The name of the daemon process that runs the node software for the blockchain. (seid) */ + daemon_name: string; + /** The prefix used for Bech32 encoded addresses on the network. (sei) */ + bech32_prefix: string; + /** An array of cryptographic algorithms supported by the network for key generation. */ + key_algos: string[]; + /** The SLIP-44 coin type number assigned to the network for HD wallet purposes. */ + slip44: number; + /** The denomination of the fee token used for transaction fees on the network. */ + fee_token: string; + /** A list of wallet software that supports this blockchain network. */ + supported_wallets: string[]; +} + +/** + * A constant that holds the chain information, imported from the official Sei [chain-registry](https://github.com/sei-protocol/chain-registry). + * + * @example + * ```tsx + * import { CHAIN_INFO } from '@sei-js/registry'; + * + * console.log(CHAIN_INFO.bech32_prefix); // 'sei' + * ``` + */ +export const CHAIN_INFO: ChainInfo = ChainInfoJSON as ChainInfo; diff --git a/packages/registry/src/gas/__tests__/index.spec.ts b/packages/registry/src/gas/__tests__/index.spec.ts new file mode 100644 index 00000000..e8e93d5f --- /dev/null +++ b/packages/registry/src/gas/__tests__/index.spec.ts @@ -0,0 +1,35 @@ +import { ModuleAdjustments, GAS_INFO, ChainGasInfo } from '../index'; +import { Network } from '../../index'; + +describe('GasInfo Tests', () => { + // Check if GasInfo contains all expected networks + it('contains all required networks', () => { + const expectedNetworks: Network[] = ['pacific-1', 'atlantic-2', 'arctic-1']; + expectedNetworks.forEach((network) => { + expect(GAS_INFO).toHaveProperty(network); + }); + }); + + // Validate the structure of GasInfo for each network + it('validates structure for each network', () => { + Object.values(GAS_INFO).forEach((info: ChainGasInfo) => { + expect(typeof info.denom).toBe('string'); + expect(typeof info.min_gas_price).toBe('number'); + expect(info).toHaveProperty('module_adjustments'); + expect(info.module_adjustments).toHaveProperty('dex'); + + const { dex }: { dex: ModuleAdjustments['dex'] } = info.module_adjustments; + expect(typeof dex.sudo_gas_price).toBe('number'); + expect(typeof dex.order_placement).toBe('number'); + expect(typeof dex.order_cancellation).toBe('number'); + }); + }); + + // Example: Check specific values for a network (e.g., 'pacific-1') + it('checks specific values for pacific-1', () => { + const pacific1 = GAS_INFO['pacific-1']; + expect(pacific1.denom).toBe('usei'); + expect(pacific1.min_gas_price).toBeGreaterThanOrEqual(0.01); + expect(pacific1.module_adjustments.dex.sudo_gas_price).toBeLessThanOrEqual(0.02); + }); +}); diff --git a/packages/registry/src/gas/index.ts b/packages/registry/src/gas/index.ts new file mode 100644 index 00000000..1c8bedf1 --- /dev/null +++ b/packages/registry/src/gas/index.ts @@ -0,0 +1,53 @@ +import GasInfoJSON from '../../chain-registry/gas.json'; +import { Network } from '../index'; + +/** + * Defines the gas price adjustments for specific modules within the Sei blockchain, + * allowing for differentiated gas pricing based on transaction type. + */ +export interface ModuleAdjustments { + /** Adjustments specifically for decentralized exchange (DEX) transactions. */ + dex: { + /** The sudo (superuser) gas price for critical operations. */ + sudo_gas_price: number; + /** The gas price for placing orders on the DEX. */ + order_placement: number; + /** The gas price for canceling orders on the DEX. */ + order_cancellation: number; + }; +} + +/** + * Represents the gas information for a specific Sei network, + * including the default minimum gas price and module-specific adjustments. + */ +export interface ChainGasInfo { + /** The denomination of the gas fee. */ + denom: string; + /** The minimum gas price required for transactions on the network. */ + min_gas_price: number; + /** Gas price adjustments for specific modules. */ + module_adjustments: ModuleAdjustments; +} + +/** + * A mapping of network identifiers (chain id's) to their respective gas information. + */ +type GasInfo = { + /** Each network identifier is associated with its gas information. */ + [network in Network]: ChainGasInfo; +}; + +/** + * A constant holding the gas information for each official Sei network, imported from the official Sei [chain-registry](https://github.com/sei-protocol/chain-registry). + * This includes details such as the gas denomination, minimum gas price, and module-specific adjustments. + * + * @example + * ```tsx + * import { GAS_INFO } from '@sei-js/registry'; + * + * const pacific1Info = GAS_INFO['pacific-1']; + * console.log(pacific1Info.denom); // 'usei' + * ``` + */ +export const GAS_INFO: GasInfo = GasInfoJSON as GasInfo; diff --git a/packages/registry/src/ibc/__tests__/index.spec.ts b/packages/registry/src/ibc/__tests__/index.spec.ts new file mode 100644 index 00000000..c0da19ae --- /dev/null +++ b/packages/registry/src/ibc/__tests__/index.spec.ts @@ -0,0 +1,34 @@ +import { IBC_INFO } from '../index'; +import { Network } from '../../index'; + +describe('IBCInfo Tests', () => { + // Check if IBCInfo contains all expected networks + it('contains all required networks', () => { + const expectedNetworks: Network[] = ['pacific-1', 'atlantic-2', 'arctic-1']; + expectedNetworks.forEach((network) => { + expect(IBC_INFO).toHaveProperty(network); + }); + }); + + // Validate the structure of IBCInfo for each network + it('validates structure for each network', () => { + Object.values(IBC_INFO).forEach((channels) => { + channels.forEach((channel) => { + expect(typeof channel.counterparty_chain_name).toBe('string'); + expect(typeof channel.dst_channel).toBe('string'); + expect(typeof channel.src_channel).toBe('string'); + expect(typeof channel.port_id).toBe('string'); + expect(typeof channel.client_id).toBe('string'); + }); + }); + }); + + // Example: Check specific content for a given network + it('checks specific values for a given network', () => { + const pacific1Channels = IBC_INFO['pacific-1']; + expect(pacific1Channels.length).toBeGreaterThan(0); // Ensure there's at least one channel + const firstChannel = pacific1Channels[0]; + expect(firstChannel.counterparty_chain_name).not.toBe(''); + expect(firstChannel.dst_channel.startsWith('channel-')).toBeTruthy(); + }); +}); diff --git a/packages/registry/src/ibc/index.ts b/packages/registry/src/ibc/index.ts new file mode 100644 index 00000000..37c2c44d --- /dev/null +++ b/packages/registry/src/ibc/index.ts @@ -0,0 +1,53 @@ +import IBCInfoJSON from '../../chain-registry/ibc_info.json'; +import { Network } from '../index'; + +/** + * Represents information about an IBC channel, facilitating communication + * between Sei and different blockchain networks. + */ +export interface ChannelInfo { + /** + * The name of the counterparty chain with which the channel is established. + */ + counterparty_chain_name: string; + /** + * The channel identifier on the destination chain. + */ + dst_channel: string; + /** + * The channel identifier on the source (Sei) chain. + */ + src_channel: string; + /** + * The port identifier used in the IBC communication. + */ + port_id: string; + /** + * The client identifier used for IBC communication. + */ + client_id: string; +} + +/** + * A mapping of Sei network names to arrays of `ChannelInfo`, providing + * detailed IBC channel configurations for each network. + */ +type IBCInfo = { + /** + * Associates each official Sei network with its respective array of `ChannelInfo` objects, + * detailing the IBC channels available on that network. + */ + [network in Network]: ChannelInfo[]; +}; + +/** + * A constant that holds the IBC channel information for each network, imported from the official Sei [chain-registry](https://github.com/sei-protocol/chain-registry) + * + * @example + * ```tsx + * import { IBC_INFO } from '@sei-js/registry'; + * + * const pacific1 = IBC_INFO['pacific-1'].find((ibcInfo) => ibcInfo.counterparty_chain_name === 'cosmoshub-4'); + * ``` + */ +export const IBC_INFO: IBCInfo = IBCInfoJSON as IBCInfo; diff --git a/packages/registry/src/index.ts b/packages/registry/src/index.ts new file mode 100644 index 00000000..d62e7952 --- /dev/null +++ b/packages/registry/src/index.ts @@ -0,0 +1,10 @@ +export * from './tokens'; +export * from './chain-info'; +export * from './gas'; +export * from './networks'; +export * from './ibc'; + +/** + * A TypeScript type representing the official Sei network chain identifiers. + */ +export type Network = 'pacific-1' | 'atlantic-2' | 'arctic-1'; diff --git a/packages/registry/src/networks/__tests__/index.spec.ts b/packages/registry/src/networks/__tests__/index.spec.ts new file mode 100644 index 00000000..d4b54e0f --- /dev/null +++ b/packages/registry/src/networks/__tests__/index.spec.ts @@ -0,0 +1,27 @@ +import { NETWORKS } from '../index'; + +describe('Networks configuration', () => { + it('should contain configurations for all expected Sei networks', () => { + const expectedNetworkIds = ['pacific-1', 'atlantic-2', 'arctic-1']; + + expectedNetworkIds.forEach((id) => { + expect(NETWORKS).toHaveProperty(id); + const networkConfig = NETWORKS[id]; + expect(networkConfig).toBeDefined(); + expect(networkConfig.chainId).toBe(id); + }); + }); + + it('should contain valid RPC endpoints for each network', () => { + Object.values(NETWORKS).forEach((networkConfig) => { + expect(networkConfig.rpc).toBeDefined(); + expect(Array.isArray(networkConfig.rpc)).toBeTruthy(); + networkConfig.rpc.forEach((endpoint) => { + expect(endpoint).toHaveProperty('provider'); + expect(typeof endpoint.provider).toBe('string'); + expect(endpoint).toHaveProperty('url'); + expect(typeof endpoint.url).toBe('string'); + }); + }); + }); +}); diff --git a/packages/registry/src/networks/index.ts b/packages/registry/src/networks/index.ts new file mode 100644 index 00000000..f33eae94 --- /dev/null +++ b/packages/registry/src/networks/index.ts @@ -0,0 +1,70 @@ +import NetworksJSON from '../../chain-registry/chains.json'; +import { Network } from '../index'; + +/** + * Describes an endpoint with a provider name and its associated URL. + * This can represent various services such as RPC, REST, or other APIs provided by the network. + */ +interface Endpoint { + /** The name of the service provider for the endpoint. */ + provider: string; + /** The URL of the service endpoint. */ + url: string; +} + +/** + * Represents a blockchain explorer service where transactions can be viewed and searched. + */ +interface Explorer { + /** The name of the explorer service. */ + name: string; + /** The base URL of the explorer. */ + url: string; + /** The URL template for viewing a transaction, where `${txHash}` can be replaced by an actual transaction hash. */ + tx_page: string; +} + +/** + * Contains the configuration details for a specific Sei network, + * including endpoints for various services and supported explorers. + */ +export interface NetworkConfig { + /** The unique identifier of the Sei network. */ + chainId: string; + /** The type of the network, which can be mainnet, testnet, or devnet. */ + network_type: 'mainnet' | 'testnet' | 'devnet'; + /** An array of RPC endpoints available for the network. */ + rpc: Endpoint[]; + /** An array of REST endpoints for accessing the network's RESTful services. */ + rest: Endpoint[]; + /** Optional array of gRPC endpoints, providing efficient, low-latency network communication. */ + grpc?: Endpoint[]; + /** Optional array of Ethereum Virtual Machine (EVM) compatible RPC endpoints. */ + evm_rpc?: Endpoint[]; + /** Optional array of WebSocket endpoints for EVM, supporting real-time data streaming. */ + evm_ws?: Endpoint[]; + /** Optional array of blockchain explorer that support this network. */ + explorers?: Explorer[]; + /** An array of faucet endpoints for obtaining test tokens on networks like testnets or devnets. */ + faucets?: Endpoint[]; +} + +/** + * A mapping of Sei network identifiers to their corresponding `NetworkConfig`. + */ +type NetworksConfig = { + /** Maps each network identifier to its `NetworkConfig`. */ + [key in Network]: NetworkConfig; +}; + +/** + * A constant holding the network configurations for each network, imported from the official Sei [chain-registry](https://github.com/sei-protocol/chain-registry) + * + * @example + * ```tsx + * import { NETWORKS } from '@sei-js/registry'; + * + * const pacific1 = NETWORKS.find((network) => network.chainId === 'pacific-1'); + * ``` + */ +export const NETWORKS: NetworksConfig = NetworksJSON as NetworksConfig; diff --git a/packages/registry/src/tokens/__tests__/index.spec.ts b/packages/registry/src/tokens/__tests__/index.spec.ts new file mode 100644 index 00000000..fdefd1f6 --- /dev/null +++ b/packages/registry/src/tokens/__tests__/index.spec.ts @@ -0,0 +1,46 @@ +import { TOKEN_LIST } from '../index'; +import { Network } from '../../index'; + +describe('AssetList Tests', () => { + it('should have the correct structure for each network', () => { + const networks: Network[] = ['pacific-1', 'atlantic-2', 'arctic-1']; + networks.forEach((network) => { + expect(Array.isArray(TOKEN_LIST[network])).toBeTruthy(); + TOKEN_LIST[network].forEach((asset) => { + expect(asset).toHaveProperty('name'); + expect(asset).toHaveProperty('description'); + expect(asset).toHaveProperty('symbol'); + expect(asset).toHaveProperty('base'); + expect(asset).toHaveProperty('display'); + expect(asset).toHaveProperty('denom_units'); + expect(Array.isArray(asset.denom_units)).toBeTruthy(); + asset.denom_units.forEach((denomUnit: any) => { + expect(denomUnit).toHaveProperty('denom'); + expect(denomUnit).toHaveProperty('exponent'); + expect(typeof denomUnit.denom).toBe('string'); + expect(typeof denomUnit.exponent).toBe('number'); + }); + if (asset.images) { + if (asset.images.png) expect(typeof asset.images.png).toBe('string'); + if (asset.images.svg) expect(typeof asset.images.svg).toBe('string'); + } + if (asset.coingecko_id) expect(typeof asset.coingecko_id).toBe('string'); + if (asset.type_token) expect(typeof asset.type_token).toBe('string'); + }); + }); + }); +}); + +it('should contain the "sei" asset with correct properties in each network', () => { + Object.keys(TOKEN_LIST).forEach((network) => { + const seiAsset = TOKEN_LIST[network as Network].find((asset) => asset.symbol === 'SEI'); + expect(seiAsset).toBeDefined(); + expect(seiAsset?.name).toBe('Sei'); + expect(seiAsset?.description).toBe('The native token of Sei'); + expect(seiAsset?.base).toBe('usei'); + expect(seiAsset?.denom_units.some((unit) => unit.denom === 'sei' && unit.exponent === 6)).toBeTruthy(); + if (seiAsset?.images) { + expect(seiAsset.images.png).toMatch(/^https?:\/\/.+/); + } + }); +}); diff --git a/packages/registry/src/tokens/index.ts b/packages/registry/src/tokens/index.ts new file mode 100644 index 00000000..434067f4 --- /dev/null +++ b/packages/registry/src/tokens/index.ts @@ -0,0 +1,72 @@ +import TokenListJSON from '../../community-assetlist/assetlist.json'; +import { Network } from '../index'; + +/** + * DenomUnit represents a struct that describes a given + * denomination unit of the basic token. + */ +export interface DenomUnit { + /** denom represents the string name of the given denom unit (e.g uatom). */ + denom: string; + /** + * exponent represents power of 10 exponent that one must + * raise the base_denom to in order to equal the given DenomUnit's denom + * 1 denom = 10^exponent base_denom + * (e.g. with a base_denom of uatom, one can create a DenomUnit of 'atom' with + * exponent = 6, thus: 1 atom = 10^6 uatom). + */ + exponent: number; + /** aliases is a list of string aliases for the given denom */ + aliases: string[]; +} + +/** + * Defines the structure for a Sei token. + */ +export interface Token { + /** The name of the token. */ + name: string; + /** A description of the token. */ + description: string; + /** The symbol representing the token. */ + symbol: string; + /** The base denomination of the token. */ + base: string; + /** The display denomination of the token for user interfaces. */ + display: string; + /** An array of denomination units for the token. */ + denom_units: DenomUnit[]; + /** URLs to images representing the token, in PNG and SVG formats (optional). */ + images: { + png?: string; + svg?: string; + }; + /** An optional identifier for the token on the CoinGecko platform. */ + coingecko_id?: string; + /** The type of the token, if applicable (e.g., "cw20" for CosmWasm tokens). */ + type_token?: string; +} + +/** + * A mapping of all supported Sei network names to their respective arrays of `Token` objects. + */ +type SeiTokens = { + /** Each network name is associated with an array of `Token` objects. */ + [network in Network]: Token[]; +}; + +/** + * A constant that maps each Sei networks to its respective tokens, imported from the community ran [assetlist](https://github.com/Sei-Public-Goods/sei-assetlist). + * + * @remarks + * **Important**: This token list is community-driven and subject to change. + * Always verify and filter tokens yourself before use in any production environment. + * + * @example + * ```tsx + * import { TOKEN_LIST } from '@sei-js/registry'; + * + * const uSei = TOKEN_LIST['pacific-1'].find((asset) => asset.symbol === 'sei'); + * ``` + */ +export const TOKEN_LIST: SeiTokens = TokenListJSON as unknown as SeiTokens; diff --git a/packages/registry/src/wallets/__tests__/index.spec.ts b/packages/registry/src/wallets/__tests__/index.spec.ts new file mode 100644 index 00000000..4cbd990a --- /dev/null +++ b/packages/registry/src/wallets/__tests__/index.spec.ts @@ -0,0 +1,28 @@ +import { Wallet, WALLETS } from '../index'; + +describe('Wallet Extensions Configuration Tests', () => { + it('contains an array of wallet extensions', () => { + expect(Array.isArray(WALLETS)).toBeTruthy(); + WALLETS.forEach((extension: Wallet) => { + expect(typeof extension.name).toBe('string'); + expect(typeof extension.identifier).toBe('string'); + expect(typeof extension.icon).toBe('string'); + expect(typeof extension.url).toBe('string'); + expect(Array.isArray(extension.capabilities)).toBeTruthy(); + extension.capabilities.forEach((capability) => { + expect(['native', 'evm']).toContain(capability); + }); + }); + }); + + it('contains specific wallet extension by identifier', () => { + const identifierToCheck = 'compass'; // Example identifier + const extension = WALLETS.find((ext) => ext.identifier === identifierToCheck); + expect(extension).toBeDefined(); + if (extension) { + expect(extension.name).toBe('Compass Wallet'); + expect(extension.url).toBe('https://compasswallet.io/'); + expect(extension.capabilities).toContain('native'); + } + }); +}); diff --git a/packages/registry/src/wallets/index.ts b/packages/registry/src/wallets/index.ts new file mode 100644 index 00000000..8d43d758 --- /dev/null +++ b/packages/registry/src/wallets/index.ts @@ -0,0 +1,46 @@ +import WalletsJSON from '../../chain-registry/wallets.json'; + +/** + * Defines the supported capabilities of a wallet, categorizing it by its compatibility + * with either native functionality or EVM (Ethereum Virtual Machine) based interactions. + */ +type Capability = 'native' | 'evm'; + +/** + * Describes the structure and capabilities of a wallet, + * providing essential information such as its name, unique identifier, and supported functions. + */ +export interface Wallet { + /** + * The name of the wallet. + */ + name: string; + /** + * A unique identifier for the wallet, used for referencing in code or configurations. + */ + identifier: string; + /** + * The URL to the wallet's icon image, providing a visual representation of the wallet. + */ + icon: string; + /** + * The official website or landing page URL of the wallet, where users can find more information or download the wallet. + */ + url: string; + /** + * An array of capabilities supported by the wallet, indicating whether it supports native blockchain functions, EVM-based interactions, or both. + */ + capabilities: Capability[]; +} + +/** + * A constant holding the collection of wallet extensions, imported from the official Sei [chain-registry](https://github.com/sei-protocol/chain-registry). + * + * @example + * ```tsx + * import { WALLETS } from '@sei-js/registry'; + * + * const compass = WALLETS.find((wallet) => wallet.identifier === 'compass'); + * ``` + */ +export const WALLETS: Wallet[] = WalletsJSON.extensions as Wallet[]; diff --git a/packages/registry/tsconfig.declaration.json b/packages/registry/tsconfig.declaration.json new file mode 100644 index 00000000..7d2850cd --- /dev/null +++ b/packages/registry/tsconfig.declaration.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist/types", + "declaration": true, + "emitDeclarationOnly": true, + "isolatedModules": false, + "preserveConstEnums": false + } +} diff --git a/packages/registry/tsconfig.json b/packages/registry/tsconfig.json new file mode 100644 index 00000000..fcc84c94 --- /dev/null +++ b/packages/registry/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["./src/**/*"], + "compilerOptions": { + "outDir": "./dist/types", + "rootDir": "./src", + }, + "typedocOptions": { + "readme": "./README.md", + "name": "registry", + "entryPoints": ["src/index.ts"] + } +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 8a394c77..998e713a 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -17,14 +17,17 @@ "paths": { "@sei-js/proto/types/*": ["packages/proto/dist/types/codegen/*"], "@sei-js/proto/*": ["packages/proto/dist/esm/codegen/*", "packages/proto/dist/cjs/codegen/*"], - "@sei-js/cosmjs/types/*": ["packages/cosmjs/dist/types/codegen/*"], - "@sei-js/cosmjs/*": ["packages/cosmjs/dist/esm/codegen/*", "packages/cosmjs/dist/cjs/codegen/*"], - "@sei-js/evm/types/*": ["packages/evm/dist/types/codegen/*"], - "@sei-js/evm/*": ["packages/evm/dist/esm/codegen/*", "packages/evm/dist/cjs/codegen/*"] + "@sei-js/cosmjs/types/*": ["packages/cosmjs/dist/types/*"], + "@sei-js/cosmjs/*": ["packages/cosmjs/dist/esm/*", "packages/cosmjs/dist/cjs/*"], + "@sei-js/evm/types/*": ["packages/evm/dist/types/*"], + "@sei-js/evm/*": ["packages/evm/dist/esm/*", "packages/evm/dist/cjs/*"], + "@sei-js/registry/types/*": ["packages/registry/dist/types/*"], + "@sei-js/registry/*": ["packages/registry/dist/esm/*", "packages/registry/dist/cjs/*"] } }, "exclude": [ "node_modules", + "dist", "**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", diff --git a/typedoc.config.js b/typedoc.config.js index 0ce919a5..54778c74 100644 --- a/typedoc.config.js +++ b/typedoc.config.js @@ -1,5 +1,5 @@ module.exports = { - entryPoints: ['packages/evm', 'packages/cosmjs', 'packages/proto'], + entryPoints: ['packages/evm', 'packages/cosmjs', 'packages/proto', 'packages/registry'], name: '@sei-js', entryPointStrategy: 'packages', includeVersion: false, diff --git a/yarn.lock b/yarn.lock index 6aab6ac6..58b4b50c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2090,7 +2090,7 @@ dependencies: "@emotion/memoize" "^0.8.1" -"@emotion/is-prop-valid@^1.2.1": +"@emotion/is-prop-valid@^1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz#d4175076679c6a26faa92b03bb786f9e52612337" integrity sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw== @@ -2116,10 +2116,10 @@ "@emotion/weak-memoize" "^0.3.1" hoist-non-react-statics "^3.3.1" -"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.3.tgz#84b77bfcfe3b7bb47d326602f640ccfcacd5ffb0" - integrity sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA== +"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3", "@emotion/serialize@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.4.tgz#fc8f6d80c492cfa08801d544a05331d1cc7cd451" + integrity sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ== dependencies: "@emotion/hash" "^0.9.1" "@emotion/memoize" "^0.8.1" @@ -2133,14 +2133,14 @@ integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== "@emotion/styled@^11.10.6": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.0.tgz#26b75e1b5a1b7a629d7c0a8b708fbf5a9cdce346" - integrity sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng== + version "11.11.5" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.5.tgz#0c5c8febef9d86e8a926e663b2e5488705545dfb" + integrity sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ== dependencies: "@babel/runtime" "^7.18.3" "@emotion/babel-plugin" "^11.11.0" - "@emotion/is-prop-valid" "^1.2.1" - "@emotion/serialize" "^1.1.2" + "@emotion/is-prop-valid" "^1.2.2" + "@emotion/serialize" "^1.1.4" "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" "@emotion/utils" "^1.2.1" @@ -4430,10 +4430,10 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@wagmi/connectors@4.1.24": - version "4.1.24" - resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-4.1.24.tgz#e9ffa2944391ef24ced6e2dc524f429514274722" - integrity sha512-gFziI7E3m+ESJmEnsvlm/eMlboKwdfGqOOQIU068MoZ+ZcNxoLZe4gu8CqnrmG7ksdPtwG38prsMl96opZexIA== +"@wagmi/connectors@4.1.23": + version "4.1.23" + resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-4.1.23.tgz#34ecc4c03e1ff666d1ff743777bc21e95cbc037d" + integrity sha512-IgGCJvQfvCBI9Kq0TvudYPnz/HQSqTuXrNKPHT+SIQaaHebDmPdJYPvj4fgdEPtU3Z5fDtQsBszVpbfcYXgWKA== dependencies: "@coinbase/wallet-sdk" "3.9.1" "@metamask/sdk" "0.14.3" @@ -4442,10 +4442,10 @@ "@walletconnect/ethereum-provider" "2.11.2" "@walletconnect/modal" "2.6.2" -"@wagmi/core@2.6.15": - version "2.6.15" - resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-2.6.15.tgz#14dca5f575d5267d72016448623bdd6c959d178b" - integrity sha512-P3w7NIPBs6Pt3j8k5Tq9cVYjvUiyuEAk3WxZfUG5NyaveLqs3b6IC6Frl63zriSV3Bj0tdJJXhEVoIIeIUqMCA== +"@wagmi/core@2.6.14": + version "2.6.14" + resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-2.6.14.tgz#b69362e483b306d0ac323acd9875b44bffb9c62a" + integrity sha512-en2DN/Dt059ROJRyLh/M7xN/U8cxHHC+TFEQPpifIJbh4VzUJXdjF+Oqzg/FFqn6JO5wvibFZGT0j4uPclUE2A== dependencies: eventemitter3 "5.0.1" mipd "0.0.5" @@ -5651,9 +5651,9 @@ convert-source-map@^2.0.0: integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== cookie-es@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.0.0.tgz#4759684af168dfc54365b2c2dda0a8d7ee1e4865" - integrity sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.1.0.tgz#68f8d9f48aeb5a534f3896f80e792760d3d20def" + integrity sha512-L2rLOcK0wzWSfSDA33YR+PUHDG10a8px7rUHKWbGLP4YfbsMed2KFUw5fczvDPbT98DDe3LEzviswl810apTEw== core-js-compat@^3.21.0, core-js-compat@^3.22.1, core-js-compat@^3.31.0, core-js-compat@^3.36.1: version "3.36.1" @@ -7400,9 +7400,9 @@ human-signals@^5.0.0: integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== i18next-browser-languagedetector@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.2.0.tgz#de0321cba6881be37d82e20e4d6f05aa75f6e37f" - integrity sha512-U00DbDtFIYD3wkWsr2aVGfXGAj2TgnELzOX9qv8bT0aJtvPV9CRO77h+vgmHFBMe7LAxdwvT/7VkCWGya6L3tA== + version "7.2.1" + resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.2.1.tgz#1968196d437b4c8db847410c7c33554f6c448f6f" + integrity sha512-h/pM34bcH6tbz8WgGXcmWauNpQupCGr25XPp9cZwZInR9XHSjIFDYp1SIok7zSPsTOMxdvuLyu86V+g2Kycnfw== dependencies: "@babel/runtime" "^7.23.2" @@ -11487,9 +11487,9 @@ valtio@1.11.2: use-sync-external-store "1.2.0" viem@2.x: - version "2.9.0" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.9.0.tgz#f59cd9b44d07ceaeacfd33477f116274860fd35d" - integrity sha512-7jNrY9GY4aLGU2qX4/TCXpA9qR4PDx5ctQyJpxoh8jDmlV0Rh2FLlnJsgJs9sAB8cKbNafkRTYQtuMA3OOn0JA== + version "2.9.7" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.9.7.tgz#01ca9f886a6f7113acb489b587c1f7787c791049" + integrity sha512-/yy+pkv3e+DrZg6cXbcsx/MUFplgUz1XuHJ1iaMChVkMlO/m7keBYGhs0rOJSqPI6D5onND7Xhki56Vab5i6hg== dependencies: "@adraffy/ens-normalize" "1.10.0" "@noble/curves" "1.2.0" @@ -11544,12 +11544,12 @@ w3c-xmlserializer@^3.0.0: xml-name-validator "^4.0.0" wagmi@^2.5.17: - version "2.5.18" - resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-2.5.18.tgz#aff4477929399ba55eb29766249ba51f51f390c7" - integrity sha512-V2NTcgI1kZxLZcpW/FaS5KEoc89IkW8b39kBEZLzCFMIiSYqOINoq2N1S5Y9ZD8PYFmBmvFC0KxQ0uNBmWi+pg== + version "2.5.17" + resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-2.5.17.tgz#f4d848aea984e0703ea33a7cd9616a08ea1ddd90" + integrity sha512-VY1D/S890HAMeMWaFNb26ObrBJVXaSdJFGiHuRTVRBAi6UlutK3g/VNWNPydmYBqL7X6Lu672n2cruTo3B/JlQ== dependencies: - "@wagmi/connectors" "4.1.24" - "@wagmi/core" "2.6.15" + "@wagmi/connectors" "4.1.23" + "@wagmi/core" "2.6.14" use-sync-external-store "1.2.0" walker@^1.0.8: