-
Notifications
You must be signed in to change notification settings - Fork 308
feat(statics): add bip44CoinType per coin family #9882
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import { SAFE_ROOT_SLOT_ORDINALS } from '@bitgo/statics'; | ||
| import type { RootKeyType } from '@bitgo/public-types'; | ||
| import { SAFE_ROOT_SLOTS } from '../../../../src/bitgo/safe/rootCoin'; | ||
|
|
||
| describe('SAFE_ROOT_SLOTS', function () { | ||
| it('should match the slot ordinals served from statics, in order', function () { | ||
| // typed as Record<RootKeyType, number>, so a slot missing from statics is a compile error | ||
| const ordinals: Record<RootKeyType, number> = SAFE_ROOT_SLOT_ORDINALS; | ||
| SAFE_ROOT_SLOTS.map((slot) => ordinals[slot]).should.deepEqual(SAFE_ROOT_SLOTS.map((_, i) => i + 1)); | ||
| Object.keys(SAFE_ROOT_SLOT_ORDINALS).should.deepEqual(SAFE_ROOT_SLOTS); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| import type { CoinFamily } from './base'; | ||
|
|
||
| /** | ||
| * BIP44 coin types are assigned per coin family: a coin family covers a mainnet chain, its testnet | ||
| * mirror (`btc`/`tbtc`) and every token on it, which all share one coin type by design. Safe child | ||
| * key uniqueness comes from per-(slot, coinType) account allocation, never from coin type uniqueness. | ||
| */ | ||
| type CoinFamilyName = `${CoinFamily}`; | ||
|
|
||
| /** | ||
| * Families with no BIP44 coin type: OFC and fiat are not BIP44-derivable, and `dydx` and `eth2` have no | ||
| * key-holding coins yet. A new family must be added to the table below or to this list, so skipping | ||
| * the decision is a compile error. | ||
| */ | ||
| type CoinFamilyWithoutCoinType = 'ofc' | 'fiat' | 'dydx' | 'eth2'; | ||
|
|
||
| /** | ||
| * BitGo's BIP44 coin type per coin family, used as `m/44'/<coinType>'/<slot>'/<account>'`. | ||
| * The values are BitGo's own: some deliberately match SLIP-44 (btc 0, eth 60, ...), but the registry | ||
| * is not binding. Values are unique per family and paths are immutable once keys exist, so never | ||
| * change one. A new coin family takes the next free value above the highest (0x70000000 and up). | ||
| */ | ||
| export const BIP44_COIN_TYPES: Record<Exclude<CoinFamilyName, CoinFamilyWithoutCoinType>, number> = { | ||
| btc: 0, | ||
| ltc: 2, | ||
| doge: 3, | ||
| dash: 5, | ||
| eth: 60, | ||
| etc: 61, | ||
| atom: 118, | ||
| zec: 133, | ||
| rbtc: 137, | ||
| xrp: 144, | ||
| bch: 145, | ||
| xlm: 148, | ||
| btg: 156, | ||
| eos: 194, | ||
| trx: 195, | ||
| icp: 223, | ||
| bsv: 236, | ||
| algo: 283, | ||
| dot: 354, | ||
| near: 397, | ||
| kavacosmos: 459, | ||
| sol: 501, | ||
| hash: 505, | ||
| cspr: 506, | ||
| flow: 539, | ||
| xdc: 550, | ||
| bld: 564, | ||
| ctc: 583, | ||
| polyx: 595, | ||
| ton: 607, | ||
| apt: 637, | ||
| oas: 685, | ||
| baby: 736, | ||
| sui: 784, | ||
| vet: 818, | ||
| bcha: 899, | ||
| thor: 931, | ||
| polygon: 966, | ||
| lnbtc: 998, | ||
| tao: 1005, | ||
| fantom: 1007, | ||
| coredao: 1116, | ||
| islm: 1348, | ||
| xtz: 1729, | ||
| ada: 1815, | ||
| hyperliquid: 2457, | ||
| hbar: 3030, | ||
| phrs: 3172, | ||
| irys: 3282, | ||
| iota: 4218, | ||
| somi: 5031, | ||
| stx: 5757, | ||
| canton: 6767, | ||
| zeta: 7000, | ||
| bera: 8008, | ||
| kaia: 8217, | ||
| starknet: 9004, | ||
| avaxc: 9005, | ||
| sonic: 10007, | ||
| celo: 52752, | ||
| kaspa: 111111, | ||
| scrolleth: 534352, | ||
| osmo: 10000118, | ||
| sei: 19000118, | ||
| dydxcosmos: 22000118, | ||
| injective: 22000119, | ||
| mon: 268435779, | ||
| abstracteth: 0x70000000, | ||
| apechain: 0x70000001, | ||
| arbeth: 0x70000002, | ||
| arcusdc: 0x70000003, | ||
| asi: 0x70000004, | ||
| avaxp: 0x70000005, | ||
| baseeth: 0x70000006, | ||
| bobaeth: 0x70000007, | ||
| bsc: 0x70000008, | ||
| chiliz: 0x70000009, | ||
| codexeth: 0x7000000a, | ||
| coreum: 0x7000000b, | ||
| cotieth: 0x7000000c, | ||
| cronos: 0x7000000d, | ||
| dogeos: 0x7000000e, | ||
| ethw: 0x7000000f, | ||
| fetchai: 0x70000010, | ||
| flr: 0x70000011, | ||
| flrp: 0x70000012, | ||
| fluenteth: 0x70000013, | ||
| gasevm: 0x70000014, | ||
| h: 0x70000015, | ||
| hbarevm: 0x70000016, | ||
| hemieth: 0x70000017, | ||
| hoodeth: 0x70000018, | ||
| hppeth: 0x70000019, | ||
| hypeevm: 0x7000001a, | ||
| initia: 0x7000001b, | ||
| inketh: 0x7000001c, | ||
| ip: 0x7000001d, | ||
| jovayeth: 0x7000001e, | ||
| katanaeth: 0x7000001f, | ||
| kavaevm: 0x70000020, | ||
| lineaeth: 0x70000021, | ||
| mantle: 0x70000022, | ||
| mantra: 0x70000023, | ||
| megaeth: 0x70000024, | ||
| morph: 0x70000025, | ||
| morpheth: 0x70000026, | ||
| og: 0x70000027, | ||
| okbxlayer: 0x70000028, | ||
| opbnb: 0x70000029, | ||
| opeth: 0x7000002a, | ||
| pearl: 0x7000002b, | ||
| plume: 0x7000002c, | ||
| prividiumeth: 0x7000002d, | ||
| seievm: 0x7000002e, | ||
| sgb: 0x7000002f, | ||
| soneium: 0x70000030, | ||
| stt: 0x70000031, | ||
| susd: 0x70000032, | ||
| tempo: 0x70000033, | ||
| tia: 0x70000034, | ||
| unieth: 0x70000035, | ||
| usdt0: 0x70000036, | ||
| wemix: 0x70000037, | ||
| world: 0x70000038, | ||
| xpl: 0x70000039, | ||
| xtzevm: 0x7000003a, | ||
| zketh: 0x7000003b, | ||
| zksyncera: 0x7000003c, | ||
| }; | ||
|
|
||
| /** | ||
| * The BIP44 coin type of a coin family, or undefined if the family has none (OFC and fiat). | ||
| */ | ||
| export function getBip44CoinType(family: CoinFamily): number | undefined { | ||
| const coinTypes: Partial<Record<CoinFamilyName, number>> = BIP44_COIN_TYPES; | ||
| return coinTypes[family]; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,9 @@ | ||
| export const DOMAIN_PATTERN = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/; | ||
|
|
||
| export const HEDERA_NODE_ACCCOUNT_ID = '0.0.3'; | ||
|
|
||
| /** | ||
| * Highest BIP32 child index below the hardened offset (2^31 - 1), which is also the highest valid | ||
| * BIP44 coin type. | ||
| */ | ||
| export const MAX_BIP32_INDEX = 0x7fffffff; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import { BaseCoin, CoinKind } from './base'; | ||
| import { OfcCoin } from './ofc'; | ||
|
|
||
| /** | ||
| * A safe's root slot, by (curve, scheme). Mirrors `RootKeyType` in `@bitgo/public-types`, which is the | ||
| * canonical source of these names; statics cannot depend on that package. | ||
| * @experimental | ||
| */ | ||
| export type SafeRootSlot = 'secp256k1Multisig' | 'ed25519Multisig' | 'ecdsaMpc' | 'eddsaMpc'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit (non-blocking): This adds a third name for the same 4-value union — public-types has
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a comment clarifying and test that the slots match for this |
||
|
|
||
| /** | ||
| * Fixed ordinal (1–4) of each safe root slot: the `<slot>` segment of the safe child derivation path. | ||
| * User children are hardened-derived at `m/44'/<bip44CoinType>'/<slot>'/<account>'` and multisig | ||
| * co-signers are soft-derived at the same numeric path without hardening. The ordinals follow | ||
| * `SAFE_ROOT_SLOTS` in `@bitgo/sdk-core`. | ||
| * @experimental | ||
| */ | ||
| export const SAFE_ROOT_SLOT_ORDINALS: Record<SafeRootSlot, number> = { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is it possible to move these types to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| secp256k1Multisig: 1, | ||
| ed25519Multisig: 2, | ||
| ecdsaMpc: 3, | ||
| eddsaMpc: 4, | ||
| }; | ||
|
|
||
| /** | ||
| * Whether safe child keys can be derived for the coin. OFC (off-chain virtual assets) and fiat | ||
| * coins carry no `bip44CoinType` and cannot mint a safe child key. | ||
| * @experimental | ||
| */ | ||
| export function isBip44Derivable(coin: Readonly<BaseCoin>): boolean { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit (non-blocking):
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have a set of tickets for this work and this is planned |
||
| return !(coin instanceof OfcCoin) && coin.kind !== CoinKind.FIAT; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit (non-blocking): Validation asymmetry — explicitly-passed
bip44CoinTypevalues are range-checked here, but family-derived values (the?? getBip44CoinType(...)fallback in the constructor) are only guarded by theBIP44_COIN_TYPEStable test. Consistent today since the table is tested, just worth being aware the two paths carry different guarantees.