chore: sync submodule state (parent ref update)
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Tests for ISO-4217 compliant symbol validation and parsing.
|
||||
*/
|
||||
|
||||
import {
|
||||
isValidNativeSymbol,
|
||||
isValidBridgedSymbol,
|
||||
parseSymbol,
|
||||
} from './iso4217-symbol-validator';
|
||||
import { V0_TO_V1_SYMBOL_MAP, getV1IdentityForV0Symbol } from '../config/iso4217-symbol-registry';
|
||||
|
||||
describe('isValidNativeSymbol', () => {
|
||||
it('accepts valid 6-char native symbols', () => {
|
||||
expect(isValidNativeSymbol('cAUSDT')).toBe(true);
|
||||
expect(isValidNativeSymbol('cXUSDC')).toBe(true);
|
||||
expect(isValidNativeSymbol('cAUSDC')).toBe(true);
|
||||
expect(isValidNativeSymbol('cXEURC')).toBe(true);
|
||||
expect(isValidNativeSymbol('cAGBPT')).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects v0 legacy (no chain designator)', () => {
|
||||
expect(isValidNativeSymbol('cUSDT')).toBe(false);
|
||||
expect(isValidNativeSymbol('cUSDC')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects missing type', () => {
|
||||
expect(isValidNativeSymbol('cAUSD')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects wrong length', () => {
|
||||
expect(isValidNativeSymbol('cAUSDCX')).toBe(false);
|
||||
expect(isValidNativeSymbol('cAUSD')).toBe(false);
|
||||
expect(isValidNativeSymbol('')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects invalid ISO code', () => {
|
||||
expect(isValidNativeSymbol('cAXXXT')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects invalid chain designator', () => {
|
||||
expect(isValidNativeSymbol('cBUSDT')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isValidBridgedSymbol', () => {
|
||||
it('accepts valid 7-char bridged symbols', () => {
|
||||
expect(isValidBridgedSymbol('cWAUSDT')).toBe(true);
|
||||
expect(isValidBridgedSymbol('cWXUSDC')).toBe(true);
|
||||
expect(isValidBridgedSymbol('cWAEURC')).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects native 6-char', () => {
|
||||
expect(isValidBridgedSymbol('cAUSDT')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects missing W at position 2', () => {
|
||||
expect(isValidBridgedSymbol('cWAUSD')).toBe(false);
|
||||
expect(isValidBridgedSymbol('cAUSDTX')).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects invalid length', () => {
|
||||
expect(isValidBridgedSymbol('cWAUSD')).toBe(false);
|
||||
expect(isValidBridgedSymbol('cWAUSDTW')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseSymbol', () => {
|
||||
it('parses v0 symbols and returns v1 identity', () => {
|
||||
const cusdt = parseSymbol('cUSDT');
|
||||
expect(cusdt).not.toBeNull();
|
||||
expect(cusdt!.type).toBe('v0');
|
||||
expect(cusdt!.iso).toBe('USD');
|
||||
expect(cusdt!.typeChar).toBe('T');
|
||||
expect(cusdt!.originChain).toBe('X');
|
||||
expect(cusdt!.v1Identity).toEqual({ iso: 'USD', type: 'T', originChain: 'X' });
|
||||
|
||||
const cusdc = parseSymbol('cUSDC');
|
||||
expect(cusdc).not.toBeNull();
|
||||
expect(cusdc!.type).toBe('v0');
|
||||
expect(cusdc!.iso).toBe('USD');
|
||||
expect(cusdc!.typeChar).toBe('C');
|
||||
expect(cusdc!.originChain).toBe('X');
|
||||
});
|
||||
|
||||
it('parses native 6-char symbols', () => {
|
||||
const p = parseSymbol('cAUSDT');
|
||||
expect(p).not.toBeNull();
|
||||
expect(p!.type).toBe('native');
|
||||
expect(p!.iso).toBe('USD');
|
||||
expect(p!.typeChar).toBe('T');
|
||||
expect(p!.originChain).toBe('A');
|
||||
});
|
||||
|
||||
it('parses bridged 7-char symbols', () => {
|
||||
const p = parseSymbol('cWXUSDC');
|
||||
expect(p).not.toBeNull();
|
||||
expect(p!.type).toBe('bridged');
|
||||
expect(p!.iso).toBe('USD');
|
||||
expect(p!.typeChar).toBe('C');
|
||||
expect(p!.originChain).toBe('X');
|
||||
});
|
||||
|
||||
it('returns null for invalid or unknown symbols', () => {
|
||||
expect(parseSymbol('cAUSD')).toBeNull();
|
||||
expect(parseSymbol('invalid')).toBeNull();
|
||||
expect(parseSymbol('')).toBeNull();
|
||||
expect(parseSymbol(null as unknown as string)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('v0 to v1 map lookup', () => {
|
||||
it('V0_TO_V1_SYMBOL_MAP has correct entries', () => {
|
||||
expect(V0_TO_V1_SYMBOL_MAP.cUSDT).toEqual({ iso: 'USD', type: 'T', originChain: 'X' });
|
||||
expect(V0_TO_V1_SYMBOL_MAP.cUSDC).toEqual({ iso: 'USD', type: 'C', originChain: 'X' });
|
||||
});
|
||||
|
||||
it('getV1IdentityForV0Symbol returns identity for v0 symbols', () => {
|
||||
expect(getV1IdentityForV0Symbol('cUSDT')).toEqual({ iso: 'USD', type: 'T', originChain: 'X' });
|
||||
expect(getV1IdentityForV0Symbol('cUSDC')).toEqual({ iso: 'USD', type: 'C', originChain: 'X' });
|
||||
expect(getV1IdentityForV0Symbol('cAUSDT')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* ISO-4217 compliant token symbol validation.
|
||||
* Validates 6-char native and 7-char bridged symbols; parses and resolves v0 legacy.
|
||||
* See docs/04-configuration/ISO4217_COMPLIANT_TOKEN_MATRIX.md
|
||||
*/
|
||||
|
||||
import {
|
||||
FIN_CHAIN_SET,
|
||||
ISO4217_SUPPORTED,
|
||||
ASSET_TYPE_SET,
|
||||
V0_TO_V1_SYMBOL_MAP,
|
||||
isFinChainDesignator,
|
||||
isISO4217Supported,
|
||||
isAssetTypeChar,
|
||||
type V1SymbolIdentity,
|
||||
} from '../config/iso4217-symbol-registry';
|
||||
|
||||
export type ParsedSymbolType = 'native' | 'bridged' | 'v0';
|
||||
|
||||
export interface ParsedSymbol {
|
||||
type: ParsedSymbolType;
|
||||
iso?: string;
|
||||
typeChar?: string;
|
||||
originChain?: string;
|
||||
v1Identity?: V1SymbolIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates native (6-char) symbol: c + FinChain + ISO4217 + Type
|
||||
*/
|
||||
export function isValidNativeSymbol(s: string): boolean {
|
||||
if (typeof s !== 'string' || s.length !== 6) return false;
|
||||
if (s[0] !== 'c') return false;
|
||||
if (!isFinChainDesignator(s[1])) return false;
|
||||
const iso = s.slice(2, 5);
|
||||
if (!isISO4217Supported(iso)) return false;
|
||||
if (!isAssetTypeChar(s[5])) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates bridged (7-char) symbol: c + W + OriginFinChain + ISO4217 + Type
|
||||
*/
|
||||
export function isValidBridgedSymbol(s: string): boolean {
|
||||
if (typeof s !== 'string' || s.length !== 7) return false;
|
||||
if (s[0] !== 'c') return false;
|
||||
if (s[1] !== 'W') return false;
|
||||
if (!isFinChainDesignator(s[2])) return false;
|
||||
const iso = s.slice(3, 6);
|
||||
if (!isISO4217Supported(iso)) return false;
|
||||
if (!isAssetTypeChar(s[6])) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a symbol and returns its type and components, or null if invalid/unknown.
|
||||
* v0 symbols (e.g. cUSDT, cUSDC) return type 'v0' with v1Identity from registry.
|
||||
*/
|
||||
export function parseSymbol(s: string): ParsedSymbol | null {
|
||||
if (typeof s !== 'string' || s.length === 0) return null;
|
||||
|
||||
const v0Identity = V0_TO_V1_SYMBOL_MAP[s];
|
||||
if (v0Identity) {
|
||||
return {
|
||||
type: 'v0',
|
||||
iso: v0Identity.iso,
|
||||
typeChar: v0Identity.type,
|
||||
originChain: v0Identity.originChain,
|
||||
v1Identity: v0Identity,
|
||||
};
|
||||
}
|
||||
|
||||
if (s.length === 6 && isValidNativeSymbol(s)) {
|
||||
return {
|
||||
type: 'native',
|
||||
iso: s.slice(2, 5),
|
||||
typeChar: s[5],
|
||||
originChain: s[1],
|
||||
};
|
||||
}
|
||||
|
||||
if (s.length === 7 && isValidBridgedSymbol(s)) {
|
||||
return {
|
||||
type: 'bridged',
|
||||
iso: s.slice(3, 6),
|
||||
typeChar: s[6],
|
||||
originChain: s[2],
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user