From 612ae7dc07c3f865a109ee51980bb0fadb72184e Mon Sep 17 00:00:00 2001 From: Kashif Jamil Date: Wed, 15 Apr 2026 13:34:49 +0530 Subject: [PATCH] feat(statics): add Kaspa to statics and environments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add KaspaCoin class and kaspa() factory function in statics/src/kaspa.ts - Add CoinFamily.KASPA, UnderlyingAsset.KASPA, BaseUnit.KASPA (sompi) to base.ts - Add KaspaMainnet + KaspaTestnet network classes and Networks entries in networks.ts - Add kaspa/tkaspa coin entries with UUIDs to allCoinsAndTokens.ts - Export KaspaCoin from statics/src/index.ts - Add kaspa/tkaspa to expectedColdFeatures.ts (justTSS — ECDSA TSS support) - Add kaspaNodeUrl to EnvironmentTemplate interface and mainnet/testnet bases in environments.ts Jira: CECHO-388 --- modules/sdk-core/src/bitgo/environments.ts | 3 + modules/statics/src/allCoinsAndTokens.ts | 3 + modules/statics/src/base.ts | 3 + modules/statics/src/index.ts | 1 + modules/statics/src/kaspa.ts | 90 +++++++++++++++++++ modules/statics/src/networks.ts | 16 ++++ .../unit/fixtures/expectedColdFeatures.ts | 2 + 7 files changed, 118 insertions(+) create mode 100644 modules/statics/src/kaspa.ts diff --git a/modules/sdk-core/src/bitgo/environments.ts b/modules/sdk-core/src/bitgo/environments.ts index 8f210a7718..824130ce1c 100644 --- a/modules/sdk-core/src/bitgo/environments.ts +++ b/modules/sdk-core/src/bitgo/environments.ts @@ -77,6 +77,7 @@ interface EnvironmentTemplate { sgbExplorerBaseUrl?: string; sgbExplorerApiToken?: string; icpNodeUrl: string; + kaspaNodeUrl: string; hyperLiquidNodeUrl: string; wemixExplorerBaseUrl?: string; wemixExplorerApiToken?: string; @@ -358,6 +359,7 @@ const mainnetBase: EnvironmentTemplate = { }, }, icpNodeUrl: 'https://ic0.app', + kaspaNodeUrl: 'https://api.kaspa.org', hyperLiquidNodeUrl: 'https://api.hyperliquid.xyz', worldExplorerBaseUrl: 'https://worldscan.org/', somniaExplorerBaseUrl: 'https://mainnet.somnia.w3us.site/', @@ -436,6 +438,7 @@ const testnetBase: EnvironmentTemplate = { xdcExplorerBaseUrl: 'https://api.etherscan.io/v2', sgbExplorerBaseUrl: 'https://coston-explorer.flare.network', icpNodeUrl: 'https://ic0.app', + kaspaNodeUrl: 'https://api-tn10.kaspa.org', hyperLiquidNodeUrl: 'https://api.hyperliquid-testnet.xyz', monExplorerBaseUrl: 'https://api.etherscan.io/v2', worldExplorerBaseUrl: 'https://sepolia.worldscan.org/', diff --git a/modules/statics/src/allCoinsAndTokens.ts b/modules/statics/src/allCoinsAndTokens.ts index 47e195cbef..a5280f2e1e 100644 --- a/modules/statics/src/allCoinsAndTokens.ts +++ b/modules/statics/src/allCoinsAndTokens.ts @@ -76,6 +76,7 @@ import { polyxTokens } from './coins/polyxTokens'; import { cantonTokens } from './coins/cantonTokens'; import { flrp } from './flrp'; import { hypeEvm } from './hypeevm'; +import { kaspa } from './kaspa'; import { ACCOUNT_COIN_DEFAULT_FEATURES_EXCLUDE_SINGAPORE_AND_MENA_FZE, ADA_FEATURES, @@ -187,6 +188,8 @@ export const allCoinsAndTokens = [ Networks.test.flrP, UnderlyingAsset.FLRP ), + kaspa('3eebd6e4-b30a-4b37-819d-1e189372b5c9', 'kaspa', 'Kaspa', Networks.main.kaspa, UnderlyingAsset.KASPA), + kaspa('96b7ccfb-6130-43b2-a324-783f86752b94', 'tkaspa', 'Testnet Kaspa', Networks.test.kaspa, UnderlyingAsset.KASPA), ada( 'fd4d125e-f14f-414b-bd17-6cb1393265f0', 'ada', diff --git a/modules/statics/src/base.ts b/modules/statics/src/base.ts index 0e5da11acb..05b1bba95a 100644 --- a/modules/statics/src/base.ts +++ b/modules/statics/src/base.ts @@ -80,6 +80,7 @@ export enum CoinFamily { ISLM = 'islm', JOVAYETH = 'jovayeth', KAIA = 'kaia', + KASPA = 'kaspa', KAVACOSMOS = 'kavacosmos', KAVAEVM = 'kavaevm', LNBTC = 'lnbtc', @@ -1323,6 +1324,7 @@ export enum UnderlyingAsset { KARATE = 'karate', KARMA = 'karma', KAS = 'kas', + KASPA = 'kaspa', KCASH = 'kcash', KCS = 'kcs', KEEP = 'keep', @@ -3853,6 +3855,7 @@ export enum BaseUnit { TCRONOS = 'basetcro', TASI = 'atestfet', CANTON = 'canton', + KASPA = 'sompi', USDC = 'usdc', } diff --git a/modules/statics/src/index.ts b/modules/statics/src/index.ts index 58a31c97d4..243d3e5a90 100644 --- a/modules/statics/src/index.ts +++ b/modules/statics/src/index.ts @@ -3,6 +3,7 @@ export * from './coins'; export * from './networks'; export * from './errors'; export * from './tokenConfig'; +export { KaspaCoin } from './kaspa'; export { OfcCoin } from './ofc'; export { UtxoCoin } from './utxo'; export { LightningCoin } from './lightning'; diff --git a/modules/statics/src/kaspa.ts b/modules/statics/src/kaspa.ts new file mode 100644 index 0000000000..906bbc52bd --- /dev/null +++ b/modules/statics/src/kaspa.ts @@ -0,0 +1,90 @@ +import { BaseCoin, BaseUnit, CoinFeature, CoinKind, KeyCurve, UnderlyingAsset } from './base'; +import { KaspaMainnet, KaspaTestnet } from './networks'; + +export interface KaspaConstructorOptions { + id: string; + fullName: string; + name: string; + network: KaspaMainnet | KaspaTestnet; + features: CoinFeature[]; + asset: UnderlyingAsset; + prefix?: string; + suffix?: string; + primaryKeyCurve: KeyCurve; +} + +export class KaspaCoin extends BaseCoin { + public static readonly DEFAULT_FEATURES = [ + CoinFeature.UNSPENT_MODEL, + CoinFeature.TSS, + CoinFeature.TSS_COLD, + CoinFeature.CUSTODY, + CoinFeature.CUSTODY_BITGO_TRUST, + CoinFeature.CUSTODY_BITGO_INDIA, + CoinFeature.CUSTODY_BITGO_MENA_FZE, + CoinFeature.CUSTODY_BITGO_CUSTODY_MENA_FZE, + CoinFeature.CUSTODY_BITGO_GERMANY, + CoinFeature.CUSTODY_BITGO_FRANKFURT, + ]; + + public readonly network: KaspaMainnet | KaspaTestnet; + + constructor(options: KaspaConstructorOptions) { + super({ + ...options, + kind: CoinKind.CRYPTO, + isToken: false, + decimalPlaces: 8, + baseUnit: BaseUnit.KASPA, + }); + + this.network = options.network; + } + + protected disallowedFeatures(): Set { + return new Set([CoinFeature.ACCOUNT_MODEL]); + } + + protected requiredFeatures(): Set { + return new Set([CoinFeature.UNSPENT_MODEL]); + } +} + +/** + * Factory function for Kaspa coin instances. + * + * @param id uuid v4 + * @param name unique identifier of the coin + * @param fullName Complete human-readable name of the coin + * @param network Network object for this coin + * @param asset Asset which this coin represents. This is the same for both mainnet and testnet variants of a coin. + * @param features? Features of this coin. Defaults to the DEFAULT_FEATURES defined in `KaspaCoin` + * @param prefix? Optional coin prefix. Defaults to empty string + * @param suffix? Optional coin suffix. Defaults to coin name. + * @param primaryKeyCurve The elliptic curve for this chain/token + */ +export function kaspa( + id: string, + name: string, + fullName: string, + network: KaspaMainnet | KaspaTestnet, + asset: UnderlyingAsset, + features: CoinFeature[] = KaspaCoin.DEFAULT_FEATURES, + prefix = '', + suffix: string = name.toUpperCase(), + primaryKeyCurve: KeyCurve = KeyCurve.Secp256k1 +) { + return Object.freeze( + new KaspaCoin({ + id, + name, + fullName, + network, + prefix, + suffix, + features, + asset, + primaryKeyCurve, + }) + ); +} diff --git a/modules/statics/src/networks.ts b/modules/statics/src/networks.ts index f839754cdb..bd5ff098b4 100644 --- a/modules/statics/src/networks.ts +++ b/modules/statics/src/networks.ts @@ -268,6 +268,20 @@ class IcpTestnet extends Testnet implements AccountNetwork { accountExplorerUrl = 'https://dashboard.internetcomputer.org/account/'; } +export class KaspaMainnet extends Mainnet implements AccountNetwork { + name = 'Kaspa'; + family = CoinFamily.KASPA; + explorerUrl = 'https://explorer.kaspa.org/txs/'; + accountExplorerUrl = 'https://explorer.kaspa.org/addresses/'; +} + +export class KaspaTestnet extends Testnet implements AccountNetwork { + name = 'Testnet Kaspa'; + family = CoinFamily.KASPA; + explorerUrl = 'https://explorer-tn10.kaspa.org/txs/'; + accountExplorerUrl = 'https://explorer-tn10.kaspa.org/addresses/'; +} + class Arbitrum extends Mainnet implements EthereumNetwork { name = 'Arbitrum'; family = CoinFamily.ARBETH; @@ -2762,6 +2776,7 @@ export const Networks = { islm: Object.freeze(new Islm()), jovayeth: Object.freeze(new JovayETH()), kaia: Object.freeze(new Kaia()), + kaspa: Object.freeze(new KaspaMainnet()), kavacosmos: Object.freeze(new KavaCosmos()), kavaevm: Object.freeze(new KavaEVM()), lnbtc: Object.freeze(new LightningBitcoin()), @@ -2888,6 +2903,7 @@ export const Networks = { irys: Object.freeze(new IrysTestnet()), islm: Object.freeze(new IslmTestnet()), jovayeth: Object.freeze(new JovayETHTestnet()), + kaspa: Object.freeze(new KaspaTestnet()), kavacosmos: Object.freeze(new KavaCosmosTestnet()), kavaevm: Object.freeze(new KavaEVMTestnet()), kovan: Object.freeze(new Kovan()), diff --git a/modules/statics/test/unit/fixtures/expectedColdFeatures.ts b/modules/statics/test/unit/fixtures/expectedColdFeatures.ts index 563f4ea564..45f2f0256e 100644 --- a/modules/statics/test/unit/fixtures/expectedColdFeatures.ts +++ b/modules/statics/test/unit/fixtures/expectedColdFeatures.ts @@ -112,6 +112,7 @@ export const expectedColdFeatures = { 'injective', 'jovayeth', 'kaia', + 'kaspa', 'kavacosmos', 'megaeth', 'mantle', @@ -205,6 +206,7 @@ export const expectedColdFeatures = { 'tinjective', 'tiota', 'tkaia', + 'tkaspa', 'tkavacosmos', 'tmantle', 'tmantra',