@tcswap/helpers 4.5.15

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.
Files changed (139) hide show
  1. package/dist/api/index.cjs +4 -0
  2. package/dist/api/index.cjs.map +16 -0
  3. package/dist/api/index.js +4 -0
  4. package/dist/api/index.js.map +16 -0
  5. package/dist/chunk-pfmeq01a.js +5 -0
  6. package/dist/chunk-pfmeq01a.js.map +9 -0
  7. package/dist/chunk-vb4wtm2w.js +4 -0
  8. package/dist/chunk-vb4wtm2w.js.map +9 -0
  9. package/dist/contracts.cjs +4 -0
  10. package/dist/contracts.cjs.map +10 -0
  11. package/dist/contracts.js +4 -0
  12. package/dist/contracts.js.map +10 -0
  13. package/dist/index.cjs +7 -0
  14. package/dist/index.cjs.map +30 -0
  15. package/dist/index.js +7 -0
  16. package/dist/index.js.map +30 -0
  17. package/dist/tokens.cjs +4 -0
  18. package/dist/tokens.cjs.map +10 -0
  19. package/dist/tokens.js +4 -0
  20. package/dist/tokens.js.map +10 -0
  21. package/dist/types/api/index.d.ts +502 -0
  22. package/dist/types/api/index.d.ts.map +1 -0
  23. package/dist/types/api/memoless/endpoints.d.ts +56 -0
  24. package/dist/types/api/memoless/endpoints.d.ts.map +1 -0
  25. package/dist/types/api/memoless/types.d.ts +85 -0
  26. package/dist/types/api/memoless/types.d.ts.map +1 -0
  27. package/dist/types/api/midgard/endpoints.d.ts +80 -0
  28. package/dist/types/api/midgard/endpoints.d.ts.map +1 -0
  29. package/dist/types/api/midgard/types.d.ts +543 -0
  30. package/dist/types/api/midgard/types.d.ts.map +1 -0
  31. package/dist/types/api/thornode/endpoints.d.ts +34 -0
  32. package/dist/types/api/thornode/endpoints.d.ts.map +1 -0
  33. package/dist/types/api/thornode/types.d.ts +264 -0
  34. package/dist/types/api/thornode/types.d.ts.map +1 -0
  35. package/dist/types/api/uswap/endpoints.d.ts +372 -0
  36. package/dist/types/api/uswap/endpoints.d.ts.map +1 -0
  37. package/dist/types/api/uswap/types.d.ts +1487 -0
  38. package/dist/types/api/uswap/types.d.ts.map +1 -0
  39. package/dist/types/contracts.d.ts +2 -0
  40. package/dist/types/contracts.d.ts.map +1 -0
  41. package/dist/types/index.d.ts +32 -0
  42. package/dist/types/index.d.ts.map +1 -0
  43. package/dist/types/modules/assetValue.d.ts +82 -0
  44. package/dist/types/modules/assetValue.d.ts.map +1 -0
  45. package/dist/types/modules/bigIntArithmetics.d.ts +60 -0
  46. package/dist/types/modules/bigIntArithmetics.d.ts.map +1 -0
  47. package/dist/types/modules/feeMultiplier.d.ts +48 -0
  48. package/dist/types/modules/feeMultiplier.d.ts.map +1 -0
  49. package/dist/types/modules/requestClient.d.ts +33 -0
  50. package/dist/types/modules/requestClient.d.ts.map +1 -0
  51. package/dist/types/modules/uSwapConfig.d.ts +249 -0
  52. package/dist/types/modules/uSwapConfig.d.ts.map +1 -0
  53. package/dist/types/modules/uSwapError.d.ts +879 -0
  54. package/dist/types/modules/uSwapError.d.ts.map +1 -0
  55. package/dist/types/modules/uSwapNumber.d.ts +10 -0
  56. package/dist/types/modules/uSwapNumber.d.ts.map +1 -0
  57. package/dist/types/tokens.d.ts +2 -0
  58. package/dist/types/tokens.d.ts.map +1 -0
  59. package/dist/types/types/commonTypes.d.ts +16 -0
  60. package/dist/types/types/commonTypes.d.ts.map +1 -0
  61. package/dist/types/types/derivationPath.d.ts +4 -0
  62. package/dist/types/types/derivationPath.d.ts.map +1 -0
  63. package/dist/types/types/errors/apiV1.d.ts +2 -0
  64. package/dist/types/types/errors/apiV1.d.ts.map +1 -0
  65. package/dist/types/types/index.d.ts +6 -0
  66. package/dist/types/types/index.d.ts.map +1 -0
  67. package/dist/types/types/quotes.d.ts +180 -0
  68. package/dist/types/types/quotes.d.ts.map +1 -0
  69. package/dist/types/types/sdk.d.ts +35 -0
  70. package/dist/types/types/sdk.d.ts.map +1 -0
  71. package/dist/types/types/wallet.d.ts +130 -0
  72. package/dist/types/types/wallet.d.ts.map +1 -0
  73. package/dist/types/utils/asset.d.ts +37 -0
  74. package/dist/types/utils/asset.d.ts.map +1 -0
  75. package/dist/types/utils/chains.d.ts +13 -0
  76. package/dist/types/utils/chains.d.ts.map +1 -0
  77. package/dist/types/utils/derivationPath.d.ts +21 -0
  78. package/dist/types/utils/derivationPath.d.ts.map +1 -0
  79. package/dist/types/utils/explorerUrls.d.ts +10 -0
  80. package/dist/types/utils/explorerUrls.d.ts.map +1 -0
  81. package/dist/types/utils/liquidity.d.ts +62 -0
  82. package/dist/types/utils/liquidity.d.ts.map +1 -0
  83. package/dist/types/utils/memo.d.ts +65 -0
  84. package/dist/types/utils/memo.d.ts.map +1 -0
  85. package/dist/types/utils/others.d.ts +15 -0
  86. package/dist/types/utils/others.d.ts.map +1 -0
  87. package/dist/types/utils/validators.d.ts +6 -0
  88. package/dist/types/utils/validators.d.ts.map +1 -0
  89. package/dist/types/utils/wallets.d.ts +36 -0
  90. package/dist/types/utils/wallets.d.ts.map +1 -0
  91. package/package.json +67 -0
  92. package/src/api/index.ts +15 -0
  93. package/src/api/memoless/endpoints.ts +62 -0
  94. package/src/api/memoless/types.ts +83 -0
  95. package/src/api/midgard/endpoints.ts +352 -0
  96. package/src/api/midgard/types.ts +515 -0
  97. package/src/api/thornode/endpoints.ts +109 -0
  98. package/src/api/thornode/types.ts +247 -0
  99. package/src/api/uswap/endpoints.ts +252 -0
  100. package/src/api/uswap/types.ts +626 -0
  101. package/src/contracts.ts +1 -0
  102. package/src/index.ts +32 -0
  103. package/src/modules/__tests__/assetValue.test.ts +2452 -0
  104. package/src/modules/__tests__/bigIntArithmetics.test.ts +410 -0
  105. package/src/modules/__tests__/feeMultiplier.test.ts +131 -0
  106. package/src/modules/__tests__/uSwapConfig.test.ts +429 -0
  107. package/src/modules/__tests__/uSwapNumber.test.ts +439 -0
  108. package/src/modules/assetValue.ts +536 -0
  109. package/src/modules/bigIntArithmetics.ts +366 -0
  110. package/src/modules/feeMultiplier.ts +84 -0
  111. package/src/modules/requestClient.ts +116 -0
  112. package/src/modules/uSwapConfig.ts +189 -0
  113. package/src/modules/uSwapError.ts +474 -0
  114. package/src/modules/uSwapNumber.ts +17 -0
  115. package/src/tokens.ts +1 -0
  116. package/src/types/commonTypes.ts +10 -0
  117. package/src/types/derivationPath.ts +11 -0
  118. package/src/types/errors/apiV1.ts +0 -0
  119. package/src/types/index.ts +5 -0
  120. package/src/types/quotes.ts +182 -0
  121. package/src/types/sdk.ts +38 -0
  122. package/src/types/wallet.ts +124 -0
  123. package/src/utils/__tests__/asset.test.ts +186 -0
  124. package/src/utils/__tests__/derivationPath.test.ts +142 -0
  125. package/src/utils/__tests__/explorerUrls.test.ts +59 -0
  126. package/src/utils/__tests__/liquidity.test.ts +302 -0
  127. package/src/utils/__tests__/memo.test.ts +99 -0
  128. package/src/utils/__tests__/others.test.ts +169 -0
  129. package/src/utils/__tests__/validators.test.ts +84 -0
  130. package/src/utils/__tests__/wallets.test.ts +625 -0
  131. package/src/utils/asset.ts +399 -0
  132. package/src/utils/chains.ts +104 -0
  133. package/src/utils/derivationPath.ts +101 -0
  134. package/src/utils/explorerUrls.ts +32 -0
  135. package/src/utils/liquidity.ts +154 -0
  136. package/src/utils/memo.ts +102 -0
  137. package/src/utils/others.ts +64 -0
  138. package/src/utils/validators.ts +36 -0
  139. package/src/utils/wallets.ts +238 -0
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Modifications © 2025 Horizontal Systems.
3
+ */
4
+
5
+ import { Chain, getChainConfig } from "@tcswap/types";
6
+ import { USwapNumber } from "../modules/uSwapNumber";
7
+
8
+ type ShareParams<T extends {}> = T & { liquidityUnits: string; poolUnits: string };
9
+
10
+ type PoolParams = { runeAmount: string; assetAmount: string; runeDepth: string; assetDepth: string };
11
+
12
+ /**
13
+ * Ref: https://gitlab.com/thorchain/thornode/-/issues/657
14
+ * share = (s * A * (2 * T^2 - 2 * T * s + s^2))/T^3
15
+ * s = stakeUnits for member (after factoring in withdrawBasisPoints)
16
+ * T = totalPoolUnits for pool
17
+ * A = assetDepth to be withdrawn
18
+ *
19
+ * Formula:
20
+ * share = (s * A * (2 * T^2 - 2 * T * s + s^2))/T^3
21
+ * (part1 * (part2 - part3 + part4)) / part5
22
+ */
23
+ export function getAsymmetricRuneShare({ liquidityUnits, poolUnits, runeDepth }: ShareParams<{ runeDepth: string }>) {
24
+ const s = toTCUSwapNumber(liquidityUnits);
25
+ const T = toTCUSwapNumber(poolUnits);
26
+ const A = toTCUSwapNumber(runeDepth);
27
+
28
+ const part1 = s.mul(A);
29
+ const part2 = T.mul(T).mul(2);
30
+ const part3 = T.mul(s).mul(2);
31
+ const part4 = s.mul(s);
32
+ const part5 = T.mul(T).mul(T);
33
+
34
+ const numerator = part1.mul(part2.sub(part3).add(part4));
35
+
36
+ return numerator.div(part5);
37
+ }
38
+
39
+ export function getAsymmetricAssetShare({
40
+ liquidityUnits,
41
+ poolUnits,
42
+ assetDepth,
43
+ }: ShareParams<{ assetDepth: string }>) {
44
+ const s = toTCUSwapNumber(liquidityUnits);
45
+ const T = toTCUSwapNumber(poolUnits);
46
+ const A = toTCUSwapNumber(assetDepth);
47
+
48
+ const part1 = s.mul(A);
49
+ const part2 = T.mul(T).mul(2);
50
+ const part3 = T.mul(s).mul(2);
51
+ const part4 = s.mul(s);
52
+ const numerator = part1.mul(part2.sub(part3).add(part4));
53
+ const part5 = T.mul(T).mul(T);
54
+
55
+ return numerator.div(part5);
56
+ }
57
+
58
+ export function getAsymmetricRuneWithdrawAmount({
59
+ percent,
60
+ runeDepth,
61
+ liquidityUnits,
62
+ poolUnits,
63
+ }: ShareParams<{ percent: number; runeDepth: string }>) {
64
+ return getAsymmetricRuneShare({ liquidityUnits, poolUnits, runeDepth }).mul(percent);
65
+ }
66
+
67
+ export function getAsymmetricAssetWithdrawAmount({
68
+ percent,
69
+ assetDepth,
70
+ liquidityUnits,
71
+ poolUnits,
72
+ }: ShareParams<{ percent: number; assetDepth: string }>) {
73
+ return getAsymmetricAssetShare({ assetDepth, liquidityUnits, poolUnits }).mul(percent);
74
+ }
75
+
76
+ function toTCUSwapNumber(value: string) {
77
+ return USwapNumber.fromBigInt(BigInt(value), getChainConfig(Chain.THORChain).baseDecimal);
78
+ }
79
+
80
+ export function getSymmetricPoolShare({
81
+ liquidityUnits,
82
+ poolUnits,
83
+ runeDepth,
84
+ assetDepth,
85
+ }: ShareParams<{ runeDepth: string; assetDepth: string }>) {
86
+ return {
87
+ assetAmount: toTCUSwapNumber(assetDepth).mul(liquidityUnits).div(poolUnits),
88
+ runeAmount: toTCUSwapNumber(runeDepth).mul(liquidityUnits).div(poolUnits),
89
+ };
90
+ }
91
+
92
+ export function getSymmetricWithdraw({
93
+ liquidityUnits,
94
+ poolUnits,
95
+ runeDepth,
96
+ assetDepth,
97
+ percent,
98
+ }: ShareParams<{ runeDepth: string; assetDepth: string; percent: number }>) {
99
+ return Object.fromEntries(
100
+ Object.entries(getSymmetricPoolShare({ assetDepth, liquidityUnits, poolUnits, runeDepth })).map(([name, value]) => [
101
+ name,
102
+ value.mul(percent),
103
+ ]),
104
+ );
105
+ }
106
+
107
+ export function getEstimatedPoolShare({
108
+ runeDepth,
109
+ poolUnits,
110
+ assetDepth,
111
+ liquidityUnits,
112
+ runeAmount,
113
+ assetAmount,
114
+ }: ShareParams<{ runeAmount: string; assetAmount: string; runeDepth: string; assetDepth: string }>) {
115
+ const R = new USwapNumber({ decimal: 8, value: runeDepth });
116
+ const A = new USwapNumber({ decimal: 8, value: assetDepth });
117
+ const P = new USwapNumber({ decimal: 8, value: poolUnits });
118
+ const runeAddAmount = new USwapNumber({ decimal: 8, value: runeAmount });
119
+ const assetAddAmount = new USwapNumber({ decimal: 8, value: assetAmount });
120
+
121
+ // liquidityUnits = P * (r*A + a*R + 2*r*a) / (r*A + a*R + 2*R*A)
122
+ const rA = runeAddAmount.mul(A);
123
+ const aR = assetAddAmount.mul(R);
124
+ const ra = runeAddAmount.mul(assetAddAmount);
125
+ const RA = R.mul(A);
126
+ const numerator = P.mul(rA.add(aR.add(ra.mul(2))));
127
+ const denominator = rA.add(aR.add(RA.mul(2)));
128
+ const liquidityUnitsAfterAdd = numerator.div(denominator);
129
+ const estimatedLiquidityUnits = toTCUSwapNumber(liquidityUnits).add(liquidityUnitsAfterAdd);
130
+
131
+ if (liquidityUnitsAfterAdd.getBaseValue("number") === 0) {
132
+ return estimatedLiquidityUnits.div(P).getBaseValue("number");
133
+ }
134
+
135
+ // get pool units after add
136
+ const newPoolUnits = P.add(estimatedLiquidityUnits);
137
+
138
+ return estimatedLiquidityUnits.div(newPoolUnits).getBaseValue("number");
139
+ }
140
+
141
+ export function getLiquiditySlippage({ runeAmount, assetAmount, runeDepth, assetDepth }: PoolParams) {
142
+ if (runeAmount === "0" || assetAmount === "0" || runeDepth === "0" || assetDepth === "0") return 0;
143
+ // formula: (t * R - T * r)/ (T*r + R*T)
144
+ const R = toTCUSwapNumber(runeDepth);
145
+ const T = toTCUSwapNumber(assetDepth);
146
+ const assetAddAmount = toTCUSwapNumber(assetAmount);
147
+ const runeAddAmount = toTCUSwapNumber(runeAmount);
148
+
149
+ const numerator = assetAddAmount.mul(R).sub(T.mul(runeAddAmount));
150
+ const denominator = T.mul(runeAddAmount).add(R.mul(T));
151
+
152
+ // set absolute value of percent, no negative allowed
153
+ return Math.abs(numerator.div(denominator).getBaseValue("number"));
154
+ }
@@ -0,0 +1,102 @@
1
+ import { Chain } from "@tcswap/types";
2
+ import { match } from "ts-pattern";
3
+ import { MemoType } from "../types/sdk";
4
+
5
+ export function getMemoForLeaveAndBond({ type, address }: BondOrLeaveParams) {
6
+ return `${type}:${address}`;
7
+ }
8
+
9
+ export function getMemoForUnbond({ address, unbondAmount }: UnbondParams) {
10
+ return `${MemoType.UNBOND}:${address}:${unbondAmount}`;
11
+ }
12
+
13
+ /**
14
+ * Deposit
15
+ */
16
+ export function getMemoForRunePoolDeposit(affiliate?: WithAffiliate<{}>) {
17
+ return addAffiliate(MemoType.RUNEPOOL_DEPOSIT, affiliate);
18
+ }
19
+
20
+ export function getMemoForDeposit({
21
+ chain,
22
+ symbol,
23
+ address,
24
+ ...affiliate
25
+ }: WithAffiliate<{ chain: Chain; symbol: string; address?: string }>) {
26
+ const poolIdentifier = getPoolIdentifier({ chain, symbol });
27
+ const addressPart = address ? `:${address}:` : ":";
28
+
29
+ return addAffiliate(`${MemoType.DEPOSIT}:${poolIdentifier}${addressPart}`, affiliate);
30
+ }
31
+
32
+ /**
33
+ * Withdraw
34
+ */
35
+ export function getMemoForWithdraw({ chain, symbol, ticker, basisPoints, targetAsset }: WithdrawParams) {
36
+ const shortenedSymbol = chain === "ETH" && ticker !== "ETH" ? `${ticker}-${symbol.slice(-3)}` : symbol;
37
+ const targetPart = targetAsset ? `:${targetAsset}` : "";
38
+
39
+ return `${MemoType.WITHDRAW}:${chain}.${shortenedSymbol}:${basisPoints}${targetPart}`;
40
+ }
41
+
42
+ export function getMemoForRunePoolWithdraw({ basisPoints, ...affiliate }: WithAffiliate<{ basisPoints: number }>) {
43
+ return addAffiliate(`${MemoType.RUNEPOOL_WITHDRAW}:${basisPoints}`, affiliate);
44
+ }
45
+
46
+ /**
47
+ * TNS
48
+ */
49
+ export function getMemoForNameRegister({ name, chain, address, owner }: NameRegisterParams) {
50
+ const baseMemo = `${MemoType.NAME_REGISTER}:${name}:${chain}:${address}`;
51
+ const ownerAssignmentOrChangePart = owner ? `:${owner}` : "";
52
+
53
+ return `${baseMemo}${ownerAssignmentOrChangePart}`;
54
+ }
55
+
56
+ export function getMemoForNamePreferredAssetRegister({
57
+ name,
58
+ chain,
59
+ asset,
60
+ payout,
61
+ owner,
62
+ }: PreferredAssetRegisterParams) {
63
+ return `${MemoType.NAME_REGISTER}:${name}:${chain}:${payout}:${owner}:${asset}`;
64
+ }
65
+
66
+ export function getMemoForTcyClaim(memoType: MemoType.CLAIM_TCY, { address }: WithAffiliate<{ address: string }>) {
67
+ return `${memoType}:${address}`;
68
+ }
69
+
70
+ export function getMemoForTcyStake(
71
+ memoType: MemoType.STAKE_TCY | MemoType.UNSTAKE_TCY,
72
+ { unstakeBps, ...affiliate }: WithAffiliate<{ unstakeBps?: number }>,
73
+ ) {
74
+ const bps = unstakeBps ? `:${unstakeBps}` : "";
75
+ const baseMemo = `${memoType}${bps}`;
76
+
77
+ return addAffiliate(`${baseMemo}`, affiliate);
78
+ }
79
+
80
+ /**
81
+ * Internal helpers
82
+ */
83
+ function addAffiliate(memo: string, { affiliateAddress, affiliateBasisPoints }: WithAffiliate<{}> = {}) {
84
+ const affiliatedMemo = `${memo}${affiliateAddress ? `:${affiliateAddress}:${affiliateBasisPoints || 0}` : ""}`;
85
+
86
+ return affiliatedMemo.endsWith(":") ? affiliatedMemo.slice(0, -1) : affiliatedMemo;
87
+ }
88
+
89
+ function getPoolIdentifier({ chain, symbol }: { chain: Chain; symbol: string }) {
90
+ return match(chain)
91
+ .with(Chain.Bitcoin, Chain.Dogecoin, Chain.Litecoin, () => chain.slice(0, 1).toLowerCase())
92
+ .with(Chain.BitcoinCash, () => "c")
93
+ .otherwise(() => `${chain}.${symbol}`);
94
+ }
95
+
96
+ type WithAffiliate<T extends {}> = T & { affiliateAddress?: string; affiliateBasisPoints?: number };
97
+
98
+ type BondOrLeaveParams = { type: MemoType.BOND | MemoType.LEAVE; address: string };
99
+ type UnbondParams = { address: string; unbondAmount: number };
100
+ type NameRegisterParams = { name: string; chain: string; address: string; owner?: string };
101
+ type PreferredAssetRegisterParams = { name: string; chain: Chain; asset: string; payout: string; owner: string };
102
+ type WithdrawParams = { chain: Chain; symbol: string; ticker: string; basisPoints: number; targetAsset?: string };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Modifications © 2025 Horizontal Systems.
3
+ */
4
+
5
+ import { Chain } from "@tcswap/types";
6
+ import { type ErrorKeys, USwapError } from "../modules/uSwapError";
7
+
8
+ // 10 rune for register, 1 rune per year
9
+ // MINIMUM_REGISTRATION_FEE = 11
10
+ export function getTHORNameCost(numberOfYears: number) {
11
+ if (numberOfYears < 0) throw new USwapError({ errorKey: "helpers_invalid_number_of_years", info: { numberOfYears } });
12
+ return 10 + numberOfYears;
13
+ }
14
+
15
+ // 10 CACAO for register
16
+ // 1.0512 CACAO per year
17
+ export function getMAYANameCost(numberOfYears: number) {
18
+ if (numberOfYears < 0) throw new USwapError({ errorKey: "helpers_invalid_number_of_years", info: { numberOfYears } });
19
+ // round to max 10 decimals
20
+ return Math.round((10 + numberOfYears * 1.0512) * 1e10) / 1e10;
21
+ }
22
+
23
+ export function wrapWithThrow<T>(fn: () => T, errorKey?: ErrorKeys) {
24
+ try {
25
+ return fn();
26
+ } catch (error) {
27
+ if (errorKey) {
28
+ throw new USwapError(errorKey, error);
29
+ }
30
+
31
+ return;
32
+ }
33
+ }
34
+
35
+ export function getChainIdentifier<T extends Chain>(chain: T) {
36
+ switch (chain) {
37
+ case Chain.THORChain:
38
+ return `${chain}.RUNE`;
39
+
40
+ case Chain.Cosmos:
41
+ return `${chain}.ATOM`;
42
+
43
+ case Chain.BinanceSmartChain:
44
+ return `${chain}`;
45
+
46
+ default:
47
+ return `${chain}.${chain}`;
48
+ }
49
+ }
50
+
51
+ const warnings = new Set();
52
+ export function warnOnce({ condition, id, warning }: { condition: boolean; id: string; warning: string }) {
53
+ if (condition) {
54
+ if (warnings.has(id)) {
55
+ return;
56
+ }
57
+
58
+ if (process.env.NODE_ENV !== "test") {
59
+ console.warn(warning);
60
+ }
61
+
62
+ warnings.add(id);
63
+ }
64
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Modifications © 2025 Horizontal Systems.
3
+ */
4
+
5
+ import type { Chain } from "@tcswap/types";
6
+ import { USwapConfig } from "../modules/uSwapConfig";
7
+ import { USwapError } from "../modules/uSwapError";
8
+
9
+ // Backward compatibility
10
+ const supportedChains = ["TERRA", ...USwapConfig.get("chains")];
11
+
12
+ export function validateIdentifier(identifier = "") {
13
+ const uppercasedIdentifier = identifier.toUpperCase();
14
+
15
+ const [chain] = uppercasedIdentifier.split(".") as [Chain, string];
16
+ if (supportedChains.includes(chain)) return true;
17
+
18
+ const [synthChain] = uppercasedIdentifier.split("/") as [Chain, string];
19
+ if (supportedChains.includes(synthChain)) return true;
20
+
21
+ throw new USwapError({
22
+ errorKey: "helpers_invalid_identifier",
23
+ info: {
24
+ identifier,
25
+ message: `Invalid identifier: ${identifier}. Expected format: <Chain>.<Ticker> or <Chain>.<Ticker>-<ContractAddress>`,
26
+ },
27
+ });
28
+ }
29
+
30
+ export function validateTNS(name: string) {
31
+ if (name.length > 30) return false;
32
+
33
+ const regex = /^[a-zA-Z0-9+_-]+$/g;
34
+
35
+ return !!name.match(regex);
36
+ }
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Modifications © 2025 Horizontal Systems.
3
+ */
4
+
5
+ import { type Chain, getChainConfig } from "@tcswap/types";
6
+ import type { BrowserProvider, JsonRpcProvider } from "ethers";
7
+ import { USwapError } from "../modules/uSwapError";
8
+ import {
9
+ type EIP6963AnnounceProviderEvent,
10
+ type EIP6963Provider,
11
+ type EthereumWindowProvider,
12
+ type NetworkParams,
13
+ WalletOption,
14
+ } from "../types";
15
+ import { warnOnce } from "./others";
16
+
17
+ declare const window: {
18
+ ethereum: EthereumWindowProvider;
19
+ trustwallet: EthereumWindowProvider;
20
+ coinbaseWalletExtension: EthereumWindowProvider;
21
+ braveSolana: any;
22
+ bitkeep?: { ethereum: EthereumWindowProvider };
23
+ ctrl?: { ethereum: EthereumWindowProvider };
24
+ $onekey?: { ethereum: EthereumWindowProvider };
25
+ vultisig?: { ethereum: EthereumWindowProvider };
26
+ } & Window;
27
+
28
+ export function isWeb3Detected() {
29
+ return typeof window.ethereum !== "undefined";
30
+ }
31
+
32
+ export function isDetected(walletOption: WalletOption) {
33
+ return listWeb3EVMWallets().includes(walletOption);
34
+ }
35
+
36
+ export function listWeb3EVMWallets() {
37
+ const metamaskEnabled = window?.ethereum && !window.ethereum?.isBraveWallet;
38
+ const ctrlEnabled = window?.ctrl || window?.ethereum?.__XDEFI;
39
+ const vultisigEnabled = window?.vultisig;
40
+ const braveEnabled = window?.ethereum?.isBraveWallet;
41
+ const trustEnabled = window?.ethereum?.isTrust || window?.trustwallet;
42
+ const coinbaseEnabled =
43
+ (window?.ethereum?.overrideIsMetaMask && window?.ethereum?.selectedProvider?.isCoinbaseWallet) ||
44
+ window?.coinbaseWalletExtension;
45
+ const bitgetEnabled = window?.bitkeep?.ethereum;
46
+ const onekeyEnabled = window?.$onekey?.ethereum;
47
+
48
+ const wallets = [];
49
+ if (metamaskEnabled) wallets.push(WalletOption.METAMASK);
50
+ if (ctrlEnabled) wallets.push(WalletOption.CTRL);
51
+ if (vultisigEnabled) wallets.push(WalletOption.VULTISIG);
52
+ if (braveEnabled) wallets.push(WalletOption.BRAVE);
53
+ if (trustEnabled) wallets.push(WalletOption.TRUSTWALLET_WEB);
54
+ if (coinbaseEnabled) wallets.push(WalletOption.COINBASE_WEB);
55
+ if (okxMobileEnabled()) wallets.push(WalletOption.OKX_MOBILE);
56
+ if (bitgetEnabled) wallets.push(WalletOption.BITGET);
57
+ if (onekeyEnabled) wallets.push(WalletOption.ONEKEY);
58
+
59
+ return wallets;
60
+ }
61
+
62
+ export async function switchEVMWalletNetwork(provider: BrowserProvider, chain: Chain, networkParams?: NetworkParams) {
63
+ const chainConfig = getChainConfig(chain);
64
+
65
+ try {
66
+ await providerRequest({
67
+ method: "wallet_switchEthereumChain",
68
+ params: [{ chainId: chainConfig.chainIdHex }],
69
+ provider,
70
+ });
71
+ } catch (error) {
72
+ if (!networkParams) {
73
+ throw new USwapError("helpers_failed_to_switch_network", { error: error, reason: "networkParams not provided" });
74
+ }
75
+ await addEVMWalletNetwork(provider, networkParams);
76
+ }
77
+ }
78
+
79
+ export function filterSupportedChains<T extends string[]>({
80
+ chains,
81
+ supportedChains,
82
+ walletType,
83
+ }: {
84
+ chains: Chain[];
85
+ supportedChains: T;
86
+ walletType?: WalletOption;
87
+ }) {
88
+ const supported = chains.filter((chain) => !chain || supportedChains.includes(chain));
89
+
90
+ if (supported.length === 0) {
91
+ throw new USwapError("wallet_chain_not_supported", { chain: chains.join(", "), wallet: walletType });
92
+ }
93
+
94
+ const unsupported = chains.filter((chain) => !supportedChains.includes(chain));
95
+
96
+ warnOnce({
97
+ condition: unsupported.length > 0,
98
+ id: `wallet_chain_not_supported_${walletType}`,
99
+ warning: `${walletType} wallet does not support the following chains: ${unsupported.join(
100
+ ", ",
101
+ )}. These chains will be ignored.`,
102
+ });
103
+
104
+ return supported as T;
105
+ }
106
+
107
+ export function wrapMethodWithNetworkSwitch<T extends (...args: any[]) => any>(
108
+ func: T,
109
+ provider: BrowserProvider,
110
+ chain: Chain,
111
+ ) {
112
+ return (async (...args: any[]) => {
113
+ const { chainIdHex } = getChainConfig(chain);
114
+ if ((await provider.getNetwork()).chainId.toString() === chainIdHex) {
115
+ return func(...args);
116
+ }
117
+ try {
118
+ await switchEVMWalletNetwork(provider, chain);
119
+ } catch (error) {
120
+ throw new USwapError({ errorKey: "helpers_failed_to_switch_network", info: { error } });
121
+ }
122
+ return func(...args);
123
+ }) as unknown as T;
124
+ }
125
+
126
+ export function prepareNetworkSwitch<T extends Record<string, unknown>, M extends keyof T>({
127
+ toolbox,
128
+ chain,
129
+ provider = window.ethereum,
130
+ methodNames = [],
131
+ }: {
132
+ toolbox: T;
133
+ chain: Chain;
134
+ provider?: BrowserProvider | JsonRpcProvider;
135
+ methodNames?: M[];
136
+ }) {
137
+ const methodsToWrap = [
138
+ ...methodNames,
139
+ "approve",
140
+ "approvedAmount",
141
+ "call",
142
+ "sendTransaction",
143
+ "transfer",
144
+ "isApproved",
145
+ "approvedAmount",
146
+ "EIP1193SendTransaction",
147
+ "getFeeData",
148
+ "broadcastTransaction",
149
+ "estimateCall",
150
+ "estimateGasLimit",
151
+ "estimateGasPrices",
152
+ "createContractTxObject",
153
+ ] as M[];
154
+ const wrappedMethods = methodsToWrap.reduce((object, methodName) => {
155
+ if (!toolbox[methodName]) return object;
156
+
157
+ const method = toolbox[methodName];
158
+
159
+ if (typeof method !== "function") return object;
160
+
161
+ // @ts-expect-error
162
+ const wrappedMethod = wrapMethodWithNetworkSwitch(method, provider, chain);
163
+
164
+ // biome-ignore lint/performance/noAccumulatingSpread: valid use case
165
+ return { ...object, [methodName]: wrappedMethod };
166
+ }, {});
167
+
168
+ return { ...toolbox, ...wrappedMethods };
169
+ }
170
+
171
+ export function addEVMWalletNetwork(provider: BrowserProvider, networkParams: NetworkParams) {
172
+ return providerRequest({ method: "wallet_addEthereumChain", params: [networkParams], provider });
173
+ }
174
+
175
+ export function addAccountsChangedCallback(callback: () => void) {
176
+ window.ethereum?.on("accountsChanged", () => callback());
177
+ window.ctrl?.ethereum.on("accountsChanged", () => callback());
178
+ }
179
+
180
+ export function getETHDefaultWallet() {
181
+ const { isTrust, isBraveWallet, __XDEFI, overrideIsMetaMask, selectedProvider } = window?.ethereum || {};
182
+ if (isTrust) return WalletOption.TRUSTWALLET_WEB;
183
+ if (isBraveWallet) return WalletOption.BRAVE;
184
+ if (overrideIsMetaMask && selectedProvider?.isCoinbaseWallet) return WalletOption.COINBASE_WEB;
185
+ if (__XDEFI) return WalletOption.CTRL;
186
+ if (window?.$onekey?.ethereum) return WalletOption.ONEKEY;
187
+ return WalletOption.METAMASK;
188
+ }
189
+
190
+ export function getEIP6963Wallets() {
191
+ const providers: EIP6963Provider[] = [];
192
+
193
+ function onAnnouncement(event: EIP6963AnnounceProviderEvent) {
194
+ if (providers.map((p) => p.info.uuid).includes(event.detail.info.uuid)) return;
195
+ providers.push(event.detail);
196
+ }
197
+
198
+ window.addEventListener("eip6963:announceProvider", onAnnouncement);
199
+ window.dispatchEvent(new Event("eip6963:requestProvider"));
200
+
201
+ function removeEIP6963EventListener() {
202
+ window.removeEventListener("eip6963:announceProvider", onAnnouncement);
203
+ }
204
+
205
+ return { providers, removeEIP6963EventListener };
206
+ }
207
+
208
+ export function okxMobileEnabled() {
209
+ const ua = navigator.userAgent;
210
+ const isIOS = /iphone|ipad|ipod|ios/i.test(ua);
211
+ const isAndroid = /android|XiaoMi|MiuiBrowser/i.test(ua);
212
+ const isMobile = isIOS || isAndroid;
213
+ const isOKApp = /OKApp/i.test(ua);
214
+
215
+ return isMobile && isOKApp;
216
+ }
217
+
218
+ export function providerRequest({
219
+ provider,
220
+ params,
221
+ method,
222
+ }: {
223
+ provider?: BrowserProvider;
224
+ params?: any;
225
+ method:
226
+ | "wallet_addEthereumChain"
227
+ | "wallet_switchEthereumChain"
228
+ | "eth_requestAccounts"
229
+ | "eth_sendTransaction"
230
+ | "eth_signTransaction";
231
+ }) {
232
+ if (!provider?.send) {
233
+ throw new USwapError("helpers_not_found_provider");
234
+ }
235
+
236
+ const providerParams = params ? (Array.isArray(params) ? params : [params]) : [];
237
+ return provider.send(method, providerParams);
238
+ }