@t2000/sdk 0.17.22 → 0.17.24

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 (254) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/cetus.d.ts +29 -0
  3. package/dist/adapters/cetus.d.ts.map +1 -0
  4. package/dist/adapters/cetus.js +74 -0
  5. package/dist/adapters/cetus.js.map +1 -0
  6. package/dist/adapters/cetus.test.d.ts +2 -0
  7. package/dist/adapters/cetus.test.d.ts.map +1 -0
  8. package/dist/adapters/cetus.test.js +57 -0
  9. package/dist/adapters/cetus.test.js.map +1 -0
  10. package/dist/adapters/compliance.test.d.ts +8 -0
  11. package/dist/adapters/compliance.test.d.ts.map +1 -0
  12. package/dist/adapters/compliance.test.js +202 -0
  13. package/dist/adapters/compliance.test.js.map +1 -0
  14. package/dist/adapters/index.d.ts +10 -4
  15. package/dist/adapters/index.d.ts.map +1 -0
  16. package/dist/adapters/index.js +15 -2107
  17. package/dist/adapters/index.js.map +1 -1
  18. package/dist/adapters/navi.d.ts +41 -0
  19. package/dist/adapters/navi.d.ts.map +1 -0
  20. package/dist/adapters/navi.js +102 -0
  21. package/dist/adapters/navi.js.map +1 -0
  22. package/dist/adapters/navi.test.d.ts +2 -0
  23. package/dist/adapters/navi.test.d.ts.map +1 -0
  24. package/dist/adapters/navi.test.js +164 -0
  25. package/dist/adapters/navi.test.js.map +1 -0
  26. package/dist/adapters/registry.d.ts +47 -0
  27. package/dist/adapters/registry.d.ts.map +1 -0
  28. package/dist/adapters/registry.js +162 -0
  29. package/dist/adapters/registry.js.map +1 -0
  30. package/dist/adapters/registry.test.d.ts +2 -0
  31. package/dist/adapters/registry.test.d.ts.map +1 -0
  32. package/dist/adapters/registry.test.js +197 -0
  33. package/dist/adapters/registry.test.js.map +1 -0
  34. package/dist/adapters/suilend.d.ts +71 -0
  35. package/dist/adapters/suilend.d.ts.map +1 -0
  36. package/dist/adapters/suilend.js +826 -0
  37. package/dist/adapters/suilend.js.map +1 -0
  38. package/dist/adapters/suilend.test.d.ts +2 -0
  39. package/dist/adapters/suilend.test.d.ts.map +1 -0
  40. package/dist/adapters/suilend.test.js +294 -0
  41. package/dist/adapters/suilend.test.js.map +1 -0
  42. package/dist/adapters/types.d.ts +160 -0
  43. package/dist/adapters/types.d.ts.map +1 -0
  44. package/dist/adapters/types.js +2 -0
  45. package/dist/adapters/types.js.map +1 -0
  46. package/dist/auto-invest.d.ts +23 -0
  47. package/dist/auto-invest.d.ts.map +1 -0
  48. package/dist/auto-invest.js +131 -0
  49. package/dist/auto-invest.js.map +1 -0
  50. package/dist/auto-invest.test.d.ts +2 -0
  51. package/dist/auto-invest.test.d.ts.map +1 -0
  52. package/dist/auto-invest.test.js +220 -0
  53. package/dist/auto-invest.test.js.map +1 -0
  54. package/dist/constants.d.ts +177 -0
  55. package/dist/constants.d.ts.map +1 -0
  56. package/dist/constants.js +135 -0
  57. package/dist/constants.js.map +1 -0
  58. package/dist/contacts.d.ts +25 -0
  59. package/dist/contacts.d.ts.map +1 -0
  60. package/dist/contacts.js +83 -0
  61. package/dist/contacts.js.map +1 -0
  62. package/dist/contacts.test.d.ts +2 -0
  63. package/dist/contacts.test.d.ts.map +1 -0
  64. package/dist/contacts.test.js +164 -0
  65. package/dist/contacts.test.js.map +1 -0
  66. package/dist/errors.d.ts +26 -0
  67. package/dist/errors.d.ts.map +1 -0
  68. package/dist/errors.js +81 -0
  69. package/dist/errors.js.map +1 -0
  70. package/dist/errors.test.d.ts +2 -0
  71. package/dist/errors.test.d.ts.map +1 -0
  72. package/dist/errors.test.js +48 -0
  73. package/dist/errors.test.js.map +1 -0
  74. package/dist/gas/autoTopUp.d.ts +18 -0
  75. package/dist/gas/autoTopUp.d.ts.map +1 -0
  76. package/dist/gas/autoTopUp.js +55 -0
  77. package/dist/gas/autoTopUp.js.map +1 -0
  78. package/dist/gas/autoTopUp.test.d.ts +2 -0
  79. package/dist/gas/autoTopUp.test.d.ts.map +1 -0
  80. package/dist/gas/autoTopUp.test.js +59 -0
  81. package/dist/gas/autoTopUp.test.js.map +1 -0
  82. package/dist/gas/gasStation.d.ts +23 -0
  83. package/dist/gas/gasStation.d.ts.map +1 -0
  84. package/dist/gas/gasStation.js +58 -0
  85. package/dist/gas/gasStation.js.map +1 -0
  86. package/dist/gas/index.d.ts +4 -0
  87. package/dist/gas/index.d.ts.map +1 -0
  88. package/dist/gas/index.js +4 -0
  89. package/dist/gas/index.js.map +1 -0
  90. package/dist/gas/manager.d.ts +24 -0
  91. package/dist/gas/manager.d.ts.map +1 -0
  92. package/dist/gas/manager.js +142 -0
  93. package/dist/gas/manager.js.map +1 -0
  94. package/dist/gas/manager.test.d.ts +2 -0
  95. package/dist/gas/manager.test.d.ts.map +1 -0
  96. package/dist/gas/manager.test.js +220 -0
  97. package/dist/gas/manager.test.js.map +1 -0
  98. package/dist/gas/serialization.test.d.ts +2 -0
  99. package/dist/gas/serialization.test.d.ts.map +1 -0
  100. package/dist/gas/serialization.test.js +47 -0
  101. package/dist/gas/serialization.test.js.map +1 -0
  102. package/dist/index.d.ts +30 -649
  103. package/dist/index.d.ts.map +1 -0
  104. package/dist/index.js +21 -6053
  105. package/dist/index.js.map +1 -1
  106. package/dist/invest.test.d.ts +2 -0
  107. package/dist/invest.test.d.ts.map +1 -0
  108. package/dist/invest.test.js +256 -0
  109. package/dist/invest.test.js.map +1 -0
  110. package/dist/portfolio.d.ts +39 -0
  111. package/dist/portfolio.d.ts.map +1 -0
  112. package/dist/portfolio.js +201 -0
  113. package/dist/portfolio.js.map +1 -0
  114. package/dist/portfolio.test.d.ts +2 -0
  115. package/dist/portfolio.test.d.ts.map +1 -0
  116. package/dist/portfolio.test.js +301 -0
  117. package/dist/portfolio.test.js.map +1 -0
  118. package/dist/protocols/cetus.d.ts +73 -0
  119. package/dist/protocols/cetus.d.ts.map +1 -0
  120. package/dist/protocols/cetus.js +267 -0
  121. package/dist/protocols/cetus.js.map +1 -0
  122. package/dist/protocols/cetus.test.d.ts +2 -0
  123. package/dist/protocols/cetus.test.d.ts.map +1 -0
  124. package/dist/protocols/cetus.test.js +325 -0
  125. package/dist/protocols/cetus.test.js.map +1 -0
  126. package/dist/protocols/navi.d.ts +59 -0
  127. package/dist/protocols/navi.d.ts.map +1 -0
  128. package/dist/protocols/navi.js +945 -0
  129. package/dist/protocols/navi.js.map +1 -0
  130. package/dist/protocols/navi.test.d.ts +2 -0
  131. package/dist/protocols/navi.test.d.ts.map +1 -0
  132. package/dist/protocols/navi.test.js +339 -0
  133. package/dist/protocols/navi.test.js.map +1 -0
  134. package/dist/protocols/protocolFee.d.ts +17 -0
  135. package/dist/protocols/protocolFee.d.ts.map +1 -0
  136. package/dist/protocols/protocolFee.js +62 -0
  137. package/dist/protocols/protocolFee.js.map +1 -0
  138. package/dist/protocols/protocolFee.test.d.ts +2 -0
  139. package/dist/protocols/protocolFee.test.d.ts.map +1 -0
  140. package/dist/protocols/protocolFee.test.js +137 -0
  141. package/dist/protocols/protocolFee.test.js.map +1 -0
  142. package/dist/protocols/sentinel.d.ts +18 -0
  143. package/dist/protocols/sentinel.d.ts.map +1 -0
  144. package/dist/protocols/sentinel.js +188 -0
  145. package/dist/protocols/sentinel.js.map +1 -0
  146. package/dist/protocols/sentinel.test.d.ts +2 -0
  147. package/dist/protocols/sentinel.test.d.ts.map +1 -0
  148. package/dist/protocols/sentinel.test.js +199 -0
  149. package/dist/protocols/sentinel.test.js.map +1 -0
  150. package/dist/protocols/yieldTracker.d.ts +6 -0
  151. package/dist/protocols/yieldTracker.d.ts.map +1 -0
  152. package/dist/protocols/yieldTracker.js +29 -0
  153. package/dist/protocols/yieldTracker.js.map +1 -0
  154. package/dist/safeguards/enforcer.d.ts +18 -0
  155. package/dist/safeguards/enforcer.d.ts.map +1 -0
  156. package/dist/safeguards/enforcer.js +130 -0
  157. package/dist/safeguards/enforcer.js.map +1 -0
  158. package/dist/safeguards/enforcer.test.d.ts +2 -0
  159. package/dist/safeguards/enforcer.test.d.ts.map +1 -0
  160. package/dist/safeguards/enforcer.test.js +212 -0
  161. package/dist/safeguards/enforcer.test.js.map +1 -0
  162. package/dist/safeguards/errors.d.ts +24 -0
  163. package/dist/safeguards/errors.d.ts.map +1 -0
  164. package/dist/safeguards/errors.js +31 -0
  165. package/dist/safeguards/errors.js.map +1 -0
  166. package/dist/safeguards/index.d.ts +6 -0
  167. package/dist/safeguards/index.d.ts.map +1 -0
  168. package/dist/safeguards/index.js +4 -0
  169. package/dist/safeguards/index.js.map +1 -0
  170. package/dist/safeguards/types.d.ts +16 -0
  171. package/dist/safeguards/types.d.ts.map +1 -0
  172. package/dist/safeguards/types.js +13 -0
  173. package/dist/safeguards/types.js.map +1 -0
  174. package/dist/strategy.d.ts +22 -0
  175. package/dist/strategy.d.ts.map +1 -0
  176. package/dist/strategy.js +113 -0
  177. package/dist/strategy.js.map +1 -0
  178. package/dist/strategy.test.d.ts +2 -0
  179. package/dist/strategy.test.d.ts.map +1 -0
  180. package/dist/strategy.test.js +212 -0
  181. package/dist/strategy.test.js.map +1 -0
  182. package/dist/t2000.d.ts +218 -0
  183. package/dist/t2000.d.ts.map +1 -0
  184. package/dist/t2000.integration.test.d.ts +2 -0
  185. package/dist/t2000.integration.test.d.ts.map +1 -0
  186. package/dist/t2000.integration.test.js +954 -0
  187. package/dist/t2000.integration.test.js.map +1 -0
  188. package/dist/t2000.js +2395 -0
  189. package/dist/t2000.js.map +1 -0
  190. package/dist/types.d.ts +419 -0
  191. package/dist/types.d.ts.map +1 -0
  192. package/dist/types.js +2 -0
  193. package/dist/types.js.map +1 -0
  194. package/dist/utils/format.d.ts +22 -0
  195. package/dist/utils/format.d.ts.map +1 -0
  196. package/dist/utils/format.js +71 -0
  197. package/dist/utils/format.js.map +1 -0
  198. package/dist/utils/format.test.d.ts +2 -0
  199. package/dist/utils/format.test.d.ts.map +1 -0
  200. package/dist/utils/format.test.js +187 -0
  201. package/dist/utils/format.test.js.map +1 -0
  202. package/dist/utils/hashcash.d.ts +2 -0
  203. package/dist/utils/hashcash.d.ts.map +1 -0
  204. package/dist/utils/hashcash.js +27 -0
  205. package/dist/utils/hashcash.js.map +1 -0
  206. package/dist/utils/hashcash.test.d.ts +2 -0
  207. package/dist/utils/hashcash.test.d.ts.map +1 -0
  208. package/dist/utils/hashcash.test.js +40 -0
  209. package/dist/utils/hashcash.test.js.map +1 -0
  210. package/dist/utils/retry.d.ts +9 -0
  211. package/dist/utils/retry.d.ts.map +1 -0
  212. package/dist/utils/retry.js +47 -0
  213. package/dist/utils/retry.js.map +1 -0
  214. package/dist/utils/simulate.d.ts +15 -0
  215. package/dist/utils/simulate.d.ts.map +1 -0
  216. package/dist/utils/simulate.js +75 -0
  217. package/dist/utils/simulate.js.map +1 -0
  218. package/dist/utils/simulate.test.d.ts +2 -0
  219. package/dist/utils/simulate.test.d.ts.map +1 -0
  220. package/dist/utils/simulate.test.js +80 -0
  221. package/dist/utils/simulate.test.js.map +1 -0
  222. package/dist/utils/sui.d.ts +6 -0
  223. package/dist/utils/sui.d.ts.map +1 -0
  224. package/dist/utils/sui.js +28 -0
  225. package/dist/utils/sui.js.map +1 -0
  226. package/dist/utils/sui.test.d.ts +2 -0
  227. package/dist/utils/sui.test.d.ts.map +1 -0
  228. package/dist/utils/sui.test.js +58 -0
  229. package/dist/utils/sui.test.js.map +1 -0
  230. package/dist/wallet/balance.d.ts +4 -0
  231. package/dist/wallet/balance.d.ts.map +1 -0
  232. package/dist/wallet/balance.js +98 -0
  233. package/dist/wallet/balance.js.map +1 -0
  234. package/dist/wallet/history.d.ts +4 -0
  235. package/dist/wallet/history.d.ts.map +1 -0
  236. package/dist/wallet/history.js +38 -0
  237. package/dist/wallet/history.js.map +1 -0
  238. package/dist/wallet/keyManager.d.ts +9 -0
  239. package/dist/wallet/keyManager.d.ts.map +1 -0
  240. package/dist/wallet/keyManager.js +113 -0
  241. package/dist/wallet/keyManager.js.map +1 -0
  242. package/dist/wallet/keyManager.test.d.ts +2 -0
  243. package/dist/wallet/keyManager.test.d.ts.map +1 -0
  244. package/dist/wallet/keyManager.test.js +55 -0
  245. package/dist/wallet/keyManager.test.js.map +1 -0
  246. package/dist/wallet/send.d.ts +24 -0
  247. package/dist/wallet/send.d.ts.map +1 -0
  248. package/dist/wallet/send.js +95 -0
  249. package/dist/wallet/send.js.map +1 -0
  250. package/dist/wallet/send.test.d.ts +2 -0
  251. package/dist/wallet/send.test.d.ts.map +1 -0
  252. package/dist/wallet/send.test.js +69 -0
  253. package/dist/wallet/send.test.js.map +1 -0
  254. package/package.json +1 -1
