@vultisig/rujira 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +254 -0
- package/dist/assets/amount.d.ts +80 -0
- package/dist/assets/amount.d.ts.map +1 -0
- package/dist/assets/amount.js +186 -0
- package/dist/assets/asset.d.ts +43 -0
- package/dist/assets/asset.d.ts.map +1 -0
- package/dist/assets/asset.js +1 -0
- package/dist/assets/formats.d.ts +54 -0
- package/dist/assets/formats.d.ts.map +1 -0
- package/dist/assets/formats.js +164 -0
- package/dist/assets/index.d.ts +27 -0
- package/dist/assets/index.d.ts.map +1 -0
- package/dist/assets/index.js +45 -0
- package/dist/assets/registry.d.ts +37 -0
- package/dist/assets/registry.d.ts.map +1 -0
- package/dist/assets/registry.js +487 -0
- package/dist/assets/router.d.ts +44 -0
- package/dist/assets/router.d.ts.map +1 -0
- package/dist/assets/router.js +142 -0
- package/dist/client.d.ts +70 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +250 -0
- package/dist/config/constants.d.ts +25 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +36 -0
- package/dist/config.d.ts +41 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +72 -0
- package/dist/discovery/discovery.d.ts +39 -0
- package/dist/discovery/discovery.d.ts.map +1 -0
- package/dist/discovery/discovery.js +250 -0
- package/dist/discovery/graphql-client.d.ts +46 -0
- package/dist/discovery/graphql-client.d.ts.map +1 -0
- package/dist/discovery/graphql-client.js +137 -0
- package/dist/discovery/index.d.ts +9 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +7 -0
- package/dist/discovery/types.d.ts +62 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +5 -0
- package/dist/easy-routes.d.ts +216 -0
- package/dist/easy-routes.d.ts.map +1 -0
- package/dist/easy-routes.js +241 -0
- package/dist/errors.d.ts +65 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +184 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/modules/assets.d.ts +68 -0
- package/dist/modules/assets.d.ts.map +1 -0
- package/dist/modules/assets.js +127 -0
- package/dist/modules/deposit.d.ts +152 -0
- package/dist/modules/deposit.d.ts.map +1 -0
- package/dist/modules/deposit.js +233 -0
- package/dist/modules/index.d.ts +12 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +9 -0
- package/dist/modules/orderbook.d.ts +80 -0
- package/dist/modules/orderbook.d.ts.map +1 -0
- package/dist/modules/orderbook.js +320 -0
- package/dist/modules/swap.d.ts +48 -0
- package/dist/modules/swap.d.ts.map +1 -0
- package/dist/modules/swap.js +318 -0
- package/dist/modules/withdraw.d.ts +46 -0
- package/dist/modules/withdraw.d.ts.map +1 -0
- package/dist/modules/withdraw.js +218 -0
- package/dist/services/fee-estimator.d.ts +14 -0
- package/dist/services/fee-estimator.d.ts.map +1 -0
- package/dist/services/fee-estimator.js +89 -0
- package/dist/services/price-impact.d.ts +11 -0
- package/dist/services/price-impact.d.ts.map +1 -0
- package/dist/services/price-impact.js +58 -0
- package/dist/signer/index.d.ts +3 -0
- package/dist/signer/index.d.ts.map +1 -0
- package/dist/signer/index.js +1 -0
- package/dist/signer/keysign-builder.d.ts +21 -0
- package/dist/signer/keysign-builder.d.ts.map +1 -0
- package/dist/signer/keysign-builder.js +106 -0
- package/dist/signer/types.d.ts +81 -0
- package/dist/signer/types.d.ts.map +1 -0
- package/dist/signer/types.js +8 -0
- package/dist/signer/vultisig-provider.d.ts +33 -0
- package/dist/signer/vultisig-provider.d.ts.map +1 -0
- package/dist/signer/vultisig-provider.js +242 -0
- package/dist/types.d.ts +375 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/utils/cache.d.ts +87 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +124 -0
- package/dist/utils/denom-conversion.d.ts +47 -0
- package/dist/utils/denom-conversion.d.ts.map +1 -0
- package/dist/utils/denom-conversion.js +105 -0
- package/dist/utils/encoding.d.ts +17 -0
- package/dist/utils/encoding.d.ts.map +1 -0
- package/dist/utils/encoding.js +55 -0
- package/dist/utils/format.d.ts +108 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +213 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/memo.d.ts +107 -0
- package/dist/utils/memo.d.ts.map +1 -0
- package/dist/utils/memo.js +190 -0
- package/dist/utils/rate-limiter.d.ts +38 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +67 -0
- package/dist/utils/type-guards.d.ts +22 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +27 -0
- package/dist/validation/address-validator.d.ts +15 -0
- package/dist/validation/address-validator.d.ts.map +1 -0
- package/dist/validation/address-validator.js +75 -0
- package/package.json +98 -0
- package/src/__tests__/live/README.md +47 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quote caching utility for reducing RPC calls
|
|
3
|
+
* @module utils/cache
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Cached item with TTL
|
|
7
|
+
*/
|
|
8
|
+
export type CachedItem<T> = {
|
|
9
|
+
value: T;
|
|
10
|
+
expiresAt: number;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Options for QuoteCache
|
|
14
|
+
*/
|
|
15
|
+
export type QuoteCacheOptions = {
|
|
16
|
+
/** Time-to-live in milliseconds (default: 10000 = 10 seconds) */
|
|
17
|
+
ttlMs?: number;
|
|
18
|
+
/** Maximum cache size (default: 100) */
|
|
19
|
+
maxSize?: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Simple TTL cache for swap quotes
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const cache = new QuoteCache({ ttlMs: 10000 });
|
|
27
|
+
*
|
|
28
|
+
* // Store a quote
|
|
29
|
+
* cache.set('BTC.BTC', 'THOR.RUNE', '100000000', quote);
|
|
30
|
+
*
|
|
31
|
+
* // Retrieve if not expired
|
|
32
|
+
* const cached = cache.get('BTC.BTC', 'THOR.RUNE', '100000000');
|
|
33
|
+
* if (cached) {
|
|
34
|
+
* return cached; // Cache hit
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare class QuoteCache<T = unknown> {
|
|
39
|
+
private cache;
|
|
40
|
+
private readonly ttlMs;
|
|
41
|
+
private readonly maxSize;
|
|
42
|
+
constructor(options?: QuoteCacheOptions);
|
|
43
|
+
/**
|
|
44
|
+
* Generate cache key from quote parameters.
|
|
45
|
+
* Slippage is intentionally excluded - callers should compute
|
|
46
|
+
* slippage-dependent values (like minimumOutput) at retrieval time
|
|
47
|
+
* from the cached expectedOutput, not at storage time.
|
|
48
|
+
*/
|
|
49
|
+
private makeKey;
|
|
50
|
+
/**
|
|
51
|
+
* Get cached value if not expired
|
|
52
|
+
*/
|
|
53
|
+
get(fromAsset: string, toAsset: string, amount: string): T | null;
|
|
54
|
+
/**
|
|
55
|
+
* Store value in cache
|
|
56
|
+
*/
|
|
57
|
+
set(fromAsset: string, toAsset: string, amount: string, value: T): void;
|
|
58
|
+
/**
|
|
59
|
+
* Check if cache has valid (non-expired) entry
|
|
60
|
+
*/
|
|
61
|
+
has(fromAsset: string, toAsset: string, amount: string): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Invalidate a specific cache entry
|
|
64
|
+
*/
|
|
65
|
+
invalidate(fromAsset: string, toAsset: string, amount: string): void;
|
|
66
|
+
/**
|
|
67
|
+
* Invalidate all entries for a trading pair
|
|
68
|
+
*/
|
|
69
|
+
invalidatePair(fromAsset: string, toAsset: string): void;
|
|
70
|
+
/**
|
|
71
|
+
* Clear all cached entries
|
|
72
|
+
*/
|
|
73
|
+
clear(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Get cache statistics
|
|
76
|
+
*/
|
|
77
|
+
stats(): {
|
|
78
|
+
size: number;
|
|
79
|
+
maxSize: number;
|
|
80
|
+
ttlMs: number;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Prune expired entries (call periodically for long-running processes)
|
|
84
|
+
*/
|
|
85
|
+
prune(): number;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;IAC1B,KAAK,EAAE,CAAC,CAAA;IACR,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,UAAU,CAAC,CAAC,GAAG,OAAO;IACjC,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;gBAEpB,OAAO,GAAE,iBAAsB;IAK3C;;;;;OAKG;IACH,OAAO,CAAC,OAAO;IAIf;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAiBjE;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAiBvE;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAIhE;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAKpE;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IASxD;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,KAAK,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAQzD;;OAEG;IACH,KAAK,IAAI,MAAM;CAahB"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quote caching utility for reducing RPC calls
|
|
3
|
+
* @module utils/cache
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Simple TTL cache for swap quotes
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const cache = new QuoteCache({ ttlMs: 10000 });
|
|
11
|
+
*
|
|
12
|
+
* // Store a quote
|
|
13
|
+
* cache.set('BTC.BTC', 'THOR.RUNE', '100000000', quote);
|
|
14
|
+
*
|
|
15
|
+
* // Retrieve if not expired
|
|
16
|
+
* const cached = cache.get('BTC.BTC', 'THOR.RUNE', '100000000');
|
|
17
|
+
* if (cached) {
|
|
18
|
+
* return cached; // Cache hit
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class QuoteCache {
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
this.cache = new Map();
|
|
25
|
+
this.ttlMs = options.ttlMs ?? 10000; // 10 seconds default
|
|
26
|
+
this.maxSize = options.maxSize ?? 100;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Generate cache key from quote parameters.
|
|
30
|
+
* Slippage is intentionally excluded - callers should compute
|
|
31
|
+
* slippage-dependent values (like minimumOutput) at retrieval time
|
|
32
|
+
* from the cached expectedOutput, not at storage time.
|
|
33
|
+
*/
|
|
34
|
+
makeKey(fromAsset, toAsset, amount) {
|
|
35
|
+
return `${fromAsset}/${toAsset}/${amount}`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get cached value if not expired
|
|
39
|
+
*/
|
|
40
|
+
get(fromAsset, toAsset, amount) {
|
|
41
|
+
const key = this.makeKey(fromAsset, toAsset, amount);
|
|
42
|
+
const cached = this.cache.get(key);
|
|
43
|
+
if (!cached) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
// Check expiry
|
|
47
|
+
if (Date.now() > cached.expiresAt) {
|
|
48
|
+
this.cache.delete(key);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
return cached.value;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Store value in cache
|
|
55
|
+
*/
|
|
56
|
+
set(fromAsset, toAsset, amount, value) {
|
|
57
|
+
const key = this.makeKey(fromAsset, toAsset, amount);
|
|
58
|
+
// Enforce max size (LRU-style: remove oldest entries)
|
|
59
|
+
if (this.cache.size >= this.maxSize) {
|
|
60
|
+
const firstKey = this.cache.keys().next().value;
|
|
61
|
+
if (firstKey) {
|
|
62
|
+
this.cache.delete(firstKey);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
this.cache.set(key, {
|
|
66
|
+
value,
|
|
67
|
+
expiresAt: Date.now() + this.ttlMs,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Check if cache has valid (non-expired) entry
|
|
72
|
+
*/
|
|
73
|
+
has(fromAsset, toAsset, amount) {
|
|
74
|
+
return this.get(fromAsset, toAsset, amount) !== null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Invalidate a specific cache entry
|
|
78
|
+
*/
|
|
79
|
+
invalidate(fromAsset, toAsset, amount) {
|
|
80
|
+
const key = this.makeKey(fromAsset, toAsset, amount);
|
|
81
|
+
this.cache.delete(key);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Invalidate all entries for a trading pair
|
|
85
|
+
*/
|
|
86
|
+
invalidatePair(fromAsset, toAsset) {
|
|
87
|
+
const prefix = `${fromAsset}/${toAsset}/`;
|
|
88
|
+
for (const key of this.cache.keys()) {
|
|
89
|
+
if (key.startsWith(prefix)) {
|
|
90
|
+
this.cache.delete(key);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Clear all cached entries
|
|
96
|
+
*/
|
|
97
|
+
clear() {
|
|
98
|
+
this.cache.clear();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get cache statistics
|
|
102
|
+
*/
|
|
103
|
+
stats() {
|
|
104
|
+
return {
|
|
105
|
+
size: this.cache.size,
|
|
106
|
+
maxSize: this.maxSize,
|
|
107
|
+
ttlMs: this.ttlMs,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Prune expired entries (call periodically for long-running processes)
|
|
112
|
+
*/
|
|
113
|
+
prune() {
|
|
114
|
+
const now = Date.now();
|
|
115
|
+
let pruned = 0;
|
|
116
|
+
for (const [key, item] of this.cache.entries()) {
|
|
117
|
+
if (now > item.expiresAt) {
|
|
118
|
+
this.cache.delete(key);
|
|
119
|
+
pruned++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return pruned;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical denom-to-ticker and denom-to-asset conversion
|
|
3
|
+
* @module utils/denom-conversion
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Convert a denom (any format) to a short ticker for display.
|
|
7
|
+
*
|
|
8
|
+
* Resolution order:
|
|
9
|
+
* 1. Look up via findAssetByFormat (handles thorchain, fin, l1 formats)
|
|
10
|
+
* 2. Iterate KNOWN_ASSETS checking fin format (catches cases where denom is a raw fin string)
|
|
11
|
+
* 3. Parse denom string (chain-symbol → SYMBOL)
|
|
12
|
+
*
|
|
13
|
+
* @param denom - Denom string in any format
|
|
14
|
+
* @returns Short ticker (e.g., "BTC", "USDC", "RUNE")
|
|
15
|
+
*/
|
|
16
|
+
export declare function denomToTicker(denom: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Convert a denom to a THORChain asset identifier (e.g., "BTC.BTC").
|
|
19
|
+
*
|
|
20
|
+
* Resolution order:
|
|
21
|
+
* 1. Look up via findAssetByFormat → return thorchain format
|
|
22
|
+
* 2. Reverse-engineer from denom format (chain-symbol → CHAIN.SYMBOL)
|
|
23
|
+
*
|
|
24
|
+
* @param denom - Denom string in any format
|
|
25
|
+
* @returns THORChain asset string or null if unresolvable
|
|
26
|
+
*/
|
|
27
|
+
export declare function denomToAsset(denom: string): string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Extract a display symbol from an asset string or denom.
|
|
30
|
+
*
|
|
31
|
+
* @param assetOrDenom - Asset string (e.g., "ETH.USDC-0X...") or denom
|
|
32
|
+
* @returns Symbol (e.g., "USDC")
|
|
33
|
+
*/
|
|
34
|
+
export declare function extractSymbol(assetOrDenom: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Parse a THORChain asset string into its components.
|
|
37
|
+
*
|
|
38
|
+
* @param asset - Asset string (e.g., "ETH.USDC-0XA0B86991...")
|
|
39
|
+
* @returns Parsed components
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseAsset(asset: string): {
|
|
42
|
+
chain: string;
|
|
43
|
+
symbol: string;
|
|
44
|
+
ticker: string;
|
|
45
|
+
contractAddress?: string;
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=denom-conversion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"denom-conversion.d.ts","sourceRoot":"","sources":["../../src/utils/denom-conversion.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAqBnD;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBzD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAkB1D;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG;IACzC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAcA"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical denom-to-ticker and denom-to-asset conversion
|
|
3
|
+
* @module utils/denom-conversion
|
|
4
|
+
*/
|
|
5
|
+
import { findAssetByFormat, KNOWN_ASSETS } from '../assets/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Convert a denom (any format) to a short ticker for display.
|
|
8
|
+
*
|
|
9
|
+
* Resolution order:
|
|
10
|
+
* 1. Look up via findAssetByFormat (handles thorchain, fin, l1 formats)
|
|
11
|
+
* 2. Iterate KNOWN_ASSETS checking fin format (catches cases where denom is a raw fin string)
|
|
12
|
+
* 3. Parse denom string (chain-symbol → SYMBOL)
|
|
13
|
+
*
|
|
14
|
+
* @param denom - Denom string in any format
|
|
15
|
+
* @returns Short ticker (e.g., "BTC", "USDC", "RUNE")
|
|
16
|
+
*/
|
|
17
|
+
export function denomToTicker(denom) {
|
|
18
|
+
// 1. Try findAssetByFormat (handles all known formats)
|
|
19
|
+
const asset = findAssetByFormat(denom);
|
|
20
|
+
if (asset) {
|
|
21
|
+
return asset.id.toUpperCase();
|
|
22
|
+
}
|
|
23
|
+
// 2. Try matching fin format directly against known assets
|
|
24
|
+
for (const knownAsset of Object.values(KNOWN_ASSETS)) {
|
|
25
|
+
if (knownAsset.formats.fin === denom) {
|
|
26
|
+
return knownAsset.name.split(' ')[0].toUpperCase();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// 3. Parse denom string
|
|
30
|
+
const parts = denom.split('-');
|
|
31
|
+
if (parts.length >= 2) {
|
|
32
|
+
return (parts[1] || '').toUpperCase();
|
|
33
|
+
}
|
|
34
|
+
return denom.toUpperCase();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Convert a denom to a THORChain asset identifier (e.g., "BTC.BTC").
|
|
38
|
+
*
|
|
39
|
+
* Resolution order:
|
|
40
|
+
* 1. Look up via findAssetByFormat → return thorchain format
|
|
41
|
+
* 2. Reverse-engineer from denom format (chain-symbol → CHAIN.SYMBOL)
|
|
42
|
+
*
|
|
43
|
+
* @param denom - Denom string in any format
|
|
44
|
+
* @returns THORChain asset string or null if unresolvable
|
|
45
|
+
*/
|
|
46
|
+
export function denomToAsset(denom) {
|
|
47
|
+
// 1. Look up in asset registry
|
|
48
|
+
const asset = findAssetByFormat(denom);
|
|
49
|
+
if (asset) {
|
|
50
|
+
return asset.formats.thorchain;
|
|
51
|
+
}
|
|
52
|
+
// 2. Reverse-engineer from denom format: btc-btc -> BTC.BTC
|
|
53
|
+
if (denom.includes('-')) {
|
|
54
|
+
const parts = denom.split('-');
|
|
55
|
+
if (parts.length >= 2) {
|
|
56
|
+
const chain = (parts[0] || '').toUpperCase();
|
|
57
|
+
const symbol = parts.slice(1).join('-').toUpperCase();
|
|
58
|
+
return `${chain}.${symbol}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Extract a display symbol from an asset string or denom.
|
|
65
|
+
*
|
|
66
|
+
* @param assetOrDenom - Asset string (e.g., "ETH.USDC-0X...") or denom
|
|
67
|
+
* @returns Symbol (e.g., "USDC")
|
|
68
|
+
*/
|
|
69
|
+
export function extractSymbol(assetOrDenom) {
|
|
70
|
+
// Handle full asset format: ETH.USDC-0X... -> USDC
|
|
71
|
+
if (assetOrDenom.includes('.')) {
|
|
72
|
+
const afterDot = assetOrDenom.split('.')[1] || '';
|
|
73
|
+
const symbol = afterDot.split('-')[0] || '';
|
|
74
|
+
return symbol.toUpperCase();
|
|
75
|
+
}
|
|
76
|
+
// Handle denom format: eth-usdc-0x... -> USDC
|
|
77
|
+
if (assetOrDenom.includes('-')) {
|
|
78
|
+
const parts = assetOrDenom.split('-');
|
|
79
|
+
if (parts.length >= 2) {
|
|
80
|
+
return (parts[1] || '').toUpperCase();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Simple case: rune -> RUNE
|
|
84
|
+
return assetOrDenom.toUpperCase();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Parse a THORChain asset string into its components.
|
|
88
|
+
*
|
|
89
|
+
* @param asset - Asset string (e.g., "ETH.USDC-0XA0B86991...")
|
|
90
|
+
* @returns Parsed components
|
|
91
|
+
*/
|
|
92
|
+
export function parseAsset(asset) {
|
|
93
|
+
const parts = asset.split('.');
|
|
94
|
+
const chain = (parts[0] || '').toUpperCase();
|
|
95
|
+
const rest = parts.slice(1).join('.') || '';
|
|
96
|
+
const symbolParts = rest.split('-');
|
|
97
|
+
const ticker = symbolParts[0] || '';
|
|
98
|
+
const contractAddress = symbolParts[1];
|
|
99
|
+
return {
|
|
100
|
+
chain,
|
|
101
|
+
symbol: rest,
|
|
102
|
+
ticker,
|
|
103
|
+
contractAddress: contractAddress ? `0x${contractAddress.replace(/^0[xX]/, '')}` : undefined,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform encoding helpers (Node.js + browser)
|
|
3
|
+
* @module utils/encoding
|
|
4
|
+
*/
|
|
5
|
+
/** Encode a UTF-8 string to base64. */
|
|
6
|
+
export declare function base64Encode(input: string): string;
|
|
7
|
+
/** Decode a base64 string to UTF-8. */
|
|
8
|
+
export declare function base64Decode(input: string): string;
|
|
9
|
+
/** Encode a Uint8Array to a hex string (no 0x prefix). */
|
|
10
|
+
export declare function hexEncode(bytes: Uint8Array): string;
|
|
11
|
+
/** Decode a hex string (with or without 0x prefix) to Uint8Array. */
|
|
12
|
+
export declare function hexDecode(hex: string): Uint8Array;
|
|
13
|
+
/** Encode a Uint8Array to base64. */
|
|
14
|
+
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
15
|
+
/** Encode a UTF-8 string to Uint8Array. */
|
|
16
|
+
export declare function stringToBytes(str: string): Uint8Array;
|
|
17
|
+
//# sourceMappingURL=encoding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../src/utils/encoding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,uCAAuC;AACvC,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,uCAAuC;AACvC,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,0DAA0D;AAC1D,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAKnD;AAED,qEAAqE;AACrE,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAajD;AAED,qCAAqC;AACrC,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAKvD;AAED,2CAA2C;AAC3C,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAKrD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform encoding helpers (Node.js + browser)
|
|
3
|
+
* @module utils/encoding
|
|
4
|
+
*/
|
|
5
|
+
const hasBuffer = typeof globalThis.Buffer !== 'undefined';
|
|
6
|
+
/** Encode a UTF-8 string to base64. */
|
|
7
|
+
export function base64Encode(input) {
|
|
8
|
+
if (hasBuffer) {
|
|
9
|
+
return globalThis.Buffer.from(input).toString('base64');
|
|
10
|
+
}
|
|
11
|
+
return btoa(Array.from(new TextEncoder().encode(input), b => String.fromCharCode(b)).join(''));
|
|
12
|
+
}
|
|
13
|
+
/** Decode a base64 string to UTF-8. */
|
|
14
|
+
export function base64Decode(input) {
|
|
15
|
+
if (hasBuffer) {
|
|
16
|
+
return globalThis.Buffer.from(input, 'base64').toString();
|
|
17
|
+
}
|
|
18
|
+
return new TextDecoder().decode(Uint8Array.from(atob(input), c => c.charCodeAt(0)));
|
|
19
|
+
}
|
|
20
|
+
/** Encode a Uint8Array to a hex string (no 0x prefix). */
|
|
21
|
+
export function hexEncode(bytes) {
|
|
22
|
+
if (hasBuffer) {
|
|
23
|
+
return globalThis.Buffer.from(bytes).toString('hex');
|
|
24
|
+
}
|
|
25
|
+
return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
|
|
26
|
+
}
|
|
27
|
+
/** Decode a hex string (with or without 0x prefix) to Uint8Array. */
|
|
28
|
+
export function hexDecode(hex) {
|
|
29
|
+
const clean = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
30
|
+
if (clean.length % 2 !== 0) {
|
|
31
|
+
throw new Error('Hex string must have even length');
|
|
32
|
+
}
|
|
33
|
+
if (!/^[0-9a-fA-F]*$/.test(clean)) {
|
|
34
|
+
throw new Error('Hex string contains non-hex characters');
|
|
35
|
+
}
|
|
36
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
37
|
+
for (let i = 0; i < clean.length; i += 2) {
|
|
38
|
+
bytes[i / 2] = parseInt(clean.slice(i, i + 2), 16);
|
|
39
|
+
}
|
|
40
|
+
return bytes;
|
|
41
|
+
}
|
|
42
|
+
/** Encode a Uint8Array to base64. */
|
|
43
|
+
export function bytesToBase64(bytes) {
|
|
44
|
+
if (hasBuffer) {
|
|
45
|
+
return globalThis.Buffer.from(bytes).toString('base64');
|
|
46
|
+
}
|
|
47
|
+
return btoa(Array.from(bytes, b => String.fromCharCode(b)).join(''));
|
|
48
|
+
}
|
|
49
|
+
/** Encode a UTF-8 string to Uint8Array. */
|
|
50
|
+
export function stringToBytes(str) {
|
|
51
|
+
if (hasBuffer) {
|
|
52
|
+
return new Uint8Array(globalThis.Buffer.from(str));
|
|
53
|
+
}
|
|
54
|
+
return new TextEncoder().encode(str);
|
|
55
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting utilities for Rujira SDK
|
|
3
|
+
* @module utils/format
|
|
4
|
+
*/
|
|
5
|
+
import type { SwapRequest } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Convert human-readable amount to base units
|
|
8
|
+
*
|
|
9
|
+
* @param amount - Human readable amount (e.g., "1.5")
|
|
10
|
+
* @param decimals - Number of decimals
|
|
11
|
+
* @returns Base units as string
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* toBaseUnits("1.5", 8); // "150000000"
|
|
16
|
+
* toBaseUnits("0.001", 18); // "1000000000000000"
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function toBaseUnits(amount: string | number, decimals: number): string;
|
|
20
|
+
/**
|
|
21
|
+
* Convert base units to human-readable amount
|
|
22
|
+
*
|
|
23
|
+
* @param baseUnits - Amount in base units
|
|
24
|
+
* @param decimals - Number of decimals
|
|
25
|
+
* @returns Human readable amount
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* fromBaseUnits("150000000", 8); // "1.5"
|
|
30
|
+
* fromBaseUnits("1000000000000000", 18); // "0.001"
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function fromBaseUnits(baseUnits: string | bigint, decimals: number): string;
|
|
34
|
+
/**
|
|
35
|
+
* Format amount for display (truncates fractional digits).
|
|
36
|
+
* For fee displays where underestimation is harmful, use {@link formatFee} instead.
|
|
37
|
+
*
|
|
38
|
+
* @param baseUnits - Amount in base units
|
|
39
|
+
* @param asset - Asset identifier (any format recognized by the asset registry)
|
|
40
|
+
* @param maxDecimals - Maximum decimal places to show
|
|
41
|
+
*/
|
|
42
|
+
export declare function formatAmount(baseUnits: string | bigint, asset: string, maxDecimals?: number): string;
|
|
43
|
+
/**
|
|
44
|
+
* Format fee amount for display (rounds UP to avoid underestimating costs).
|
|
45
|
+
* Use this for fee/gas displays where showing less than actual is misleading.
|
|
46
|
+
*
|
|
47
|
+
* @param baseUnits - Amount in base units
|
|
48
|
+
* @param asset - Asset identifier (any format recognized by the asset registry)
|
|
49
|
+
* @param maxDecimals - Maximum decimal places to show
|
|
50
|
+
*/
|
|
51
|
+
export declare function formatFee(baseUnits: string | bigint, asset: string, maxDecimals?: number): string;
|
|
52
|
+
/**
|
|
53
|
+
* Calculate minimum return after slippage
|
|
54
|
+
*
|
|
55
|
+
* @param expectedOutput - Expected output in base units
|
|
56
|
+
* @param slippageBps - Slippage tolerance in basis points
|
|
57
|
+
* @returns Minimum acceptable output
|
|
58
|
+
*/
|
|
59
|
+
export declare function calculateMinReturn(expectedOutput: string | bigint, slippageBps: number): string;
|
|
60
|
+
/**
|
|
61
|
+
* Calculate slippage percentage from expected vs actual
|
|
62
|
+
*
|
|
63
|
+
* @param expected - Expected amount
|
|
64
|
+
* @param actual - Actual amount received
|
|
65
|
+
* @returns Slippage percentage (negative if worse than expected)
|
|
66
|
+
*/
|
|
67
|
+
export declare function calculateSlippage(expected: string | bigint, actual: string | bigint): string;
|
|
68
|
+
/**
|
|
69
|
+
* Generate a unique quote ID using cryptographic randomness.
|
|
70
|
+
*/
|
|
71
|
+
export declare function generateQuoteId(): string;
|
|
72
|
+
/**
|
|
73
|
+
* Build a swap message from parameters
|
|
74
|
+
*
|
|
75
|
+
* @param minReturn - Minimum return amount
|
|
76
|
+
* @param to - Destination address (optional)
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildSwapMsg(minReturn: string, to?: string): {
|
|
79
|
+
swap: SwapRequest;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Truncate string in the middle (for addresses)
|
|
83
|
+
*
|
|
84
|
+
* @param str - String to truncate
|
|
85
|
+
* @param startChars - Characters to show at start
|
|
86
|
+
* @param endChars - Characters to show at end
|
|
87
|
+
*/
|
|
88
|
+
export declare function truncateMiddle(str: string, startChars?: number, endChars?: number): string;
|
|
89
|
+
/**
|
|
90
|
+
* Format percentage for display
|
|
91
|
+
*
|
|
92
|
+
* @param value - Decimal value (e.g., 0.015 for 1.5%)
|
|
93
|
+
* @param decimals - Decimal places to show
|
|
94
|
+
*/
|
|
95
|
+
export declare function formatPercentage(value: number | string, decimals?: number): string;
|
|
96
|
+
/**
|
|
97
|
+
* Format basis points as percentage
|
|
98
|
+
*
|
|
99
|
+
* @param bps - Basis points
|
|
100
|
+
*/
|
|
101
|
+
export declare function bpsToPercent(bps: number): string;
|
|
102
|
+
/**
|
|
103
|
+
* Convert percentage to basis points
|
|
104
|
+
*
|
|
105
|
+
* @param percent - Percentage (e.g., 1.5 for 1.5%)
|
|
106
|
+
*/
|
|
107
|
+
export declare function percentToBps(percent: number): number;
|
|
108
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAW7E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOlF;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,SAAI,GAAG,MAAM,CAkB/F;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,SAAI,GAAG,MAAM,CA0C5F;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAI/F;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAU5F;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAUxC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CASlF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,SAAI,EAAE,QAAQ,SAAI,GAAG,MAAM,CAKhF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM,CAG7E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD"}
|