@@ -0,0 +1,135 @@
1
+ export const MIST_PER_SUI = 1000000000n;
2
+ export const SUI_DECIMALS = 9;
3
+ export const USDC_DECIMALS = 6;
4
+ export const BPS_DENOMINATOR = 10000n;
5
+ export const PRECISION = 1000000000000000000n;
6
+ export const MIN_DEPOSIT = 1000000n; // 1 USDC (6 decimals)
7
+ export const GAS_RESERVE_USDC = 1000000n; // $1 USDC reserved for gas
8
+ export const AUTO_TOPUP_THRESHOLD = 50000000n; // 0.05 SUI
9
+ export const AUTO_TOPUP_AMOUNT = 1000000n; // $1 USDC worth of SUI
10
+ export const AUTO_TOPUP_MIN_USDC = 2000000n; // $2 USDC minimum to trigger auto-topup
11
+ export const BOOTSTRAP_LIMIT = 10;
12
+ export const GAS_FEE_CEILING_USD = 0.05;
13
+ export const SAVE_FEE_BPS = 10n; // 0.1%
14
+ export const SWAP_FEE_BPS = 0n; // Free — Cetus already charges pool fees
15
+ export const BORROW_FEE_BPS = 5n; // 0.05%
16
+ export const CLOCK_ID = '0x6';
17
+ export const SUPPORTED_ASSETS = {
18
+ USDC: {
19
+ type: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
20
+ decimals: 6,
21
+ symbol: 'USDC',
22
+ displayName: 'USDC',
23
+ },
24
+ USDT: {
25
+ type: '0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT',
26
+ decimals: 6,
27
+ symbol: 'USDT',
28
+ displayName: 'suiUSDT',
29
+ },
30
+ USDe: {
31
+ type: '0x41d587e5336f1c86cad50d38a7136db99333bb9bda91cea4ba69115defeb1402::sui_usde::SUI_USDE',
32
+ decimals: 6,
33
+ symbol: 'USDe',
34
+ displayName: 'suiUSDe',
35
+ },
36
+ USDsui: {
37
+ type: '0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI',
38
+ decimals: 6,
39
+ symbol: 'USDsui',
40
+ displayName: 'USDsui',
41
+ },
42
+ SUI: {
43
+ type: '0x2::sui::SUI',
44
+ decimals: 9,
45
+ symbol: 'SUI',
46
+ displayName: 'SUI',
47
+ },
48
+ BTC: {
49
+ type: '0x0041f9f9344cac094454cd574e333c4fdb132d7bcc9379bcd4aab485b2a63942::wbtc::WBTC',
50
+ decimals: 8,
51
+ symbol: 'BTC',
52
+ displayName: 'Bitcoin',
53
+ },
54
+ ETH: {
55
+ type: '0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH',
56
+ decimals: 8,
57
+ symbol: 'ETH',
58
+ displayName: 'Ethereum',
59
+ },
60
+ GOLD: {
61
+ type: '0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM',
62
+ decimals: 9,
63
+ symbol: 'GOLD',
64
+ displayName: 'Gold',
65
+ },
66
+ };
67
+ export const STABLE_ASSETS = ['USDC', 'USDT', 'USDe', 'USDsui'];
68
+ export const T2000_PACKAGE_ID = process.env.T2000_PACKAGE_ID ?? '0xab92e9f1fe549ad3d6a52924a73181b45791e76120b975138fac9ec9b75db9f3';
69
+ export const T2000_CONFIG_ID = process.env.T2000_CONFIG_ID ?? '0x408add9aa9322f93cfd87523d8f603006eb8713894f4c460283c58a6888dae8a';
70
+ export const T2000_ADMIN_CAP_ID = '0x863d1b02cba1b93d0fe9b87eb92d58b60c1e85c001022cb2a760e07bade47e65';
71
+ export const T2000_TREASURY_ID = process.env.T2000_TREASURY_ID ?? '0x3bb501b8300125dca59019247941a42af6b292a150ce3cfcce9449456be2ec91';
72
+ export const DEFAULT_NETWORK = 'mainnet';
73
+ export const DEFAULT_RPC_URL = 'https://fullnode.mainnet.sui.io:443';
74
+ export const DEFAULT_KEY_PATH = '~/.t2000/wallet.key';
75
+ export const DEFAULT_CONFIG_PATH = '~/.t2000/config.json';
76
+ export const API_BASE_URL = process.env.T2000_API_URL ?? 'https://api.t2000.ai';
77
+ export const CETUS_USDC_SUI_POOL = '0x51e883ba7c0b566a26cbc8a94cd33eb0abd418a77cc1e60ad22fd9b1f29cd2ab';
78
+ export const CETUS_GLOBAL_CONFIG = '0xdaa46292632c3c4d8f31f23ea0f9b36a28ff3677e9684980e4438403a67a3d8f';
79
+ export const CETUS_PACKAGE = '0x1eabed72c53feb3805120a081dc15963c204dc8d091542592abaf7a35689b2fb';
80
+ // --- Investment ---
81
+ export const INVESTMENT_ASSETS = {
82
+ SUI: SUPPORTED_ASSETS.SUI,
83
+ BTC: SUPPORTED_ASSETS.BTC,
84
+ ETH: SUPPORTED_ASSETS.ETH,
85
+ GOLD: SUPPORTED_ASSETS.GOLD,
86
+ };
87
+ export const DEFAULT_STRATEGIES = {
88
+ bluechip: {
89
+ name: 'Bluechip / Large-Cap',
90
+ allocations: { BTC: 50, ETH: 30, SUI: 20 },
91
+ description: 'Large-cap crypto index',
92
+ custom: false,
93
+ },
94
+ layer1: {
95
+ name: 'Smart Contract Platforms',
96
+ allocations: { ETH: 50, SUI: 50 },
97
+ description: 'Smart contract platforms',
98
+ custom: false,
99
+ },
100
+ 'sui-heavy': {
101
+ name: 'Sui-Weighted Portfolio',
102
+ allocations: { BTC: 20, ETH: 20, SUI: 60 },
103
+ description: 'Sui-weighted portfolio',
104
+ custom: false,
105
+ },
106
+ 'all-weather': {
107
+ name: 'All-Weather Portfolio',
108
+ allocations: { BTC: 30, ETH: 20, SUI: 20, GOLD: 30 },
109
+ description: 'Crypto and commodities',
110
+ custom: false,
111
+ },
112
+ 'safe-haven': {
113
+ name: 'Safe Haven',
114
+ allocations: { BTC: 50, GOLD: 50 },
115
+ description: 'Store-of-value assets',
116
+ custom: false,
117
+ },
118
+ };
119
+ export const PERPS_MARKETS = ['SUI-PERP'];
120
+ export const DEFAULT_MAX_LEVERAGE = 5;
121
+ export const DEFAULT_MAX_POSITION_SIZE = 1000;
122
+ export const INVEST_FEE_BPS = 0n;
123
+ export const GAS_RESERVE_MIN = 0.05; // minimum SUI to keep for gas
124
+ export const SENTINEL = {
125
+ PACKAGE: '0x88b83f36dafcd5f6dcdcf1d2cb5889b03f61264ab3cee9cae35db7aa940a21b7',
126
+ AGENT_REGISTRY: '0xc47564f5f14c12b31e0dfa1a3dc99a6380a1edf8929c28cb0eaa3359c8db36ac',
127
+ ENCLAVE: '0xfb1261aeb9583514cb1341a548a5ec12d1231bd96af22215f1792617a93e1213',
128
+ PROTOCOL_CONFIG: '0x2fa4fa4a1dd0498612304635ff9334e1b922e78af325000e9d9c0e88adea459f',
129
+ TEE_API: 'https://app.suisentinel.xyz/api/consume-prompt',
130
+ SENTINELS_API: 'https://api.suisentinel.xyz/agents/mainnet',
131
+ RANDOM: '0x8',
132
+ MIN_FEE_MIST: 100000000n, // 0.1 SUI
133
+ MAX_PROMPT_TOKENS: 600,
134
+ };
135
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export interface Contact {
2
+ name: string;
3
+ address: string;
4
+ }
5
+ export type ContactMap = Record<string, Contact>;
6
+ export declare class ContactManager {
7
+ private contacts;
8
+ private readonly filePath;
9
+ private readonly dir;
10
+ constructor(configDir?: string);
11
+ private load;
12
+ private save;
13
+ add(name: string, address: string): {
14
+ action: 'added' | 'updated';
15
+ };
16
+ remove(name: string): boolean;
17
+ get(name: string): Contact | undefined;
18
+ list(): Contact[];
19
+ resolve(nameOrAddress: string): {
20
+ address: string;
21
+ contactName?: string;
22
+ };
23
+ private validateName;
24
+ }
25
+ //# sourceMappingURL=contacts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contacts.d.ts","sourceRoot":"","sources":["../src/contacts.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAIjD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEjB,SAAS,CAAC,EAAE,MAAM;IAM9B,OAAO,CAAC,IAAI;IAUZ,OAAO,CAAC,IAAI;IAKZ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;KAAE;IAUnE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAQ7B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAKtC,IAAI,IAAI,OAAO,EAAE;IAKjB,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;IAmBzE,OAAO,CAAC,YAAY;CAcrB"}
@@ -0,0 +1,83 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { validateAddress } from './utils/sui.js';
5
+ import { T2000Error } from './errors.js';
6
+ const RESERVED_NAMES = new Set(['to', 'all', 'address']);
7
+ export class ContactManager {
8
+ contacts = {};
9
+ filePath;
10
+ dir;
11
+ constructor(configDir) {
12
+ this.dir = configDir ?? join(homedir(), '.t2000');
13
+ this.filePath = join(this.dir, 'contacts.json');
14
+ this.load();
15
+ }
16
+ load() {
17
+ try {
18
+ if (existsSync(this.filePath)) {
19
+ this.contacts = JSON.parse(readFileSync(this.filePath, 'utf-8'));
20
+ }
21
+ }
22
+ catch {
23
+ this.contacts = {};
24
+ }
25
+ }
26
+ save() {
27
+ if (!existsSync(this.dir))
28
+ mkdirSync(this.dir, { recursive: true });
29
+ writeFileSync(this.filePath, JSON.stringify(this.contacts, null, 2));
30
+ }
31
+ add(name, address) {
32
+ this.validateName(name);
33
+ const normalized = validateAddress(address);
34
+ const key = name.toLowerCase();
35
+ const existed = key in this.contacts;
36
+ this.contacts[key] = { name, address: normalized };
37
+ this.save();
38
+ return { action: existed ? 'updated' : 'added' };
39
+ }
40
+ remove(name) {
41
+ const key = name.toLowerCase();
42
+ if (!(key in this.contacts))
43
+ return false;
44
+ delete this.contacts[key];
45
+ this.save();
46
+ return true;
47
+ }
48
+ get(name) {
49
+ this.load();
50
+ return this.contacts[name.toLowerCase()];
51
+ }
52
+ list() {
53
+ this.load();
54
+ return Object.values(this.contacts);
55
+ }
56
+ resolve(nameOrAddress) {
57
+ this.load();
58
+ if (nameOrAddress.startsWith('0x') && nameOrAddress.length >= 42) {
59
+ return { address: validateAddress(nameOrAddress) };
60
+ }
61
+ const contact = this.contacts[nameOrAddress.toLowerCase()];
62
+ if (contact) {
63
+ return { address: contact.address, contactName: contact.name };
64
+ }
65
+ throw new T2000Error('CONTACT_NOT_FOUND', `"${nameOrAddress}" is not a valid Sui address or saved contact.\n` +
66
+ ` Add it: t2000 contacts add ${nameOrAddress} 0x...`);
67
+ }
68
+ validateName(name) {
69
+ if (name.startsWith('0x')) {
70
+ throw new T2000Error('INVALID_CONTACT_NAME', 'Contact names cannot start with 0x');
71
+ }
72
+ if (!/^[a-zA-Z0-9_]+$/.test(name)) {
73
+ throw new T2000Error('INVALID_CONTACT_NAME', 'Contact names can only contain letters, numbers, and underscores');
74
+ }
75
+ if (name.length > 32) {
76
+ throw new T2000Error('INVALID_CONTACT_NAME', 'Contact names must be 32 characters or fewer');
77
+ }
78
+ if (RESERVED_NAMES.has(name.toLowerCase())) {
79
+ throw new T2000Error('INVALID_CONTACT_NAME', `"${name}" is a reserved name and cannot be used as a contact`);
80
+ }
81
+ }
82
+ }
83
+ //# sourceMappingURL=contacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contacts.js","sourceRoot":"","sources":["../src/contacts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=contacts.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contacts.test.d.ts","sourceRoot":"","sources":["../src/contacts.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,164 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { ContactManager } from './contacts.js';
6
+ const VALID_ADDRESS = '0x8b3e4f2a1c9d7b5e3f1a8c2d4e6f9b0a1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e';
7
+ const VALID_ADDRESS_2 = '0x40cdfd49d252c798833ddb6e48900b4cd44eeff5f2ee8e5fad76b69b739c3e62';
8
+ describe('ContactManager', () => {
9
+ let dir;
10
+ let manager;
11
+ beforeEach(() => {
12
+ dir = mkdtempSync(join(tmpdir(), 't2000-contacts-test-'));
13
+ manager = new ContactManager(dir);
14
+ });
15
+ afterEach(() => {
16
+ rmSync(dir, { recursive: true, force: true });
17
+ });
18
+ describe('add', () => {
19
+ it('adds a new contact', () => {
20
+ const result = manager.add('Tom', VALID_ADDRESS);
21
+ expect(result.action).toBe('added');
22
+ });
23
+ it('updates an existing contact', () => {
24
+ manager.add('Tom', VALID_ADDRESS);
25
+ const result = manager.add('Tom', VALID_ADDRESS_2);
26
+ expect(result.action).toBe('updated');
27
+ });
28
+ it('persists to disk', () => {
29
+ manager.add('Tom', VALID_ADDRESS);
30
+ const fresh = new ContactManager(dir);
31
+ const contact = fresh.get('Tom');
32
+ expect(contact).toBeDefined();
33
+ expect(contact.name).toBe('Tom');
34
+ });
35
+ it('rejects names starting with 0x', () => {
36
+ expect(() => manager.add('0xHacker', VALID_ADDRESS)).toThrow('cannot start with 0x');
37
+ });
38
+ it('rejects names with special characters', () => {
39
+ expect(() => manager.add('Tom!', VALID_ADDRESS)).toThrow('letters, numbers, and underscores');
40
+ });
41
+ it('rejects names with spaces', () => {
42
+ expect(() => manager.add('Tom Smith', VALID_ADDRESS)).toThrow('letters, numbers, and underscores');
43
+ });
44
+ it('rejects names longer than 32 chars', () => {
45
+ const long = 'a'.repeat(33);
46
+ expect(() => manager.add(long, VALID_ADDRESS)).toThrow('32 characters or fewer');
47
+ });
48
+ it('rejects reserved name "to"', () => {
49
+ expect(() => manager.add('to', VALID_ADDRESS)).toThrow('reserved name');
50
+ });
51
+ it('rejects reserved name "all"', () => {
52
+ expect(() => manager.add('ALL', VALID_ADDRESS)).toThrow('reserved name');
53
+ });
54
+ it('rejects reserved name "address"', () => {
55
+ expect(() => manager.add('Address', VALID_ADDRESS)).toThrow('reserved name');
56
+ });
57
+ it('rejects invalid Sui address', () => {
58
+ expect(() => manager.add('Tom', 'not-an-address')).toThrow('Invalid Sui address');
59
+ });
60
+ it('allows underscores in names', () => {
61
+ const result = manager.add('my_wallet', VALID_ADDRESS);
62
+ expect(result.action).toBe('added');
63
+ });
64
+ it('allows numeric names', () => {
65
+ const result = manager.add('wallet1', VALID_ADDRESS);
66
+ expect(result.action).toBe('added');
67
+ });
68
+ it('rejects empty name', () => {
69
+ expect(() => manager.add('', VALID_ADDRESS)).toThrow('letters, numbers, and underscores');
70
+ });
71
+ });
72
+ describe('remove', () => {
73
+ it('removes existing contact', () => {
74
+ manager.add('Tom', VALID_ADDRESS);
75
+ expect(manager.remove('Tom')).toBe(true);
76
+ expect(manager.get('Tom')).toBeUndefined();
77
+ });
78
+ it('returns false for non-existent contact', () => {
79
+ expect(manager.remove('Nobody')).toBe(false);
80
+ });
81
+ it('is case-insensitive', () => {
82
+ manager.add('Tom', VALID_ADDRESS);
83
+ expect(manager.remove('TOM')).toBe(true);
84
+ });
85
+ });
86
+ describe('get', () => {
87
+ it('returns contact by name', () => {
88
+ manager.add('Tom', VALID_ADDRESS);
89
+ const contact = manager.get('Tom');
90
+ expect(contact).toBeDefined();
91
+ expect(contact.name).toBe('Tom');
92
+ });
93
+ it('is case-insensitive', () => {
94
+ manager.add('Tom', VALID_ADDRESS);
95
+ expect(manager.get('tom')).toBeDefined();
96
+ expect(manager.get('TOM')).toBeDefined();
97
+ });
98
+ it('returns undefined for non-existent contact', () => {
99
+ expect(manager.get('Nobody')).toBeUndefined();
100
+ });
101
+ it('preserves original casing', () => {
102
+ manager.add('MyWallet', VALID_ADDRESS);
103
+ const contact = manager.get('mywallet');
104
+ expect(contact.name).toBe('MyWallet');
105
+ });
106
+ });
107
+ describe('list', () => {
108
+ it('returns empty array when no contacts', () => {
109
+ expect(manager.list()).toEqual([]);
110
+ });
111
+ it('returns all contacts', () => {
112
+ manager.add('Tom', VALID_ADDRESS);
113
+ manager.add('Alice', VALID_ADDRESS_2);
114
+ const list = manager.list();
115
+ expect(list).toHaveLength(2);
116
+ expect(list.map(c => c.name).sort()).toEqual(['Alice', 'Tom']);
117
+ });
118
+ });
119
+ describe('resolve', () => {
120
+ it('resolves raw address directly', () => {
121
+ const result = manager.resolve(VALID_ADDRESS);
122
+ expect(result.address).toBeDefined();
123
+ expect(result.contactName).toBeUndefined();
124
+ });
125
+ it('resolves contact name to address', () => {
126
+ manager.add('Tom', VALID_ADDRESS);
127
+ const result = manager.resolve('Tom');
128
+ expect(result.contactName).toBe('Tom');
129
+ expect(result.address).toBeDefined();
130
+ });
131
+ it('is case-insensitive for names', () => {
132
+ manager.add('Tom', VALID_ADDRESS);
133
+ const result = manager.resolve('tom');
134
+ expect(result.contactName).toBe('Tom');
135
+ });
136
+ it('throws for unknown name', () => {
137
+ expect(() => manager.resolve('Nobody')).toThrow('not a valid Sui address or saved contact');
138
+ });
139
+ it('throws with helpful add hint', () => {
140
+ expect(() => manager.resolve('Nobody')).toThrow('t2000 contacts add Nobody');
141
+ });
142
+ it('validates raw addresses', () => {
143
+ expect(() => manager.resolve('0xinvalid')).toThrow();
144
+ });
145
+ });
146
+ describe('corrupted file', () => {
147
+ it('handles corrupted JSON gracefully', () => {
148
+ writeFileSync(join(dir, 'contacts.json'), 'not valid json!!!');
149
+ const m = new ContactManager(dir);
150
+ expect(m.list()).toEqual([]);
151
+ });
152
+ });
153
+ describe('reload from disk', () => {
154
+ it('picks up changes from another process', () => {
155
+ const m1 = new ContactManager(dir);
156
+ m1.add('Tom', VALID_ADDRESS);
157
+ const m2 = new ContactManager(dir);
158
+ const contact = m2.get('Tom');
159
+ expect(contact).toBeDefined();
160
+ expect(contact.name).toBe('Tom');
161
+ });
162
+ });
163
+ });
164
+ //# sourceMappingURL=contacts.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contacts.test.js","sourceRoot":"","sources":["../src/contacts.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export type T2000ErrorCode = 'INSUFFICIENT_BALANCE' | 'INSUFFICIENT_GAS' | 'INVALID_ADDRESS' | 'INVALID_AMOUNT' | 'WALLET_NOT_FOUND' | 'WALLET_LOCKED' | 'WALLET_EXISTS' | 'SPONSOR_FAILED' | 'SPONSOR_RATE_LIMITED' | 'GAS_STATION_UNAVAILABLE' | 'GAS_FEE_EXCEEDED' | 'SIMULATION_FAILED' | 'TRANSACTION_FAILED' | 'ASSET_NOT_SUPPORTED' | 'SWAP_FAILED' | 'SLIPPAGE_EXCEEDED' | 'HEALTH_FACTOR_TOO_LOW' | 'WITHDRAW_WOULD_LIQUIDATE' | 'NO_COLLATERAL' | 'PROTOCOL_PAUSED' | 'PROTOCOL_UNAVAILABLE' | 'RPC_ERROR' | 'RPC_UNREACHABLE' | 'SPONSOR_UNAVAILABLE' | 'AUTO_TOPUP_FAILED' | 'PRICE_EXCEEDS_LIMIT' | 'UNSUPPORTED_NETWORK' | 'PAYMENT_EXPIRED' | 'DUPLICATE_PAYMENT' | 'FACILITATOR_REJECTION' | 'CONTACT_NOT_FOUND' | 'INVALID_CONTACT_NAME' | 'FACILITATOR_TIMEOUT' | 'SENTINEL_API_ERROR' | 'SENTINEL_NOT_FOUND' | 'SENTINEL_TX_FAILED' | 'SENTINEL_TEE_ERROR' | 'SAFEGUARD_BLOCKED' | 'INSUFFICIENT_INVESTMENT' | 'INVESTMENT_LOCKED' | 'INVEST_ALREADY_EARNING' | 'INVEST_NOT_EARNING' | 'BORROW_GUARD_INVESTMENT' | 'STRATEGY_NOT_FOUND' | 'STRATEGY_INVALID_ALLOCATIONS' | 'STRATEGY_HAS_POSITIONS' | 'STRATEGY_BUILTIN' | 'STRATEGY_MIN_AMOUNT' | 'AUTO_INVEST_NOT_FOUND' | 'AUTO_INVEST_INSUFFICIENT' | 'MARKET_NOT_SUPPORTED' | 'LEVERAGE_EXCEEDED' | 'POSITION_SIZE_EXCEEDED' | 'BLUEFIN_AUTH_FAILED' | 'BLUEFIN_API_ERROR' | 'POSITION_NOT_FOUND' | 'UNKNOWN';
2
+ export interface T2000ErrorData {
3
+ reason?: string;
4
+ [key: string]: unknown;
5
+ }
6
+ export declare class T2000Error extends Error {
7
+ readonly code: T2000ErrorCode;
8
+ readonly data?: T2000ErrorData;
9
+ readonly retryable: boolean;
10
+ constructor(code: T2000ErrorCode, message: string, data?: T2000ErrorData, retryable?: boolean);
11
+ toJSON(): {
12
+ retryable: boolean;
13
+ data?: T2000ErrorData | undefined;
14
+ error: T2000ErrorCode;
15
+ message: string;
16
+ };
17
+ }
18
+ export declare function mapWalletError(error: unknown): T2000Error;
19
+ export declare function mapMoveAbortCode(code: number): string;
20
+ /**
21
+ * Check if an error message contains a MoveAbort — these are on-chain
22
+ * failures that will fail regardless of gas method, so retrying is pointless.
23
+ */
24
+ export declare function isMoveAbort(msg: string): boolean;
25
+ export declare function parseMoveAbortMessage(msg: string): string;
26
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GACtB,sBAAsB,GACtB,kBAAkB,GAClB,iBAAiB,GACjB,gBAAgB,GAChB,kBAAkB,GAClB,eAAe,GACf,eAAe,GACf,gBAAgB,GAChB,sBAAsB,GACtB,yBAAyB,GACzB,kBAAkB,GAClB,mBAAmB,GACnB,oBAAoB,GACpB,qBAAqB,GACrB,aAAa,GACb,mBAAmB,GACnB,uBAAuB,GACvB,0BAA0B,GAC1B,eAAe,GACf,iBAAiB,GACjB,sBAAsB,GACtB,WAAW,GACX,iBAAiB,GACjB,qBAAqB,GACrB,mBAAmB,GACnB,qBAAqB,GACrB,qBAAqB,GACrB,iBAAiB,GACjB,mBAAmB,GACnB,uBAAuB,GACvB,mBAAmB,GACnB,sBAAsB,GACtB,qBAAqB,GACrB,oBAAoB,GACpB,oBAAoB,GACpB,oBAAoB,GACpB,oBAAoB,GACpB,mBAAmB,GACnB,yBAAyB,GACzB,mBAAmB,GACnB,wBAAwB,GACxB,oBAAoB,GACpB,yBAAyB,GACzB,oBAAoB,GACpB,8BAA8B,GAC9B,wBAAwB,GACxB,kBAAkB,GAClB,qBAAqB,GACrB,uBAAuB,GACvB,0BAA0B,GAC1B,sBAAsB,GACtB,mBAAmB,GACnB,wBAAwB,GACxB,qBAAqB,GACrB,mBAAmB,GACnB,oBAAoB,GACpB,SAAS,CAAC;AAEd,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAEhB,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,EAAE,SAAS,UAAQ;IAQ3F,MAAM;;;;;;CAQP;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAWzD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqBrD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAuBzD"}
package/dist/errors.js ADDED
@@ -0,0 +1,81 @@
1
+ export class T2000Error extends Error {
2
+ code;
3
+ data;
4
+ retryable;
5
+ constructor(code, message, data, retryable = false) {
6
+ super(message);
7
+ this.name = 'T2000Error';
8
+ this.code = code;
9
+ this.data = data;
10
+ this.retryable = retryable;
11
+ }
12
+ toJSON() {
13
+ return {
14
+ error: this.code,
15
+ message: this.message,
16
+ ...(this.data && { data: this.data }),
17
+ retryable: this.retryable,
18
+ };
19
+ }
20
+ }
21
+ export function mapWalletError(error) {
22
+ const msg = error instanceof Error ? error.message : String(error);
23
+ if (msg.includes('rejected') || msg.includes('cancelled')) {
24
+ return new T2000Error('TRANSACTION_FAILED', 'Transaction cancelled');
25
+ }
26
+ if (msg.includes('Insufficient') || msg.includes('insufficient')) {
27
+ return new T2000Error('INSUFFICIENT_BALANCE', 'Insufficient balance');
28
+ }
29
+ return new T2000Error('UNKNOWN', msg, undefined, true);
30
+ }
31
+ export function mapMoveAbortCode(code) {
32
+ const abortMessages = {
33
+ 1: 'Protocol is temporarily paused',
34
+ 2: 'Amount must be greater than zero',
35
+ 3: 'Invalid operation type',
36
+ 4: 'Fee rate exceeds maximum',
37
+ 5: 'Insufficient treasury balance',
38
+ 6: 'Not authorized',
39
+ 7: 'Package version mismatch — upgrade required',
40
+ 8: 'Timelock is active — wait for expiry',
41
+ 9: 'No pending change to execute',
42
+ 10: 'Already at current version',
43
+ // NAVI Protocol abort codes
44
+ 1502: 'Oracle price is stale — try again in a moment',
45
+ 1503: 'Withdrawal amount is invalid (zero or dust) — try a specific amount instead of "all"',
46
+ 1600: 'Health factor too low — withdrawal would risk liquidation',
47
+ 1605: 'Asset borrowing is disabled or at capacity on this protocol',
48
+ // Cetus DEX abort codes
49
+ 46001: 'Swap failed — the DEX pool rejected the trade (liquidity or routing issue). Try again.',
50
+ };
51
+ return abortMessages[code] ?? `Move abort code: ${code}`;
52
+ }
53
+ /**
54
+ * Check if an error message contains a MoveAbort — these are on-chain
55
+ * failures that will fail regardless of gas method, so retrying is pointless.
56
+ */
57
+ export function isMoveAbort(msg) {
58
+ return msg.includes('MoveAbort') || msg.includes('MovePrimitiveRuntimeError');
59
+ }
60
+ export function parseMoveAbortMessage(msg) {
61
+ const abortMatch = msg.match(/abort code:\s*(\d+)/i) ?? msg.match(/MoveAbort[^,]*,\s*(\d+)/);
62
+ if (abortMatch) {
63
+ const code = parseInt(abortMatch[1], 10);
64
+ const moduleMatch = msg.match(/Identifier\("([^"]+)"\)/) ?? msg.match(/in '([^']+)'/);
65
+ const fnMatch = msg.match(/function_name:\s*Some\("([^"]+)"\)/);
66
+ const context = `${moduleMatch?.[1] ?? ''}${fnMatch ? `::${fnMatch[1]}` : ''}`.toLowerCase();
67
+ const suffix = moduleMatch
68
+ ? ` [${moduleMatch[1]}${fnMatch ? `::${fnMatch[1]}` : ''}]`
69
+ : '';
70
+ if (context.includes('slippage')) {
71
+ return `Swap slippage too high — price moved during execution${suffix}`;
72
+ }
73
+ if (context.includes('balance::split') || context.includes('balance::ENotEnough')) {
74
+ return `Insufficient on-chain balance${suffix}`;
75
+ }
76
+ const mapped = mapMoveAbortCode(code);
77
+ return `${mapped}${suffix}`;
78
+ }
79
+ return msg;
80
+ }
81
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=errors.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../src/errors.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,48 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { T2000Error, mapWalletError, mapMoveAbortCode } from './errors.js';
3
+ describe('T2000Error', () => {
4
+ it('creates error with correct fields', () => {
5
+ const err = new T2000Error('INSUFFICIENT_BALANCE', 'Not enough', { available: 5 });
6
+ expect(err.code).toBe('INSUFFICIENT_BALANCE');
7
+ expect(err.message).toBe('Not enough');
8
+ expect(err.data?.available).toBe(5);
9
+ expect(err.retryable).toBe(false);
10
+ expect(err.name).toBe('T2000Error');
11
+ });
12
+ it('serializes to JSON', () => {
13
+ const err = new T2000Error('RPC_ERROR', 'timeout', undefined, true);
14
+ const json = err.toJSON();
15
+ expect(json.error).toBe('RPC_ERROR');
16
+ expect(json.retryable).toBe(true);
17
+ });
18
+ it('maps wallet rejection errors', () => {
19
+ const err = mapWalletError(new Error('User rejected the request'));
20
+ expect(err.code).toBe('TRANSACTION_FAILED');
21
+ });
22
+ it('maps insufficient balance errors', () => {
23
+ const err = mapWalletError(new Error('Insufficient gas'));
24
+ expect(err.code).toBe('INSUFFICIENT_BALANCE');
25
+ });
26
+ it('maps unknown errors as retryable', () => {
27
+ const err = mapWalletError(new Error('some random error'));
28
+ expect(err.code).toBe('UNKNOWN');
29
+ expect(err.retryable).toBe(true);
30
+ });
31
+ });
32
+ describe('mapMoveAbortCode', () => {
33
+ it('maps known abort codes', () => {
34
+ expect(mapMoveAbortCode(1)).toContain('paused');
35
+ expect(mapMoveAbortCode(6)).toContain('authorized');
36
+ expect(mapMoveAbortCode(10)).toContain('version');
37
+ });
38
+ it('maps NAVI invalid amount abort code 1503', () => {
39
+ expect(mapMoveAbortCode(1503)).toContain('invalid');
40
+ });
41
+ it('maps Cetus DEX abort code 46001', () => {
42
+ expect(mapMoveAbortCode(46001)).toContain('Swap failed');
43
+ });
44
+ it('handles unknown codes', () => {
45
+ expect(mapMoveAbortCode(999)).toContain('999');
46
+ });
47
+ });
48
+ //# sourceMappingURL=errors.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.js","sourceRoot":"","sources":["../src/errors.test.ts"],"names":[],"mappings":"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"}