@clober/v2-sdk 0.0.6 → 0.0.7-5.dev

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 (343) hide show
  1. package/README.md +12 -4
  2. package/dist/cjs/abis/core/book-manager-abi.js +112 -0
  3. package/dist/cjs/abis/core/book-manager-abi.js.map +1 -0
  4. package/dist/cjs/abis/core/book-viewer-abi.js +137 -5
  5. package/dist/cjs/abis/core/book-viewer-abi.js.map +1 -1
  6. package/dist/cjs/abis/core/controller-abi.js +29 -24
  7. package/dist/cjs/abis/core/controller-abi.js.map +1 -1
  8. package/dist/cjs/abis/rebalancer/minter-abi.js +230 -0
  9. package/dist/cjs/abis/rebalancer/minter-abi.js.map +1 -0
  10. package/dist/cjs/abis/rebalancer/mock-swap-abi.js +95 -0
  11. package/dist/cjs/abis/rebalancer/mock-swap-abi.js.map +1 -0
  12. package/dist/cjs/abis/rebalancer/operator-abi.js +375 -0
  13. package/dist/cjs/abis/rebalancer/operator-abi.js.map +1 -0
  14. package/dist/cjs/abis/rebalancer/rebalancer-abi.js +1367 -0
  15. package/dist/cjs/abis/rebalancer/rebalancer-abi.js.map +1 -0
  16. package/dist/cjs/abis/rebalancer/strategy-abi.js +780 -0
  17. package/dist/cjs/abis/rebalancer/strategy-abi.js.map +1 -0
  18. package/dist/cjs/apis/chart-logs.js +163 -0
  19. package/dist/cjs/apis/chart-logs.js.map +1 -0
  20. package/dist/cjs/apis/market.js +40 -21
  21. package/dist/cjs/apis/market.js.map +1 -1
  22. package/dist/cjs/apis/odos.js +100 -0
  23. package/dist/cjs/apis/odos.js.map +1 -0
  24. package/dist/cjs/apis/open-order.js +60 -28
  25. package/dist/cjs/apis/open-order.js.map +1 -1
  26. package/dist/cjs/apis/pool.js +79 -0
  27. package/dist/cjs/apis/pool.js.map +1 -0
  28. package/dist/cjs/apis/strategy.js +30 -0
  29. package/dist/cjs/apis/strategy.js.map +1 -0
  30. package/dist/cjs/approval.js +85 -31
  31. package/dist/cjs/approval.js.map +1 -1
  32. package/dist/cjs/call.js +837 -155
  33. package/dist/cjs/call.js.map +1 -1
  34. package/dist/cjs/constants/addresses.js +50 -1
  35. package/dist/cjs/constants/addresses.js.map +1 -1
  36. package/dist/cjs/constants/bera-bartio-chain.js +30 -0
  37. package/dist/cjs/constants/bera-bartio-chain.js.map +1 -0
  38. package/dist/cjs/constants/chain.js +18 -2
  39. package/dist/cjs/constants/chain.js.map +1 -1
  40. package/dist/cjs/constants/currency.js +56 -3
  41. package/dist/cjs/constants/currency.js.map +1 -1
  42. package/dist/cjs/constants/fee.js +17 -2
  43. package/dist/cjs/constants/fee.js.map +1 -1
  44. package/dist/cjs/constants/permit.js +14 -0
  45. package/dist/cjs/constants/permit.js.map +1 -0
  46. package/dist/cjs/constants/price.js +2 -1
  47. package/dist/cjs/constants/price.js.map +1 -1
  48. package/dist/cjs/constants/subgraph.js +35 -0
  49. package/dist/cjs/constants/subgraph.js.map +1 -0
  50. package/dist/cjs/constants/test-chain.js +50 -0
  51. package/dist/cjs/constants/test-chain.js.map +1 -0
  52. package/dist/cjs/constants/tick.js +6 -0
  53. package/dist/cjs/constants/tick.js.map +1 -0
  54. package/dist/cjs/index.js +1 -1
  55. package/dist/cjs/index.js.map +1 -1
  56. package/dist/cjs/model/book.js +62 -35
  57. package/dist/cjs/model/book.js.map +1 -1
  58. package/dist/cjs/model/chart-log.js +3 -0
  59. package/dist/cjs/model/chart-log.js.map +1 -0
  60. package/dist/cjs/model/market.js +61 -26
  61. package/dist/cjs/model/market.js.map +1 -1
  62. package/dist/cjs/model/pool.js +240 -0
  63. package/dist/cjs/model/pool.js.map +1 -0
  64. package/dist/cjs/type.js +16 -1
  65. package/dist/cjs/type.js.map +1 -1
  66. package/dist/cjs/utils/allowance.js +39 -0
  67. package/dist/cjs/utils/allowance.js.map +1 -0
  68. package/dist/cjs/utils/approval.js +2 -3
  69. package/dist/cjs/utils/approval.js.map +1 -1
  70. package/dist/cjs/utils/bigint.js +13 -0
  71. package/dist/cjs/utils/bigint.js.map +1 -0
  72. package/dist/cjs/utils/book-id.js +7 -7
  73. package/dist/cjs/utils/book-id.js.map +1 -1
  74. package/dist/cjs/utils/build-transaction.js +9 -9
  75. package/dist/cjs/utils/build-transaction.js.map +1 -1
  76. package/dist/cjs/utils/currency.js +95 -11
  77. package/dist/cjs/utils/currency.js.map +1 -1
  78. package/dist/cjs/utils/market.js +1 -1
  79. package/dist/cjs/utils/market.js.map +1 -1
  80. package/dist/cjs/utils/math.js +3 -1
  81. package/dist/cjs/utils/math.js.map +1 -1
  82. package/dist/cjs/utils/open.js +35 -25
  83. package/dist/cjs/utils/open.js.map +1 -1
  84. package/dist/cjs/utils/order.js +115 -0
  85. package/dist/cjs/utils/order.js.map +1 -0
  86. package/dist/cjs/utils/pool-key.js +17 -0
  87. package/dist/cjs/utils/pool-key.js.map +1 -0
  88. package/dist/cjs/utils/pool.js +88 -0
  89. package/dist/cjs/utils/pool.js.map +1 -0
  90. package/dist/cjs/utils/prices.js +40 -5
  91. package/dist/cjs/utils/prices.js.map +1 -1
  92. package/dist/cjs/utils/tick.js +12 -1
  93. package/dist/cjs/utils/tick.js.map +1 -1
  94. package/dist/cjs/utils/unit-size.js +48 -0
  95. package/dist/cjs/utils/unit-size.js.map +1 -0
  96. package/dist/cjs/utils.js +16 -0
  97. package/dist/cjs/utils.js.map +1 -0
  98. package/dist/cjs/view.js +271 -40
  99. package/dist/cjs/view.js.map +1 -1
  100. package/dist/esm/abis/core/book-manager-abi.js +109 -0
  101. package/dist/esm/abis/core/book-manager-abi.js.map +1 -0
  102. package/dist/esm/abis/core/book-viewer-abi.js +137 -5
  103. package/dist/esm/abis/core/book-viewer-abi.js.map +1 -1
  104. package/dist/esm/abis/core/controller-abi.js +29 -24
  105. package/dist/esm/abis/core/controller-abi.js.map +1 -1
  106. package/dist/esm/abis/rebalancer/minter-abi.js +227 -0
  107. package/dist/esm/abis/rebalancer/minter-abi.js.map +1 -0
  108. package/dist/esm/abis/rebalancer/mock-swap-abi.js +92 -0
  109. package/dist/esm/abis/rebalancer/mock-swap-abi.js.map +1 -0
  110. package/dist/esm/abis/rebalancer/operator-abi.js +372 -0
  111. package/dist/esm/abis/rebalancer/operator-abi.js.map +1 -0
  112. package/dist/esm/abis/rebalancer/rebalancer-abi.js +1364 -0
  113. package/dist/esm/abis/rebalancer/rebalancer-abi.js.map +1 -0
  114. package/dist/esm/abis/rebalancer/strategy-abi.js +777 -0
  115. package/dist/esm/abis/rebalancer/strategy-abi.js.map +1 -0
  116. package/dist/esm/apis/chart-logs.js +159 -0
  117. package/dist/esm/apis/chart-logs.js.map +1 -0
  118. package/dist/esm/apis/market.js +41 -22
  119. package/dist/esm/apis/market.js.map +1 -1
  120. package/dist/esm/apis/odos.js +94 -0
  121. package/dist/esm/apis/odos.js.map +1 -0
  122. package/dist/esm/apis/open-order.js +61 -28
  123. package/dist/esm/apis/open-order.js.map +1 -1
  124. package/dist/esm/apis/pool.js +74 -0
  125. package/dist/esm/apis/pool.js.map +1 -0
  126. package/dist/esm/apis/strategy.js +26 -0
  127. package/dist/esm/apis/strategy.js.map +1 -0
  128. package/dist/esm/approval.js +122 -45
  129. package/dist/esm/approval.js.map +1 -1
  130. package/dist/esm/call.js +942 -270
  131. package/dist/esm/call.js.map +1 -1
  132. package/dist/esm/constants/addresses.js +51 -2
  133. package/dist/esm/constants/addresses.js.map +1 -1
  134. package/dist/esm/constants/bera-bartio-chain.js +27 -0
  135. package/dist/esm/constants/bera-bartio-chain.js.map +1 -0
  136. package/dist/esm/constants/chain.js +17 -2
  137. package/dist/esm/constants/chain.js.map +1 -1
  138. package/dist/esm/constants/currency.js +57 -2
  139. package/dist/esm/constants/currency.js.map +1 -1
  140. package/dist/esm/constants/fee.js +17 -2
  141. package/dist/esm/constants/fee.js.map +1 -1
  142. package/dist/esm/constants/permit.js +11 -0
  143. package/dist/esm/constants/permit.js.map +1 -0
  144. package/dist/esm/constants/price.js +1 -0
  145. package/dist/esm/constants/price.js.map +1 -1
  146. package/dist/esm/constants/subgraph.js +31 -0
  147. package/dist/esm/constants/subgraph.js.map +1 -0
  148. package/dist/esm/constants/test-chain.js +47 -0
  149. package/dist/esm/constants/test-chain.js.map +1 -0
  150. package/dist/esm/constants/tick.js +3 -0
  151. package/dist/esm/constants/tick.js.map +1 -0
  152. package/dist/esm/index.js +1 -1
  153. package/dist/esm/index.js.map +1 -1
  154. package/dist/esm/model/book.js +62 -35
  155. package/dist/esm/model/book.js.map +1 -1
  156. package/dist/esm/model/chart-log.js +2 -0
  157. package/dist/esm/model/chart-log.js.map +1 -0
  158. package/dist/esm/model/market.js +63 -28
  159. package/dist/esm/model/market.js.map +1 -1
  160. package/dist/esm/model/pool.js +237 -0
  161. package/dist/esm/model/pool.js.map +1 -0
  162. package/dist/esm/type.js +15 -0
  163. package/dist/esm/type.js.map +1 -1
  164. package/dist/esm/utils/allowance.js +35 -0
  165. package/dist/esm/utils/allowance.js.map +1 -0
  166. package/dist/esm/utils/approval.js +2 -3
  167. package/dist/esm/utils/approval.js.map +1 -1
  168. package/dist/esm/utils/bigint.js +7 -0
  169. package/dist/esm/utils/bigint.js.map +1 -0
  170. package/dist/esm/utils/book-id.js +7 -7
  171. package/dist/esm/utils/book-id.js.map +1 -1
  172. package/dist/esm/utils/build-transaction.js +9 -9
  173. package/dist/esm/utils/build-transaction.js.map +1 -1
  174. package/dist/esm/utils/currency.js +93 -10
  175. package/dist/esm/utils/currency.js.map +1 -1
  176. package/dist/esm/utils/market.js +1 -1
  177. package/dist/esm/utils/market.js.map +1 -1
  178. package/dist/esm/utils/math.js +1 -0
  179. package/dist/esm/utils/math.js.map +1 -1
  180. package/dist/esm/utils/open.js +33 -23
  181. package/dist/esm/utils/open.js.map +1 -1
  182. package/dist/esm/utils/order.js +110 -0
  183. package/dist/esm/utils/order.js.map +1 -0
  184. package/dist/esm/utils/pool-key.js +12 -0
  185. package/dist/esm/utils/pool-key.js.map +1 -0
  186. package/dist/esm/utils/pool.js +84 -0
  187. package/dist/esm/utils/pool.js.map +1 -0
  188. package/dist/esm/utils/prices.js +39 -5
  189. package/dist/esm/utils/prices.js.map +1 -1
  190. package/dist/esm/utils/tick.js +11 -1
  191. package/dist/esm/utils/tick.js.map +1 -1
  192. package/dist/esm/utils/unit-size.js +44 -0
  193. package/dist/esm/utils/unit-size.js.map +1 -0
  194. package/dist/esm/utils.js +4 -0
  195. package/dist/esm/utils.js.map +1 -0
  196. package/dist/esm/view.js +410 -79
  197. package/dist/esm/view.js.map +1 -1
  198. package/dist/tsconfig.build.tsbuildinfo +1 -1
  199. package/dist/types/abis/core/book-manager-abi.d.ts +82 -0
  200. package/dist/types/abis/core/book-manager-abi.d.ts.map +1 -0
  201. package/dist/types/abis/core/book-viewer-abi.d.ts +107 -5
  202. package/dist/types/abis/core/book-viewer-abi.d.ts.map +1 -1
  203. package/dist/types/abis/core/controller-abi.d.ts +23 -19
  204. package/dist/types/abis/core/controller-abi.d.ts.map +1 -1
  205. package/dist/types/abis/rebalancer/minter-abi.d.ts +174 -0
  206. package/dist/types/abis/rebalancer/minter-abi.d.ts.map +1 -0
  207. package/dist/types/abis/rebalancer/mock-swap-abi.d.ts +70 -0
  208. package/dist/types/abis/rebalancer/mock-swap-abi.d.ts.map +1 -0
  209. package/dist/types/abis/rebalancer/operator-abi.d.ts +287 -0
  210. package/dist/types/abis/rebalancer/operator-abi.d.ts.map +1 -0
  211. package/dist/types/abis/rebalancer/rebalancer-abi.d.ts +1056 -0
  212. package/dist/types/abis/rebalancer/rebalancer-abi.d.ts.map +1 -0
  213. package/dist/types/abis/rebalancer/strategy-abi.d.ts +602 -0
  214. package/dist/types/abis/rebalancer/strategy-abi.d.ts.map +1 -0
  215. package/dist/types/apis/chart-logs.d.ts +5 -0
  216. package/dist/types/apis/chart-logs.d.ts.map +1 -0
  217. package/dist/types/apis/market.d.ts +2 -1
  218. package/dist/types/apis/market.d.ts.map +1 -1
  219. package/dist/types/apis/odos.d.ts +28 -0
  220. package/dist/types/apis/odos.d.ts.map +1 -0
  221. package/dist/types/apis/open-order.d.ts +4 -2
  222. package/dist/types/apis/open-order.d.ts.map +1 -1
  223. package/dist/types/apis/pool.d.ts +12 -0
  224. package/dist/types/apis/pool.d.ts.map +1 -0
  225. package/dist/types/apis/strategy.d.ts +5 -0
  226. package/dist/types/apis/strategy.d.ts.map +1 -0
  227. package/dist/types/approval.d.ts +49 -17
  228. package/dist/types/approval.d.ts.map +1 -1
  229. package/dist/types/call.d.ts +311 -133
  230. package/dist/types/call.d.ts.map +1 -1
  231. package/dist/types/constants/addresses.d.ts +4 -0
  232. package/dist/types/constants/addresses.d.ts.map +1 -1
  233. package/dist/types/constants/bera-bartio-chain.d.ts +33 -0
  234. package/dist/types/constants/bera-bartio-chain.d.ts.map +1 -0
  235. package/dist/types/constants/chain.d.ts +7 -2
  236. package/dist/types/constants/chain.d.ts.map +1 -1
  237. package/dist/types/constants/currency.d.ts +6 -0
  238. package/dist/types/constants/currency.d.ts.map +1 -1
  239. package/dist/types/constants/fee.d.ts +7 -2
  240. package/dist/types/constants/fee.d.ts.map +1 -1
  241. package/dist/types/constants/permit.d.ts +10 -0
  242. package/dist/types/constants/permit.d.ts.map +1 -0
  243. package/dist/types/constants/price.d.ts +1 -0
  244. package/dist/types/constants/price.d.ts.map +1 -1
  245. package/dist/types/constants/subgraph.d.ts +5 -0
  246. package/dist/types/constants/subgraph.d.ts.map +1 -0
  247. package/dist/types/constants/test-chain.d.ts +4 -0
  248. package/dist/types/constants/test-chain.d.ts.map +1 -0
  249. package/dist/types/constants/tick.d.ts +3 -0
  250. package/dist/types/constants/tick.d.ts.map +1 -0
  251. package/dist/types/index.d.ts +1 -1
  252. package/dist/types/index.d.ts.map +1 -1
  253. package/dist/types/model/book.d.ts +25 -33
  254. package/dist/types/model/book.d.ts.map +1 -1
  255. package/dist/types/model/chart-log.d.ts +9 -0
  256. package/dist/types/model/chart-log.d.ts.map +1 -0
  257. package/dist/types/model/currency.d.ts +7 -0
  258. package/dist/types/model/currency.d.ts.map +1 -1
  259. package/dist/types/model/depth.d.ts +4 -3
  260. package/dist/types/model/depth.d.ts.map +1 -1
  261. package/dist/types/model/market.d.ts +24 -13
  262. package/dist/types/model/market.d.ts.map +1 -1
  263. package/dist/types/model/open-order.d.ts +20 -27
  264. package/dist/types/model/open-order.d.ts.map +1 -1
  265. package/dist/types/model/pool.d.ts +71 -0
  266. package/dist/types/model/pool.d.ts.map +1 -0
  267. package/dist/types/type.d.ts +112 -6
  268. package/dist/types/type.d.ts.map +1 -1
  269. package/dist/types/utils/allowance.d.ts +3 -0
  270. package/dist/types/utils/allowance.d.ts.map +1 -0
  271. package/dist/types/utils/approval.d.ts +2 -1
  272. package/dist/types/utils/approval.d.ts.map +1 -1
  273. package/dist/types/utils/bigint.d.ts +4 -0
  274. package/dist/types/utils/bigint.d.ts.map +1 -0
  275. package/dist/types/utils/book-id.d.ts +2 -1
  276. package/dist/types/utils/book-id.d.ts.map +1 -1
  277. package/dist/types/utils/build-transaction.d.ts +3 -3
  278. package/dist/types/utils/build-transaction.d.ts.map +1 -1
  279. package/dist/types/utils/currency.d.ts +5 -1
  280. package/dist/types/utils/currency.d.ts.map +1 -1
  281. package/dist/types/utils/math.d.ts +1 -0
  282. package/dist/types/utils/math.d.ts.map +1 -1
  283. package/dist/types/utils/open.d.ts +2 -1
  284. package/dist/types/utils/open.d.ts.map +1 -1
  285. package/dist/types/utils/order.d.ts +10 -0
  286. package/dist/types/utils/order.d.ts.map +1 -0
  287. package/dist/types/utils/pool-key.d.ts +3 -0
  288. package/dist/types/utils/pool-key.d.ts.map +1 -0
  289. package/dist/types/utils/pool.d.ts +11 -0
  290. package/dist/types/utils/pool.d.ts.map +1 -0
  291. package/dist/types/utils/prices.d.ts +13 -2
  292. package/dist/types/utils/prices.d.ts.map +1 -1
  293. package/dist/types/utils/tick.d.ts +1 -0
  294. package/dist/types/utils/tick.d.ts.map +1 -1
  295. package/dist/types/utils/unit-size.d.ts +5 -0
  296. package/dist/types/utils/unit-size.d.ts.map +1 -0
  297. package/dist/types/utils.d.ts +4 -0
  298. package/dist/types/utils.d.ts.map +1 -0
  299. package/dist/types/view.d.ts +309 -51
  300. package/dist/types/view.d.ts.map +1 -1
  301. package/package.json +3 -2
  302. package/dist/cjs/abis/core/params-abi.js +0 -62
  303. package/dist/cjs/abis/core/params-abi.js.map +0 -1
  304. package/dist/cjs/apis/subgraph.js +0 -26
  305. package/dist/cjs/apis/subgraph.js.map +0 -1
  306. package/dist/cjs/constants/client.js +0 -14
  307. package/dist/cjs/constants/client.js.map +0 -1
  308. package/dist/cjs/constants/subgraph-url.js +0 -8
  309. package/dist/cjs/constants/subgraph-url.js.map +0 -1
  310. package/dist/cjs/signature.js +0 -141
  311. package/dist/cjs/signature.js.map +0 -1
  312. package/dist/cjs/utils/decorator.js +0 -13
  313. package/dist/cjs/utils/decorator.js.map +0 -1
  314. package/dist/cjs/utils/unit.js +0 -34
  315. package/dist/cjs/utils/unit.js.map +0 -1
  316. package/dist/esm/abis/core/params-abi.js +0 -59
  317. package/dist/esm/abis/core/params-abi.js.map +0 -1
  318. package/dist/esm/apis/subgraph.js +0 -22
  319. package/dist/esm/apis/subgraph.js.map +0 -1
  320. package/dist/esm/constants/client.js +0 -10
  321. package/dist/esm/constants/client.js.map +0 -1
  322. package/dist/esm/constants/subgraph-url.js +0 -5
  323. package/dist/esm/constants/subgraph-url.js.map +0 -1
  324. package/dist/esm/signature.js +0 -171
  325. package/dist/esm/signature.js.map +0 -1
  326. package/dist/esm/utils/decorator.js +0 -9
  327. package/dist/esm/utils/decorator.js.map +0 -1
  328. package/dist/esm/utils/unit.js +0 -30
  329. package/dist/esm/utils/unit.js.map +0 -1
  330. package/dist/types/abis/core/params-abi.d.ts +0 -21
  331. package/dist/types/abis/core/params-abi.d.ts.map +0 -1
  332. package/dist/types/apis/subgraph.d.ts +0 -3
  333. package/dist/types/apis/subgraph.d.ts.map +0 -1
  334. package/dist/types/constants/client.d.ts +0 -5
  335. package/dist/types/constants/client.d.ts.map +0 -1
  336. package/dist/types/constants/subgraph-url.d.ts +0 -5
  337. package/dist/types/constants/subgraph-url.d.ts.map +0 -1
  338. package/dist/types/signature.d.ts +0 -44
  339. package/dist/types/signature.d.ts.map +0 -1
  340. package/dist/types/utils/decorator.d.ts +0 -6
  341. package/dist/types/utils/decorator.d.ts.map +0 -1
  342. package/dist/types/utils/unit.d.ts +0 -4
  343. package/dist/types/utils/unit.d.ts.map +0 -1
package/dist/esm/call.js CHANGED
@@ -1,65 +1,84 @@
1
- import { formatUnits, isAddressEqual, parseUnits, zeroAddress, zeroHash, } from 'viem';
1
+ import { createPublicClient, formatUnits, getAddress, http, isAddressEqual, parseUnits, zeroAddress, zeroHash, } from 'viem';
2
2
  import { CHAIN_MAP } from './constants/chain';
3
- import { calculateUnit } from './utils/unit';
3
+ import { calculateUnitSize } from './utils/unit-size';
4
4
  import { CONTROLLER_ABI } from './abis/core/controller-abi';
5
5
  import { getDeadlineTimestampInSeconds } from './utils/time';
6
6
  import { buildTransaction } from './utils/build-transaction';
7
7
  import { CONTRACT_ADDRESSES } from './constants/addresses';
8
8
  import { MAKER_DEFAULT_POLICY, TAKER_DEFAULT_POLICY } from './constants/fee';
9
9
  import { fetchMarket } from './apis/market';
10
- import { parsePrice } from './utils/prices';
11
- import { fromPrice, invertPrice } from './utils/tick';
12
- import { getExpectedOutput, getOpenOrders } from './view';
10
+ import { convertHumanReadablePriceToRawPrice, formatPrice, parsePrice, } from './utils/prices';
11
+ import { invertTick, toPrice } from './utils/tick';
12
+ import { getExpectedInput, getExpectedOutput, getQuoteToken } from './view';
13
13
  import { toBookId } from './utils/book-id';
14
14
  import { fetchIsApprovedForAll } from './utils/approval';
15
- import { decorator } from './utils/decorator';
15
+ import { fetchOnChainOrders } from './utils/order';
16
+ import { applyPercent } from './utils/bigint';
17
+ import { fetchPool } from './apis/pool';
18
+ import { REBALANCER_ABI } from './abis/rebalancer/rebalancer-abi';
19
+ import { getExpectedMintResult, getIdealDelta } from './utils/pool';
20
+ import { fetchCallData, fetchQuote } from './apis/odos';
21
+ import { MINTER_ABI } from './abis/rebalancer/minter-abi';
22
+ import { emptyERC20PermitParams } from './constants/permit';
23
+ import { abs } from './utils/math';
24
+ import { toBytes32 } from './utils/pool-key';
25
+ import { OPERATOR_ABI } from './abis/rebalancer/operator-abi';
26
+ import { STRATEGY_ABI } from './abis/rebalancer/strategy-abi';
16
27
  /**
17
28
  * Build a transaction to open a market.
18
29
  *
19
30
  * @param chainId The chain ID of the blockchain.
31
+ * @param userAddress The address of the user.
20
32
  * @param inputToken The address of the input token.
21
33
  * @param outputToken The address of the output token.
22
- * @param options
23
- * @param options.rpcUrl The RPC URL of the blockchain.
34
+ * @param options {@link DefaultWriteContractOptions} options.
24
35
  * @returns A Promise resolving to a transaction object. If the market is already open, returns undefined.
25
36
  * @example
26
37
  * import { openMarket } from '@clober/v2-sdk'
27
38
  *
28
- * const transaction = await openMarket(
29
- * 421614,
30
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
31
- * '0x0000000000000000000000000000000000000000'
32
- * )
39
+ * const transaction = await openMarket({
40
+ * chainId: 421614,
41
+ * userAddress: '0xF8c1869Ecd4df136693C45EcE1b67f85B6bDaE69',
42
+ * inputToken: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
43
+ * outputToken: '0x0000000000000000000000000000000000000000'
44
+ * })
33
45
  */
34
- export const openMarket = decorator(async ({ chainId, inputToken, outputToken, }) => {
35
- const market = await fetchMarket(chainId, [inputToken, outputToken]);
46
+ export const openMarket = async ({ chainId, userAddress, inputToken, outputToken, options, }) => {
47
+ const publicClient = createPublicClient({
48
+ chain: CHAIN_MAP[chainId],
49
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
50
+ });
51
+ const market = await fetchMarket(publicClient, chainId, [inputToken, outputToken], !!(options && options.useSubgraph));
36
52
  const isBid = isAddressEqual(market.quote.address, inputToken);
37
- if ((isBid && !market.bidBookOpen) || (!isBid && !market.askBookOpen)) {
38
- const unit = await calculateUnit(chainId, isBid ? market.quote : market.base);
39
- return buildTransaction(chainId, {
53
+ if ((isBid && !market.bidBook.isOpened) ||
54
+ (!isBid && !market.askBook.isOpened)) {
55
+ const unitSize = await calculateUnitSize(publicClient, chainId, isBid ? market.quote : market.base);
56
+ return buildTransaction(publicClient, {
57
+ chain: CHAIN_MAP[chainId],
40
58
  address: CONTRACT_ADDRESSES[chainId].Controller,
59
+ account: userAddress,
41
60
  abi: CONTROLLER_ABI,
42
61
  functionName: 'open',
43
62
  args: [
44
63
  [
45
64
  {
46
65
  key: {
47
- base: inputToken,
48
- unit,
49
- quote: outputToken,
50
- makerPolicy: MAKER_DEFAULT_POLICY.value,
66
+ base: outputToken,
67
+ unitSize,
68
+ quote: inputToken,
69
+ makerPolicy: MAKER_DEFAULT_POLICY[chainId].value,
51
70
  hooks: zeroAddress,
52
- takerPolicy: TAKER_DEFAULT_POLICY.value,
71
+ takerPolicy: TAKER_DEFAULT_POLICY[chainId].value,
53
72
  },
54
73
  hookData: zeroHash,
55
74
  },
56
75
  ],
57
76
  getDeadlineTimestampInSeconds(),
58
77
  ],
59
- });
78
+ }, options?.gasLimit);
60
79
  }
61
80
  return undefined;
62
- });
81
+ };
63
82
  /**
64
83
  * Places a limit order on the specified chain for trading tokens.
65
84
  *
@@ -69,66 +88,76 @@ export const openMarket = decorator(async ({ chainId, inputToken, outputToken, }
69
88
  * @param {`0x${string}`} outputToken The address of the token to be received as output.
70
89
  * @param {string} amount The amount of input tokens for the order.
71
90
  * @param {string} price The price at which the order should be executed.
72
- * @param {Object} [options] Optional parameters for the limit order.
73
- * @param {PermitSignature} [options.signature] The permit signature for token approval.
91
+ * @param options {@link DefaultWriteContractOptions} options.
92
+ * @param {erc20PermitParam} [options.erc20PermitParam] The permit signature for token approval.
74
93
  * @param {boolean} [options.postOnly] A boolean indicating whether the order is only to be made not taken.
75
- * @param {string} [options.rpcUrl] The RPC URL of the blockchain.
76
- * @returns {Promise<{ transaction: Transaction, result: { make: CurrencyFlow, take: CurrencyFlow } }>}
94
+ * @param {bigint} [options.makeTick] The tick for the make order.
95
+ * @param {bigint} [options.takeLimitTick] The tick for the take order.
96
+ * @param {boolean} [options.roundingUpMakeBid] A boolean indicating whether to round up the make bid.
97
+ * @param {boolean} [options.roundingDownMakeAsk] A boolean indicating whether to round down the make ask.
98
+ * @param {boolean} [options.roundingDownTakenBid] A boolean indicating whether to round down the taken bid.
99
+ * @param {boolean} [options.roundingUpTakenAsk] A boolean indicating whether to round up the taken ask.
100
+ * @returns {Promise<{ transaction: Transaction, result: { make: CurrencyFlow, take: CurrencyFlow, spent: CurrencyFlow }>}
77
101
  * Promise resolving to the transaction object representing the limit order with the result of the order.
78
102
  * @example
79
- * import { signERC20Permit, limitOrder } from '@clober/v2-sdk'
103
+ * import { limitOrder } from '@clober/v2-sdk'
80
104
  * import { privateKeyToAccount } from 'viem/accounts'
81
105
  *
82
- * const signature = await signERC20Permit(
83
- * 421614,
84
- * privateKeyToAccount('0x...'),
85
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
86
- * '100.123'
87
- * )
88
- *
89
- * const { transaction } = await limitOrder(
90
- * 421614,
91
- * '0xF8c1869Ecd4df136693C45EcE1b67f85B6bDaE69
92
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
93
- * '0x0000000000000000000000000000000000000000',
94
- * '100.123', // 100.123 USDC
95
- * '4000.01', // price at 4000.01 (ETH/USDC)
96
- * { signature }
97
- * )
106
+ * const { transaction } = await limitOrder({
107
+ * chainId: 421614,
108
+ * userAddress: '0xF8c1869Ecd4df136693C45EcE1b67f85B6bDaE69
109
+ * inputToken: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
110
+ * outputToken: '0x0000000000000000000000000000000000000000',
111
+ * amount: '100.123', // 100.123 USDC
112
+ * price: '4000.01', // price at 4000.01 (ETH/USDC)
113
+ * })
98
114
  *
99
115
  * @example
100
116
  * import { limitOrder } from '@clober/v2-sdk'
101
117
  *
102
- * const { transaction } = await limitOrder(
103
- * 421614,
104
- * '0xF8c1869Ecd4df136693C45EcE1b67f85B6bDaE69
105
- * '0x0000000000000000000000000000000000000000',
106
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
107
- * '0.13', // 0.13 ETH
108
- * '4000.01', // price at 4000.01 (ETH/USDC)
109
- * )
118
+ * const { transaction } = await limitOrder({
119
+ * chainId: 421614,
120
+ * userAddress: '0xF8c1869Ecd4df136693C45EcE1b67f85B6bDaE69
121
+ * inputToken: '0x0000000000000000000000000000000000000000',
122
+ * outputToken: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
123
+ * amount: '0.13', // 0.13 ETH
124
+ * price: '4000.01', // price at 4000.01 (ETH/USDC)
125
+ * })
110
126
  */
111
- export const limitOrder = decorator(async ({ chainId, userAddress, inputToken, outputToken, amount, price, options, }) => {
112
- const market = await fetchMarket(chainId, [inputToken, outputToken]);
127
+ export const limitOrder = async ({ chainId, userAddress, inputToken, outputToken, amount, price, options, }) => {
128
+ const [roundingUpMakeBid, roundingDownMakeAsk, roundingDownTakenBid, roundingUpTakenAsk,] = [
129
+ options?.roundingUpMakeBid ? options.roundingUpMakeBid : false,
130
+ options?.roundingDownMakeAsk ? options.roundingDownMakeAsk : false,
131
+ options?.roundingDownTakenBid ? options.roundingDownTakenBid : false,
132
+ options?.roundingUpTakenAsk ? options.roundingUpTakenAsk : false,
133
+ ];
134
+ const publicClient = createPublicClient({
135
+ chain: CHAIN_MAP[chainId],
136
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
137
+ });
138
+ const market = await fetchMarket(publicClient, chainId, [inputToken, outputToken], !!(options && options.useSubgraph));
113
139
  const isBid = isAddressEqual(market.quote.address, inputToken);
114
- if ((isBid && !market.bidBookOpen) || (!isBid && !market.askBookOpen)) {
140
+ const [inputCurrency, outputCurrency] = isBid
141
+ ? [market.quote, market.base]
142
+ : [market.base, market.quote];
143
+ if ((isBid && !market.bidBook.isOpened) ||
144
+ (!isBid && !market.askBook.isOpened)) {
115
145
  throw new Error(`
116
146
  Open the market before placing a limit order.
117
147
  import { openMarket } from '@clober/v2-sdk'
118
148
 
119
- const transaction = await openMarket(
120
- ${chainId},
121
- '${inputToken}',
122
- '${outputToken}',
123
- )
149
+ const transaction = await openMarket({
150
+ chainId: ${chainId},
151
+ inputToken: '${inputToken}',
152
+ outputToken: '${outputToken}',
153
+ })
124
154
  `);
125
155
  }
126
- const rawPrice = parsePrice(Number(price), market.quote.decimals, market.base.decimals);
127
- const tick = isBid ? fromPrice(rawPrice) : fromPrice(invertPrice(rawPrice));
156
+ const { roundingDownTick, roundingUpTick } = parsePrice(Number(price), market.quote.decimals, market.base.decimals);
128
157
  const tokensToSettle = [inputToken, outputToken].filter((address) => !isAddressEqual(address, zeroAddress));
129
- const quoteAmount = parseUnits(amount, isBid ? market.quote.decimals : market.base.decimals);
130
- const [unit, { spendAmount, bookId }] = await Promise.all([
131
- calculateUnit(chainId, isBid ? market.quote : market.base),
158
+ const quoteAmount = parseUnits(amount, inputCurrency.decimals);
159
+ const [unitSize, { takenAmount, spentAmount, bookId, events }] = await Promise.all([
160
+ calculateUnitSize(publicClient, chainId, inputCurrency),
132
161
  getExpectedOutput({
133
162
  chainId,
134
163
  inputToken,
@@ -141,24 +170,21 @@ export const limitOrder = decorator(async ({ chainId, userAddress, inputToken, o
141
170
  }),
142
171
  ]);
143
172
  const isETH = isAddressEqual(inputToken, zeroAddress);
144
- const permitParamsList = options?.signature && !isETH
145
- ? [
146
- {
147
- token: inputToken,
148
- permitAmount: quoteAmount,
149
- signature: options.signature,
150
- },
151
- ]
152
- : [];
153
173
  const makeParam = {
154
- id: toBookId(inputToken, outputToken, unit),
155
- tick: Number(tick),
174
+ id: toBookId(chainId, inputToken, outputToken, unitSize),
175
+ tick: options?.makeTick
176
+ ? Number(options.makeTick)
177
+ : Number(isBid
178
+ ? roundingUpMakeBid
179
+ ? roundingUpTick
180
+ : roundingDownTick
181
+ : invertTick(roundingDownMakeAsk ? roundingDownTick : roundingUpTick)),
156
182
  quoteAmount,
157
183
  hookData: zeroHash,
158
184
  };
159
- if (options?.postOnly === true || spendAmount === '0') {
185
+ if (options?.postOnly === true || spentAmount === '0') {
160
186
  return {
161
- transaction: await buildTransaction(chainId, {
187
+ transaction: await buildTransaction(publicClient, {
162
188
  chain: CHAIN_MAP[chainId],
163
189
  account: userAddress,
164
190
  address: CONTRACT_ADDRESSES[chainId].Controller,
@@ -167,21 +193,31 @@ export const limitOrder = decorator(async ({ chainId, userAddress, inputToken, o
167
193
  args: [
168
194
  [makeParam],
169
195
  tokensToSettle,
170
- permitParamsList,
196
+ options?.erc20PermitParam ? [options.erc20PermitParam] : [],
171
197
  getDeadlineTimestampInSeconds(),
172
198
  ],
173
199
  value: isETH ? quoteAmount : 0n,
174
- }),
200
+ }, options?.gasLimit),
175
201
  result: {
176
202
  make: {
177
- amount: formatUnits(quoteAmount, isBid ? market.quote.decimals : market.base.decimals),
178
- currency: isBid ? market.quote : market.base,
203
+ amount: formatUnits(quoteAmount, inputCurrency.decimals),
204
+ currency: inputCurrency,
179
205
  direction: 'in',
206
+ price: formatPrice(isBid
207
+ ? toPrice(BigInt(makeParam.tick))
208
+ : toPrice(invertTick(BigInt(makeParam.tick))), market.quote.decimals, market.base.decimals),
180
209
  },
181
- take: {
210
+ spent: {
182
211
  amount: '0',
183
- currency: isBid ? market.base : market.quote,
212
+ currency: inputCurrency,
213
+ direction: 'in',
214
+ events: [],
215
+ },
216
+ taken: {
217
+ amount: '0',
218
+ currency: outputCurrency,
184
219
  direction: 'out',
220
+ events: [],
185
221
  },
186
222
  },
187
223
  };
@@ -189,7 +225,7 @@ export const limitOrder = decorator(async ({ chainId, userAddress, inputToken, o
189
225
  else {
190
226
  // take and make
191
227
  return {
192
- transaction: await buildTransaction(chainId, {
228
+ transaction: await buildTransaction(publicClient, {
193
229
  chain: CHAIN_MAP[chainId],
194
230
  account: userAddress,
195
231
  address: CONTRACT_ADDRESSES[chainId].Controller,
@@ -200,7 +236,15 @@ export const limitOrder = decorator(async ({ chainId, userAddress, inputToken, o
200
236
  {
201
237
  takeBookId: bookId,
202
238
  makeBookId: makeParam.id,
203
- limitPrice: isBid ? invertPrice(rawPrice) : rawPrice,
239
+ limitPrice: options?.takeLimitTick
240
+ ? toPrice(options.takeLimitTick)
241
+ : toPrice(isBid
242
+ ? invertTick(roundingUpTakenAsk
243
+ ? roundingUpTick
244
+ : roundingDownTick)
245
+ : roundingDownTakenBid
246
+ ? roundingDownTick
247
+ : roundingUpTick),
204
248
  tick: makeParam.tick,
205
249
  quoteAmount,
206
250
  takeHookData: zeroHash,
@@ -208,75 +252,93 @@ export const limitOrder = decorator(async ({ chainId, userAddress, inputToken, o
208
252
  },
209
253
  ],
210
254
  tokensToSettle,
211
- permitParamsList,
255
+ options?.erc20PermitParam ? [options.erc20PermitParam] : [],
212
256
  getDeadlineTimestampInSeconds(),
213
257
  ],
214
258
  value: isETH ? quoteAmount : 0n,
215
- }),
259
+ }, options?.gasLimit),
216
260
  result: {
217
261
  make: {
218
- amount: formatUnits(quoteAmount, isBid ? market.quote.decimals : market.base.decimals),
219
- currency: isBid ? market.quote : market.base,
262
+ amount: formatUnits(quoteAmount - parseUnits(spentAmount, inputCurrency.decimals), inputCurrency.decimals),
263
+ currency: inputCurrency,
264
+ direction: 'in',
265
+ price: formatPrice(isBid
266
+ ? toPrice(BigInt(makeParam.tick))
267
+ : toPrice(invertTick(BigInt(makeParam.tick))), market.quote.decimals, market.base.decimals),
268
+ },
269
+ spent: {
270
+ amount: spentAmount,
271
+ currency: inputCurrency,
220
272
  direction: 'in',
273
+ events: events.map(({ price, spentAmount }) => ({
274
+ price,
275
+ amount: spentAmount,
276
+ })),
221
277
  },
222
- take: {
223
- amount: spendAmount,
224
- currency: isBid ? market.base : market.quote,
278
+ taken: {
279
+ amount: takenAmount,
280
+ currency: outputCurrency,
225
281
  direction: 'out',
282
+ events: events.map(({ price, takenAmount }) => ({
283
+ price,
284
+ amount: takenAmount,
285
+ })),
226
286
  },
227
287
  },
228
288
  };
229
289
  }
230
- });
290
+ };
231
291
  /**
232
292
  * Executes a market order on the specified chain for trading tokens.
293
+ * If only `amountIn` is provided, spend the specified amount of input tokens.
294
+ * If only `amountOut` is provided, take the specified amount of output tokens.
233
295
  *
234
296
  * @param {CHAIN_IDS} chainId The chain ID.
235
297
  * @param {`0x${string}`} userAddress The Ethereum address of the user placing the order.
236
298
  * @param {`0x${string}`} inputToken The address of the token to be used as input.
237
299
  * @param {`0x${string}`} outputToken The address of the token to be received as output.
238
- * @param {string} amount The amount of input tokens for the order.
239
- * @param {Object} [options] Optional parameters for the limit order.
240
- * @param {PermitSignature} [options.signature] The permit signature for token approval.
241
- * @param {string} [options.rpcUrl] The RPC URL of the blockchain.
242
- * @param {string} [options.limitPrice] The upper bound price to tolerate for the market bid, or the lower bound price to tolerate for the market ask.
243
- * if the limit price is not provided, unlimited slippage is allowed.
244
- * @returns {Promise<Transaction>} Promise resolving to the transaction object representing the limit order.
300
+ * @param {string} amountIn The amount of input tokens for the order to spend.
301
+ * @param {string} amountOut The amount of output tokens for the order to take.
302
+ * @param options {@link DefaultWriteContractOptions} options.
303
+ * @param {erc20PermitParam} [options.erc20PermitParam] The permit signature for token approval.
304
+ * @param {number} [options.slippage] The maximum slippage percentage allowed for the order.
305
+ * @param {boolean} [options.roundingDownTakenBid] A boolean indicating whether to round down the taken bid.
306
+ * @param {boolean} [options.roundingUpTakenAsk] A boolean indicating whether to round up the taken ask.
307
+ * if the slippage is not provided, unlimited slippage is allowed.
308
+ * @returns {Promise<{ transaction: Transaction, result: { spent: CurrencyFlow, taken: CurrencyFlow } }>}
309
+ * Promise resolving to the transaction object representing the market order with the result of the order.
245
310
  * @example
246
- * import { signERC20Permit, marketOrder } from '@clober/v2-sdk'
311
+ * import { marketOrder } from '@clober/v2-sdk'
247
312
  * import { privateKeyToAccount } from 'viem/accounts'
248
313
  *
249
- * const signature = await signERC20Permit(
250
- * 421614,
251
- * privateKeyToAccount('0x...'),
252
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
253
- * '100.123'
254
- * )
255
- *
256
- * const transaction = await marketOrder(
257
- * 421614,
258
- * '0xF8c1869Ecd4df136693C45EcE1b67f85B6bDaE69
259
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
260
- * '0x0000000000000000000000000000000000000000',
261
- * '100.123', // 100.123 USDC
262
- * { signature }
263
- * )
264
- *
265
- * @example
266
- * import { marketOrder } from '@clober/v2-sdk'
314
+ * const transaction = await marketOrder({
315
+ * chainId: 421614,
316
+ * userAddress: '0xF8c1869Ecd4df136693C45EcE1b67f85B6bDaE69
317
+ * inputToken: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
318
+ * outputToken: '0x0000000000000000000000000000000000000000',
319
+ * amount: '100.123', // 100.123 USDC
320
+ * options: { erc20PermitParam }
321
+ * })
267
322
  *
268
- * const transaction = await limitOrder(
269
- * 421614,
270
- * '0xF8c1869Ecd4df136693C45EcE1b67f85B6bDaE69
271
- * '0x0000000000000000000000000000000000000000',
272
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
273
- * '0.13', // 0.13 ETH
274
- * )
275
323
  */
276
- export const marketOrder = decorator(async ({ chainId, userAddress, inputToken, outputToken, amount, options, }) => {
277
- const market = await fetchMarket(chainId, [inputToken, outputToken]);
278
- const isBid = isAddressEqual(market.quote.address, inputToken);
279
- if ((isBid && !market.bidBookOpen) || (!isBid && !market.askBookOpen)) {
324
+ export const marketOrder = async ({ chainId, userAddress, inputToken, outputToken, amountIn, amountOut, options, }) => {
325
+ if (!amountIn && !amountOut) {
326
+ throw new Error('Either amountIn or amountOut must be provided');
327
+ }
328
+ else if (amountIn && amountOut) {
329
+ throw new Error('Only one of amountIn or amountOut can be provided');
330
+ }
331
+ const publicClient = createPublicClient({
332
+ chain: CHAIN_MAP[chainId],
333
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
334
+ });
335
+ const market = await fetchMarket(publicClient, chainId, [inputToken, outputToken], !!(options && options.useSubgraph));
336
+ const isTakingBid = isAddressEqual(market.base.address, inputToken);
337
+ const [inputCurrency, outputCurrency] = isTakingBid
338
+ ? [market.base, market.quote]
339
+ : [market.quote, market.base];
340
+ if ((isTakingBid && !market.bidBook.isOpened) ||
341
+ (!isTakingBid && !market.askBook.isOpened)) {
280
342
  throw new Error(`
281
343
  Open the market before placing a market order.
282
344
  import { openMarket } from '@clober/v2-sdk'
@@ -288,51 +350,135 @@ export const marketOrder = decorator(async ({ chainId, userAddress, inputToken,
288
350
  )
289
351
  `);
290
352
  }
291
- const rawLimitPrice = parsePrice(Number(options?.limitPrice ?? '0'), market.quote.decimals, market.base.decimals);
292
353
  const tokensToSettle = [inputToken, outputToken].filter((address) => !isAddressEqual(address, zeroAddress));
293
- const quoteAmount = parseUnits(amount, isBid ? market.quote.decimals : market.base.decimals);
294
- const { bookId, takenAmount } = await getExpectedOutput({
295
- chainId,
296
- inputToken,
297
- outputToken,
298
- amountIn: amount,
299
- options: {
300
- ...options,
301
- // todo: pass limit price
302
- },
303
- });
304
354
  const isETH = isAddressEqual(inputToken, zeroAddress);
305
- const permitParamsList = options?.signature && !isETH
306
- ? [
307
- {
308
- token: inputToken,
309
- permitAmount: quoteAmount,
310
- signature: options.signature,
355
+ if (amountIn && !amountOut) {
356
+ const { bookId, takenAmount, spentAmount, events } = await getExpectedOutput({
357
+ chainId,
358
+ inputToken,
359
+ outputToken,
360
+ amountIn,
361
+ options: {
362
+ ...options,
363
+ // don't need to check limit price for market order
311
364
  },
312
- ]
313
- : [];
314
- return buildTransaction(chainId, {
315
- chain: CHAIN_MAP[chainId],
316
- account: userAddress,
317
- address: CONTRACT_ADDRESSES[chainId].Controller,
318
- abi: CONTROLLER_ABI,
319
- functionName: 'take',
320
- args: [
321
- [
322
- {
323
- id: bookId,
324
- limitPrice: isBid ? invertPrice(rawLimitPrice) : rawLimitPrice,
325
- quoteAmount: takenAmount,
326
- hookData: zeroHash,
365
+ });
366
+ const baseAmount = parseUnits(amountIn, inputCurrency.decimals);
367
+ return {
368
+ transaction: await buildTransaction(publicClient, {
369
+ chain: CHAIN_MAP[chainId],
370
+ account: userAddress,
371
+ address: CONTRACT_ADDRESSES[chainId].Controller,
372
+ abi: CONTROLLER_ABI,
373
+ functionName: 'spend',
374
+ args: [
375
+ [
376
+ {
377
+ id: bookId,
378
+ limitPrice: 0n,
379
+ baseAmount,
380
+ minQuoteAmount: options?.slippage
381
+ ? applyPercent(parseUnits(takenAmount, outputCurrency.decimals), 100 - options.slippage)
382
+ : 0n,
383
+ hookData: zeroHash,
384
+ },
385
+ ],
386
+ tokensToSettle,
387
+ options?.erc20PermitParam ? [options.erc20PermitParam] : [],
388
+ getDeadlineTimestampInSeconds(),
389
+ ],
390
+ value: isETH ? baseAmount : 0n,
391
+ }, options?.gasLimit),
392
+ result: {
393
+ spent: {
394
+ amount: spentAmount,
395
+ currency: inputCurrency,
396
+ direction: 'in',
397
+ events: events.map(({ price, spentAmount }) => ({
398
+ price,
399
+ amount: spentAmount,
400
+ })),
327
401
  },
328
- ],
329
- tokensToSettle,
330
- permitParamsList,
331
- getDeadlineTimestampInSeconds(),
332
- ],
333
- value: isETH ? quoteAmount : 0n,
334
- });
335
- });
402
+ taken: {
403
+ amount: takenAmount,
404
+ currency: outputCurrency,
405
+ direction: 'out',
406
+ events: events.map(({ price, takenAmount }) => ({
407
+ price,
408
+ amount: takenAmount,
409
+ })),
410
+ },
411
+ },
412
+ };
413
+ }
414
+ else if (!amountIn && amountOut) {
415
+ const { bookId, spentAmount, takenAmount, events } = await getExpectedInput({
416
+ chainId,
417
+ inputToken,
418
+ outputToken,
419
+ amountOut,
420
+ options: {
421
+ ...options,
422
+ // don't need to check limit price for market order
423
+ },
424
+ });
425
+ const quoteAmount = parseUnits(amountOut, outputCurrency.decimals);
426
+ const baseAmount = parseUnits(spentAmount, inputCurrency.decimals);
427
+ const maxBaseAmount = options?.erc20PermitParam?.permitAmount ??
428
+ (options?.slippage
429
+ ? applyPercent(baseAmount, 100 + options.slippage)
430
+ : isETH
431
+ ? baseAmount
432
+ : 2n ** 256n - 1n);
433
+ return {
434
+ transaction: await buildTransaction(publicClient, {
435
+ chain: CHAIN_MAP[chainId],
436
+ account: userAddress,
437
+ address: CONTRACT_ADDRESSES[chainId].Controller,
438
+ abi: CONTROLLER_ABI,
439
+ functionName: 'take',
440
+ args: [
441
+ [
442
+ {
443
+ id: bookId,
444
+ limitPrice: 0n,
445
+ quoteAmount,
446
+ maxBaseAmount,
447
+ hookData: zeroHash,
448
+ },
449
+ ],
450
+ tokensToSettle,
451
+ options?.erc20PermitParam ? [options.erc20PermitParam] : [],
452
+ getDeadlineTimestampInSeconds(),
453
+ ],
454
+ value: isETH ? maxBaseAmount : 0n,
455
+ }, options?.gasLimit),
456
+ result: {
457
+ spent: {
458
+ amount: spentAmount,
459
+ currency: inputCurrency,
460
+ direction: 'in',
461
+ events: events.map(({ price, spentAmount }) => ({
462
+ price,
463
+ amount: spentAmount,
464
+ })),
465
+ },
466
+ taken: {
467
+ amount: takenAmount,
468
+ currency: outputCurrency,
469
+ direction: 'out',
470
+ events: events.map(({ price, takenAmount }) => ({
471
+ price,
472
+ amount: takenAmount,
473
+ })),
474
+ },
475
+ },
476
+ };
477
+ }
478
+ else {
479
+ throw new Error('Either amountIn or amountOut must be provided');
480
+ }
481
+ };
336
482
  /**
337
483
  * Claims specified open order for settlement.
338
484
  * [IMPORTANT] Set ApprovalForAll before calling this function.
@@ -340,25 +486,24 @@ export const marketOrder = decorator(async ({ chainId, userAddress, inputToken,
340
486
  * @param {CHAIN_IDS} chainId The chain ID.
341
487
  * @param {`0x${string}`} userAddress The Ethereum address of the user.
342
488
  * @param {string} id An ID representing the open order to be claimed.
343
- * @param {Object} [options] Optional parameters for claiming orders.
344
- * @param {string} [options.rpcUrl] The RPC URL to use for executing the transaction.
489
+ * @param options {@link DefaultWriteContractOptions} options.
345
490
  * @returns {Promise<{ transaction: Transaction, result: CurrencyFlow }>}
346
491
  * Promise resolving to the transaction object representing the claim action with the result of the order.
347
492
  * @throws {Error} Throws an error if no open orders are found for the specified user.
348
493
  * @example
349
494
  * import { getOpenOrders, claimOrders } from '@clober/v2-sdk'
350
495
  *
351
- * const openOrders = await getOpenOrders(
352
- * 421614,
353
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0'
354
- * )
355
- * const transaction = await claimOrders(
356
- * 421614,
357
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
358
- * openOrders.map((order) => order.id)
359
- * )
496
+ * const openOrders = await getOpenOrders({
497
+ * chainId: 421614,
498
+ * userAddress: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0'
499
+ * })
500
+ * const transaction = await claimOrders({
501
+ * chainId: 421614,
502
+ * userAddress: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
503
+ * id: openOrders.map((order) => order.id)
504
+ * })
360
505
  */
361
- export const claimOrder = decorator(async ({ chainId, userAddress, id, options, }) => {
506
+ export const claimOrder = async ({ chainId, userAddress, id, options, }) => {
362
507
  const { transaction, result } = await claimOrders({
363
508
  chainId,
364
509
  userAddress,
@@ -369,7 +514,7 @@ export const claimOrder = decorator(async ({ chainId, userAddress, id, options,
369
514
  transaction,
370
515
  result: result[0],
371
516
  };
372
- });
517
+ };
373
518
  /**
374
519
  * Claims specified open orders for settlement.
375
520
  * [IMPORTANT] Set ApprovalForAll before calling this function.
@@ -377,73 +522,73 @@ export const claimOrder = decorator(async ({ chainId, userAddress, id, options,
377
522
  * @param {CHAIN_IDS} chainId The chain ID.
378
523
  * @param {`0x${string}`} userAddress The Ethereum address of the user.
379
524
  * @param {string[]} ids An array of IDs representing the open orders to be claimed.
380
- * @param {Object} [options] Optional parameters for claiming orders.
381
- * @param {string} [options.rpcUrl] The RPC URL to use for executing the transaction.
525
+ * @param options {@link DefaultWriteContractOptions} options.
382
526
  * @returns {Promise<{ transaction: Transaction, result: CurrencyFlow[] }>}
383
527
  * Promise resolving to the transaction object representing the claim action with the result of the orders.
384
528
  * @throws {Error} Throws an error if no open orders are found for the specified user.
385
529
  * @example
386
530
  * import { getOpenOrders, claimOrders } from '@clober/v2-sdk'
387
531
  *
388
- * const openOrders = await getOpenOrders(
389
- * 421614,
390
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0'
391
- * )
532
+ * const openOrders = await getOpenOrders({
533
+ * chainId: 421614,
534
+ * userAddress: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0'
535
+ * })
392
536
  * const transaction = await claimOrders(
393
- * 421614,
394
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
395
- * openOrders.map((order) => order.id)
537
+ * chainId: 421614,
538
+ * userAddress: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
539
+ * ids: openOrders.map((order) => order.id)
396
540
  * )
397
541
  */
398
- export const claimOrders = decorator(async ({ chainId, userAddress, ids, options, }) => {
399
- const isApprovedForAll = await fetchIsApprovedForAll(chainId, userAddress);
542
+ export const claimOrders = async ({ chainId, userAddress, ids, options, }) => {
543
+ const publicClient = createPublicClient({
544
+ chain: CHAIN_MAP[chainId],
545
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
546
+ });
547
+ const isApprovedForAll = await fetchIsApprovedForAll(publicClient, chainId, userAddress);
400
548
  if (!isApprovedForAll) {
401
549
  throw new Error(`
402
550
  Set ApprovalForAll before calling this function.
403
551
  import { setApprovalOfOpenOrdersForAll } from '@clober/v2-sdk'
404
552
 
405
- const hash = await setApprovalOfOpenOrdersForAll(
406
- ${chainId},
407
- privateKeyToAccount('0x...')
408
- )
553
+ const hash = await setApprovalOfOpenOrdersForAll({
554
+ chainId: ${chainId},
555
+ walletClient, // use viem
556
+ })
409
557
  `);
410
558
  }
411
- const openOrders = (await getOpenOrders({ chainId, userAddress, options: { ...options } })).filter((order) => ids.includes(order.id));
412
- if (openOrders.length === 0) {
413
- throw new Error(`No claimable open orders found for ${userAddress}`);
414
- }
415
- const tokensToSettle = openOrders
416
- .map((order) => [
417
- order.outputCurrency.address,
418
- order.inputCurrency.address,
419
- ])
559
+ const orders = (await fetchOnChainOrders(publicClient, chainId, ids.map((id) => BigInt(id)), !!(options && options.useSubgraph))).filter((order) => isAddressEqual(order.user, userAddress) && order.claimable.value !== '0');
560
+ const tokensToSettle = orders
561
+ .map((order) => [order.inputCurrency.address, order.outputCurrency.address])
420
562
  .flat()
421
563
  .filter((address, index, self) => self.findIndex((c) => isAddressEqual(c, address)) === index)
422
564
  .filter((address) => !isAddressEqual(address, zeroAddress));
423
565
  return {
424
- transaction: await buildTransaction(chainId, {
566
+ transaction: await buildTransaction(publicClient, {
425
567
  chain: CHAIN_MAP[chainId],
426
568
  account: userAddress,
427
569
  address: CONTRACT_ADDRESSES[chainId].Controller,
428
570
  abi: CONTROLLER_ABI,
429
571
  functionName: 'claim',
430
572
  args: [
431
- openOrders.map((order) => ({
432
- id: BigInt(order.id),
573
+ orders.map(({ id }) => ({
574
+ id,
433
575
  hookData: zeroHash,
434
576
  })),
435
577
  tokensToSettle,
436
578
  [],
437
579
  getDeadlineTimestampInSeconds(),
438
580
  ],
439
- }),
440
- result: openOrders.map((order) => ({
441
- currency: order.claimable.currency,
442
- amount: order.claimable.value,
443
- direction: 'out',
444
- })),
581
+ }, options?.gasLimit),
582
+ result: orders.reduce((acc, { claimable: { currency, value } }) => {
583
+ const index = acc.findIndex((c) => isAddressEqual(c.currency.address, currency.address));
584
+ if (index === -1) {
585
+ return [...acc, { currency, amount: value, direction: 'out' }];
586
+ }
587
+ acc[index].amount = (Number(acc[index].amount) + Number(value)).toString();
588
+ return acc;
589
+ }, []),
445
590
  };
446
- });
591
+ };
447
592
  /**
448
593
  * Cancels specified open order if the order is not fully filled.
449
594
  * [IMPORTANT] Set ApprovalForAll before calling this function.
@@ -451,25 +596,24 @@ export const claimOrders = decorator(async ({ chainId, userAddress, ids, options
451
596
  * @param {CHAIN_IDS} chainId The chain ID.
452
597
  * @param {`0x${string}`} userAddress The Ethereum address of the user.
453
598
  * @param {string} id An ID representing the open order to be canceled
454
- * @param {Object} [options] Optional parameters for canceling orders.
455
- * @param {string} [options.rpcUrl] The RPC URL to use for executing the transaction.
599
+ * @param options {@link DefaultWriteContractOptions} options.
456
600
  * @returns {Promise<{ transaction: Transaction, result: CurrencyFlow }>}
457
601
  * Promise resolving to the transaction object representing the cancel action with the result of the order.
458
602
  * @throws {Error} Throws an error if no open orders are found for the specified user.
459
603
  * @example
460
604
  * import { getOpenOrders, cancelOrders } from '@clober/v2-sdk'
461
605
  *
462
- * const openOrders = await getOpenOrders(
463
- * 421614,
464
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0'
465
- * )
466
- * const transaction = await cancelOrders(
467
- * 421614,
468
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
469
- * openOrders.map((order) => order.id)
470
- * )
606
+ * const openOrders = await getOpenOrders({
607
+ * chainId: 421614,
608
+ * userAddress:'0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0'
609
+ * })
610
+ * const transaction = await cancelOrders({
611
+ * chainId: 421614,
612
+ * userAddress: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
613
+ * id: openOrders.map((order) => order.id)
614
+ * })
471
615
  */
472
- export const cancelOrder = decorator(async ({ chainId, userAddress, id, options, }) => {
616
+ export const cancelOrder = async ({ chainId, userAddress, id, options, }) => {
473
617
  const { transaction, result } = await cancelOrders({
474
618
  chainId,
475
619
  userAddress,
@@ -480,7 +624,7 @@ export const cancelOrder = decorator(async ({ chainId, userAddress, id, options,
480
624
  transaction,
481
625
  result: result[0],
482
626
  };
483
- });
627
+ };
484
628
  /**
485
629
  * Cancels specified open orders if orders are not fully filled.
486
630
  * [IMPORTANT] Set ApprovalForAll before calling this function.
@@ -488,59 +632,56 @@ export const cancelOrder = decorator(async ({ chainId, userAddress, id, options,
488
632
  * @param {CHAIN_IDS} chainId The chain ID.
489
633
  * @param {`0x${string}`} userAddress The Ethereum address of the user.
490
634
  * @param {string[]} ids An array of IDs representing the open orders to be canceled.
491
- * @param {Object} [options] Optional parameters for canceling orders.
492
- * @param {string} [options.rpcUrl] The RPC URL to use for executing the transaction.
635
+ * @param options {@link DefaultWriteContractOptions} options.
493
636
  * @returns {Promise<{ transaction: Transaction, result: CurrencyFlow[] }>
494
637
  * Promise resolving to the transaction object representing the cancel action with the result of the orders.
495
638
  * @throws {Error} Throws an error if no open orders are found for the specified user.
496
639
  * @example
497
640
  * import { getOpenOrders, cancelOrders } from '@clober/v2-sdk'
498
641
  *
499
- * const openOrders = await getOpenOrders(
500
- * 421614,
501
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0'
502
- * )
503
- * const transaction = await cancelOrders(
504
- * 421614,
505
- * '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
506
- * openOrders.map((order) => order.id)
507
- * )
642
+ * const openOrders = await getOpenOrders({
643
+ * chainId: 421614,
644
+ * userAddress: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0'
645
+ * })
646
+ * const transaction = await cancelOrders({
647
+ * chainId: 421614,
648
+ * userAddress: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
649
+ * ids: openOrders.map((order) => order.id)
650
+ * })
508
651
  */
509
- export const cancelOrders = decorator(async ({ chainId, userAddress, ids, options, }) => {
510
- const isApprovedForAll = await fetchIsApprovedForAll(chainId, userAddress);
652
+ export const cancelOrders = async ({ chainId, userAddress, ids, options, }) => {
653
+ const publicClient = createPublicClient({
654
+ chain: CHAIN_MAP[chainId],
655
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
656
+ });
657
+ const isApprovedForAll = await fetchIsApprovedForAll(publicClient, chainId, userAddress);
511
658
  if (!isApprovedForAll) {
512
659
  throw new Error(`
513
660
  Set ApprovalForAll before calling this function.
514
661
  import { setApprovalOfOpenOrdersForAll } from '@clober/v2-sdk'
515
662
 
516
- const hash = await setApprovalOfOpenOrdersForAll(
517
- ${chainId},
518
- privateKeyToAccount('0x...')
519
- )
663
+ const hash = await setApprovalOfOpenOrdersForAll({
664
+ chainId: ${chainId},
665
+ walletClient, // use viem
666
+ })
520
667
  `);
521
668
  }
522
- const openOrders = (await getOpenOrders({ chainId, userAddress, options: { ...options } })).filter((order) => ids.includes(order.id) && order.claimable.value !== '0');
523
- if (openOrders.length === 0) {
524
- throw new Error(`No cancelable open orders found for ${userAddress}`);
525
- }
526
- const tokensToSettle = openOrders
527
- .map((order) => [
528
- order.outputCurrency.address,
529
- order.inputCurrency.address,
530
- ])
669
+ const orders = (await fetchOnChainOrders(publicClient, chainId, ids.map((id) => BigInt(id)), !!(options && options.useSubgraph))).filter((order) => isAddressEqual(order.user, userAddress) && order.cancelable.value !== '0');
670
+ const tokensToSettle = orders
671
+ .map((order) => [order.inputCurrency.address, order.outputCurrency.address])
531
672
  .flat()
532
673
  .filter((address, index, self) => self.findIndex((c) => isAddressEqual(c, address)) === index)
533
674
  .filter((address) => !isAddressEqual(address, zeroAddress));
534
675
  return {
535
- transaction: await buildTransaction(chainId, {
676
+ transaction: await buildTransaction(publicClient, {
536
677
  chain: CHAIN_MAP[chainId],
537
678
  account: userAddress,
538
679
  address: CONTRACT_ADDRESSES[chainId].Controller,
539
680
  abi: CONTROLLER_ABI,
540
681
  functionName: 'cancel',
541
682
  args: [
542
- openOrders.map((order) => ({
543
- id: BigInt(order.id),
683
+ orders.map(({ id }) => ({
684
+ id,
544
685
  leftQuoteAmount: 0n,
545
686
  hookData: zeroHash,
546
687
  })),
@@ -548,12 +689,543 @@ export const cancelOrders = decorator(async ({ chainId, userAddress, ids, option
548
689
  [],
549
690
  getDeadlineTimestampInSeconds(),
550
691
  ],
551
- }),
552
- result: openOrders.map((order) => ({
553
- currency: order.cancelable.currency,
554
- amount: order.cancelable.value,
555
- direction: 'out',
556
- })),
692
+ }, options?.gasLimit),
693
+ result: orders.reduce((acc, { cancelable: { currency, value } }) => {
694
+ const index = acc.findIndex((c) => isAddressEqual(c.currency.address, currency.address));
695
+ if (index === -1) {
696
+ return [...acc, { currency, amount: value, direction: 'out' }];
697
+ }
698
+ acc[index].amount = (Number(acc[index].amount) + Number(value)).toString();
699
+ return acc;
700
+ }, []),
701
+ };
702
+ };
703
+ /**
704
+ * Build a transaction to open a pool,
705
+ *
706
+ * @param chainId The chain ID of the blockchain.
707
+ * @param userAddress The address of the user.
708
+ * @param inputToken The address of the input token.
709
+ * @param outputToken The address of the output token.
710
+ * @param options {@link DefaultWriteContractOptions} options.
711
+ * @returns A Promise resolving to a transaction object. If the market is already open, returns undefined.
712
+ * @example
713
+ * import { openPool } from '@clober/v2-sdk'
714
+ *
715
+ * const transaction = await openPool({
716
+ * chainId: 421614,
717
+ * userAddress: '0xF8c1869Ecd4df136693C45EcE1b67f85B6bDaE69',
718
+ * inputToken: '0x00bfd44e79fb7f6dd5887a9426c8ef85a0cd23e0',
719
+ * outputToken: '0x0000000000000000000000000000000000000000',
720
+ * salt: '0x0000000000000000000000000000000000000000000000000000000000000000',
721
+ * })
722
+ */
723
+ export const openPool = async ({ chainId, userAddress, tokenA, tokenB, salt, options, }) => {
724
+ const publicClient = createPublicClient({
725
+ chain: CHAIN_MAP[chainId],
726
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
727
+ });
728
+ const pool = await fetchPool(publicClient, chainId, [tokenA, tokenB], salt, !!(options && options.useSubgraph));
729
+ if (!pool.isOpened) {
730
+ return buildTransaction(publicClient, {
731
+ chain: CHAIN_MAP[chainId],
732
+ address: CONTRACT_ADDRESSES[chainId].Rebalancer,
733
+ account: userAddress,
734
+ abi: REBALANCER_ABI,
735
+ functionName: 'open',
736
+ args: [
737
+ {
738
+ base: pool.market.bidBook.base.address,
739
+ unitSize: pool.market.bidBook.unitSize,
740
+ quote: pool.market.bidBook.quote.address,
741
+ makerPolicy: MAKER_DEFAULT_POLICY[chainId].value,
742
+ hooks: zeroAddress,
743
+ takerPolicy: TAKER_DEFAULT_POLICY[chainId].value,
744
+ },
745
+ {
746
+ base: pool.market.askBook.base.address,
747
+ unitSize: pool.market.askBook.unitSize,
748
+ quote: pool.market.askBook.quote.address,
749
+ makerPolicy: MAKER_DEFAULT_POLICY[chainId].value,
750
+ hooks: zeroAddress,
751
+ takerPolicy: TAKER_DEFAULT_POLICY[chainId].value,
752
+ },
753
+ toBytes32(salt),
754
+ CONTRACT_ADDRESSES[chainId].Strategy,
755
+ ],
756
+ }, options?.gasLimit);
757
+ }
758
+ return undefined;
759
+ };
760
+ export const addLiquidity = async ({ chainId, userAddress, token0, token1, salt, amount0, amount1, options, }) => {
761
+ if (isAddressEqual(token0, zeroAddress) ||
762
+ isAddressEqual(token1, zeroAddress)) {
763
+ throw new Error('ETH is not supported for adding liquidity');
764
+ }
765
+ const publicClient = createPublicClient({
766
+ chain: CHAIN_MAP[chainId],
767
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
768
+ });
769
+ const pool = await fetchPool(publicClient, chainId, [token0, token1], salt, !!(options && options.useSubgraph));
770
+ if (!pool.isOpened) {
771
+ throw new Error(`
772
+ Open the pool before adding liquidity.
773
+ import { openPool } from '@clober/v2-sdk'
774
+
775
+ const transaction = await openPool({
776
+ chainId: ${chainId},
777
+ tokenA: '${token0}',
778
+ tokenB: '${token1}',
779
+ salt: '0x0000000000000000000000000000000000000000000000000000000000000000',
780
+ })
781
+ `);
782
+ }
783
+ const [amountAOrigin, amountBOrigin] = isAddressEqual(pool.currencyA.address, getAddress(token0))
784
+ ? [
785
+ parseUnits(amount0 ?? '0', pool.currencyA.decimals),
786
+ parseUnits(amount1 ?? '0', pool.currencyB.decimals),
787
+ ]
788
+ : [
789
+ parseUnits(amount1 ?? '0', pool.currencyA.decimals),
790
+ parseUnits(amount0 ?? '0', pool.currencyB.decimals),
791
+ ];
792
+ let [amountA, amountB] = [amountAOrigin, amountBOrigin];
793
+ const tokenAPermitParams = isAddressEqual(pool.currencyA.address, getAddress(token0))
794
+ ? options?.token0PermitParams ?? emptyERC20PermitParams
795
+ : options?.token1PermitParams ?? emptyERC20PermitParams;
796
+ const tokenBPermitParams = isAddressEqual(pool.currencyA.address, getAddress(token0))
797
+ ? options?.token1PermitParams ?? emptyERC20PermitParams
798
+ : options?.token0PermitParams ?? emptyERC20PermitParams;
799
+ let disableSwap = !!(options && options.disableSwap);
800
+ if (pool.totalSupply === 0n ||
801
+ (pool.liquidityA === 0n && pool.liquidityB === 0n)) {
802
+ disableSwap = true;
803
+ }
804
+ const slippageLimitPercent = options?.slippage ?? 2;
805
+ const swapParams = {
806
+ inCurrency: zeroAddress,
807
+ amount: 0n,
808
+ data: '0x',
809
+ };
810
+ if (!disableSwap) {
811
+ const currencyBPerCurrencyA = options?.testnetPrice
812
+ ? isAddressEqual(getQuoteToken({
813
+ chainId,
814
+ token0,
815
+ token1,
816
+ }), pool.currencyA.address)
817
+ ? 1 / Number(options.testnetPrice)
818
+ : Number(options.testnetPrice)
819
+ : undefined;
820
+ const swapAmountA = parseUnits('1', pool.currencyA.decimals);
821
+ const { amountOut: swapAmountB } = await fetchQuote({
822
+ chainId,
823
+ amountIn: swapAmountA,
824
+ tokenIn: pool.currencyA,
825
+ tokenOut: pool.currencyB,
826
+ slippageLimitPercent: 20,
827
+ userAddress: CONTRACT_ADDRESSES[chainId].Minter,
828
+ testnetPrice: currencyBPerCurrencyA,
829
+ });
830
+ const { deltaA, deltaB } = getIdealDelta(amountA, amountB, pool.liquidityA, pool.liquidityB, swapAmountA, swapAmountB);
831
+ if (deltaA < 0n) {
832
+ swapParams.inCurrency = pool.currencyA.address;
833
+ swapParams.amount = -deltaA;
834
+ const { amountOut: actualDeltaB, data: calldata } = await fetchCallData({
835
+ chainId,
836
+ amountIn: swapParams.amount,
837
+ tokenIn: pool.currencyA,
838
+ tokenOut: pool.currencyB,
839
+ slippageLimitPercent,
840
+ userAddress: CONTRACT_ADDRESSES[chainId].Minter,
841
+ testnetPrice: currencyBPerCurrencyA,
842
+ });
843
+ swapParams.data = calldata;
844
+ amountA += deltaA;
845
+ amountB += actualDeltaB;
846
+ }
847
+ else if (deltaB < 0n) {
848
+ swapParams.inCurrency = pool.currencyB.address;
849
+ swapParams.amount = -deltaB;
850
+ const { amountOut: actualDeltaA, data: calldata } = await fetchCallData({
851
+ chainId,
852
+ amountIn: swapParams.amount,
853
+ tokenIn: pool.currencyB,
854
+ tokenOut: pool.currencyA,
855
+ slippageLimitPercent,
856
+ userAddress: CONTRACT_ADDRESSES[chainId].Minter,
857
+ testnetPrice: currencyBPerCurrencyA
858
+ ? 1 / currencyBPerCurrencyA
859
+ : undefined,
860
+ });
861
+ swapParams.data = calldata;
862
+ amountA += actualDeltaA;
863
+ amountB += deltaB;
864
+ }
865
+ }
866
+ const { mintAmount, inAmountA, inAmountB } = getExpectedMintResult(pool.totalSupply, pool.liquidityA, pool.liquidityB, amountA, amountB, pool.currencyA, pool.currencyB);
867
+ if (mintAmount === 0n) {
868
+ return {
869
+ transaction: undefined,
870
+ result: {
871
+ currencyA: {
872
+ currency: pool.currencyA,
873
+ amount: '0',
874
+ direction: 'in',
875
+ },
876
+ currencyB: {
877
+ currency: pool.currencyB,
878
+ amount: '0',
879
+ direction: 'in',
880
+ },
881
+ lpCurrency: {
882
+ currency: pool.currencyLp,
883
+ amount: '0',
884
+ direction: 'out',
885
+ },
886
+ },
887
+ };
888
+ }
889
+ const minMintAmount = applyPercent(mintAmount, 100 - slippageLimitPercent);
890
+ const transaction = await buildTransaction(publicClient, {
891
+ chain: CHAIN_MAP[chainId],
892
+ account: userAddress,
893
+ address: CONTRACT_ADDRESSES[chainId].Minter,
894
+ abi: MINTER_ABI,
895
+ functionName: 'mint',
896
+ args: [
897
+ pool.key,
898
+ amountAOrigin,
899
+ amountBOrigin,
900
+ minMintAmount,
901
+ {
902
+ permitAmount: tokenAPermitParams.permitAmount,
903
+ signature: tokenAPermitParams.signature,
904
+ },
905
+ {
906
+ permitAmount: tokenBPermitParams.permitAmount,
907
+ signature: tokenBPermitParams.signature,
908
+ },
909
+ swapParams,
910
+ ],
911
+ }, options?.gasLimit);
912
+ const currencyARefund = amountA - inAmountA;
913
+ const currencyBRefund = amountB - inAmountB;
914
+ const currencyAResultAmount = amountAOrigin - currencyARefund;
915
+ const currencyBResultAmount = amountBOrigin - currencyBRefund;
916
+ return {
917
+ transaction,
918
+ result: {
919
+ currencyA: {
920
+ currency: pool.currencyA,
921
+ amount: formatUnits(abs(currencyAResultAmount), pool.currencyA.decimals),
922
+ direction: currencyAResultAmount >= 0 ? 'in' : 'out',
923
+ },
924
+ currencyB: {
925
+ currency: pool.currencyB,
926
+ amount: formatUnits(abs(currencyBResultAmount), pool.currencyB.decimals),
927
+ direction: currencyBResultAmount >= 0 ? 'in' : 'out',
928
+ },
929
+ lpCurrency: {
930
+ currency: pool.currencyLp,
931
+ amount: formatUnits(mintAmount, pool.currencyLp.decimals),
932
+ direction: 'out',
933
+ },
934
+ },
557
935
  };
558
- });
936
+ };
937
+ // @dev: Withdraw amount calculation logic is based on the contract code.
938
+ export const removeLiquidity = async ({ chainId, userAddress, token0, token1, salt, amount, options, }) => {
939
+ const publicClient = createPublicClient({
940
+ chain: CHAIN_MAP[chainId],
941
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
942
+ });
943
+ const pool = await fetchPool(publicClient, chainId, [token0, token1], salt, !!(options && options.useSubgraph));
944
+ if (!pool.isOpened) {
945
+ throw new Error(`
946
+ Open the pool before removing liquidity.
947
+ import { openPool } from '@clober/v2-sdk'
948
+
949
+ const transaction = await openPool({
950
+ chainId: ${chainId},
951
+ tokenA: '${token0}',
952
+ tokenB: '${token1}',
953
+ salt: '0x0000000000000000000000000000000000000000000000000000000000000000',
954
+ })
955
+ `);
956
+ }
957
+ const burnAmount = parseUnits(amount, pool.currencyLp.decimals);
958
+ const slippageLimitPercent = options?.slippage ?? 2;
959
+ const withdrawAmountA = (burnAmount * pool.liquidityA) / pool.totalSupply;
960
+ const withdrawAmountB = (burnAmount * pool.liquidityB) / pool.totalSupply;
961
+ const minWithdrawAmountA = applyPercent(withdrawAmountA, 100 - slippageLimitPercent);
962
+ const minWithdrawAmountB = applyPercent(withdrawAmountB, 100 - slippageLimitPercent);
963
+ if (burnAmount === 0n) {
964
+ return {
965
+ transaction: undefined,
966
+ result: {
967
+ currencyA: {
968
+ currency: pool.currencyA,
969
+ amount: '0',
970
+ direction: 'out',
971
+ },
972
+ currencyB: {
973
+ currency: pool.currencyB,
974
+ amount: '0',
975
+ direction: 'out',
976
+ },
977
+ lpCurrency: {
978
+ currency: pool.currencyLp,
979
+ amount: '0',
980
+ direction: 'in',
981
+ },
982
+ },
983
+ };
984
+ }
985
+ const transaction = await buildTransaction(publicClient, {
986
+ chain: CHAIN_MAP[chainId],
987
+ account: userAddress,
988
+ address: CONTRACT_ADDRESSES[chainId].Rebalancer,
989
+ abi: REBALANCER_ABI,
990
+ functionName: 'burn',
991
+ args: [pool.key, burnAmount, minWithdrawAmountA, minWithdrawAmountB],
992
+ }, options?.gasLimit);
993
+ return {
994
+ transaction,
995
+ result: {
996
+ currencyA: {
997
+ currency: pool.currencyA,
998
+ amount: formatUnits(withdrawAmountA, pool.currencyA.decimals),
999
+ direction: 'out',
1000
+ },
1001
+ currencyB: {
1002
+ currency: pool.currencyB,
1003
+ amount: formatUnits(withdrawAmountB, pool.currencyB.decimals),
1004
+ direction: 'out',
1005
+ },
1006
+ lpCurrency: {
1007
+ currency: pool.currencyLp,
1008
+ amount: amount,
1009
+ direction: 'in',
1010
+ },
1011
+ },
1012
+ };
1013
+ };
1014
+ export const refillOrder = async ({ chainId, userAddress, token0, token1, salt, options, }) => {
1015
+ const publicClient = createPublicClient({
1016
+ chain: CHAIN_MAP[chainId],
1017
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
1018
+ });
1019
+ const pool = options?.pool
1020
+ ? options.pool
1021
+ : (await fetchPool(publicClient, chainId, [token0, token1], salt, !!(options && options.useSubgraph))).toJson();
1022
+ if (!pool.isOpened) {
1023
+ throw new Error(`
1024
+ Open the pool before rebalancing pool.
1025
+ import { openPool } from '@clober/v2-sdk'
1026
+
1027
+ const transaction = await openPool({
1028
+ chainId: ${chainId},
1029
+ tokenA: '${token0}',
1030
+ tokenB: '${token1}',
1031
+ salt: '0x0000000000000000000000000000000000000000000000000000000000000000',
1032
+ })
1033
+ `);
1034
+ }
1035
+ return buildTransaction(publicClient, {
1036
+ chain: CHAIN_MAP[chainId],
1037
+ account: userAddress,
1038
+ address: CONTRACT_ADDRESSES[chainId].Rebalancer,
1039
+ abi: REBALANCER_ABI,
1040
+ functionName: 'rebalance',
1041
+ args: [pool.key],
1042
+ }, options?.gasLimit, options?.gasPriceLimit);
1043
+ };
1044
+ export const adjustOrderPrice = async ({ chainId, userAddress, token0, token1, salt, oraclePrice, bidPrice, askPrice, alpha, options, }) => {
1045
+ if (Number(alpha) <= 0 || Number(alpha) > 1) {
1046
+ throw new Error('Alpha value must be in the range (0, 1]');
1047
+ }
1048
+ if (Number(bidPrice) <= 0 || Number(askPrice) <= 0) {
1049
+ throw new Error('Price must be greater than 0');
1050
+ }
1051
+ if (Number(bidPrice) >= Number(askPrice)) {
1052
+ throw new Error('Bid price must be less than ask price');
1053
+ }
1054
+ const publicClient = createPublicClient({
1055
+ chain: CHAIN_MAP[chainId],
1056
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
1057
+ });
1058
+ const pool = options?.pool
1059
+ ? options.pool
1060
+ : (await fetchPool(publicClient, chainId, [token0, token1], salt, !!(options && options.useSubgraph))).toJson();
1061
+ if (!pool.isOpened) {
1062
+ throw new Error(`
1063
+ Open the pool before updating strategy price.
1064
+ import { openPool } from '@clober/v2-sdk'
1065
+
1066
+ const transaction = await openPool({
1067
+ chainId: ${chainId},
1068
+ tokenA: '${token0}',
1069
+ tokenB: '${token1}',
1070
+ salt: '0x0000000000000000000000000000000000000000000000000000000000000000',
1071
+ })
1072
+ `);
1073
+ }
1074
+ const [roundingUpBidPrice, roundingUpAskPrice] = [
1075
+ options?.roundingUpBidPrice ? options.roundingUpBidPrice : false,
1076
+ options?.roundingUpAskPrice ? options.roundingUpAskPrice : false,
1077
+ ];
1078
+ const { roundingDownTick: roundingDownTickA, roundingUpTick: roundingUpTickA, } = parsePrice(Number(bidPrice), pool.currencyA.decimals, pool.currencyB.decimals);
1079
+ const { roundingDownTick: roundingDownTickB, roundingUpTick: roundingUpTickB, } = parsePrice(Number(askPrice), pool.currencyA.decimals, pool.currencyB.decimals);
1080
+ const oracleRawPrice = convertHumanReadablePriceToRawPrice(Number(oraclePrice), pool.currencyA.decimals, pool.currencyB.decimals);
1081
+ const tickA = options?.bidTick
1082
+ ? Number(options.bidTick)
1083
+ : Number(roundingUpBidPrice ? roundingUpTickA : roundingDownTickA);
1084
+ const tickB = options?.askTick
1085
+ ? Number(options.askTick)
1086
+ : Number(invertTick(roundingUpAskPrice ? roundingUpTickB : roundingDownTickB));
1087
+ const alphaRaw = parseUnits(alpha, 6);
1088
+ return buildTransaction(publicClient, {
1089
+ chain: CHAIN_MAP[chainId],
1090
+ account: userAddress,
1091
+ address: CONTRACT_ADDRESSES[chainId].Operator,
1092
+ abi: OPERATOR_ABI,
1093
+ functionName: 'updatePrice',
1094
+ args: [pool.key, oracleRawPrice, tickA, tickB, alphaRaw],
1095
+ }, options?.gasLimit, options?.gasPriceLimit);
1096
+ };
1097
+ export const setStrategyConfig = async ({ chainId, userAddress, token0, token1, salt, config, options, }) => {
1098
+ // validate config
1099
+ if (Number(config.referenceThreshold) < 0 ||
1100
+ Number(config.referenceThreshold) > 1) {
1101
+ throw new Error('Reference threshold must be in the range [0, 1]');
1102
+ }
1103
+ if (Number(config.rebalanceThreshold) < 0 ||
1104
+ Number(config.rebalanceThreshold) > 1) {
1105
+ throw new Error('Rebalance threshold must be in the range [0, 1]');
1106
+ }
1107
+ if (Number(config.priceThresholdA) < 0 ||
1108
+ Number(config.priceThresholdA) > 1 ||
1109
+ Number(config.priceThresholdB) < 0 ||
1110
+ Number(config.priceThresholdB) > 1) {
1111
+ throw new Error('Price threshold must be in the range [0, 1]');
1112
+ }
1113
+ if (Number(config.rateA) < 0 ||
1114
+ Number(config.rateA) > 1 ||
1115
+ Number(config.rateB) < 0 ||
1116
+ Number(config.rateB) > 1) {
1117
+ throw new Error('Rate must be in the range [0, 1]');
1118
+ }
1119
+ if (Number(config.minRateA) < 0 ||
1120
+ Number(config.minRateA) > 1 ||
1121
+ Number(config.minRateB) < 0 ||
1122
+ Number(config.minRateB) > 1) {
1123
+ throw new Error('Min rate must be in the range [0, 1]');
1124
+ }
1125
+ if (Number(config.minRateA) > Number(config.rateA) ||
1126
+ Number(config.minRateB) > Number(config.rateB)) {
1127
+ throw new Error('Min rate must be less or equal to rate');
1128
+ }
1129
+ const publicClient = createPublicClient({
1130
+ chain: CHAIN_MAP[chainId],
1131
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
1132
+ });
1133
+ const pool = await fetchPool(publicClient, chainId, [token0, token1], salt, !!(options && options.useSubgraph));
1134
+ if (!pool.isOpened) {
1135
+ throw new Error(`
1136
+ Open the pool before set strategy config.
1137
+ import { openPool } from '@clober/v2-sdk'
1138
+
1139
+ const transaction = await openPool({
1140
+ chainId: ${chainId},
1141
+ tokenA: '${token0}',
1142
+ tokenB: '${token1}',
1143
+ })
1144
+ `);
1145
+ }
1146
+ const configRaw = {
1147
+ referenceThreshold: parseUnits(config.referenceThreshold, 6),
1148
+ rebalanceThreshold: parseUnits(config.rebalanceThreshold, 6),
1149
+ rateA: parseUnits(config.rateA, 6),
1150
+ rateB: parseUnits(config.rateB, 6),
1151
+ minRateA: parseUnits(config.minRateA, 6),
1152
+ minRateB: parseUnits(config.minRateB, 6),
1153
+ priceThresholdA: parseUnits(config.priceThresholdA, 6),
1154
+ priceThresholdB: parseUnits(config.priceThresholdB, 6),
1155
+ };
1156
+ return buildTransaction(publicClient, {
1157
+ chain: CHAIN_MAP[chainId],
1158
+ account: userAddress,
1159
+ address: CONTRACT_ADDRESSES[chainId].Strategy,
1160
+ abi: STRATEGY_ABI,
1161
+ functionName: 'setConfig',
1162
+ args: [pool.key, configRaw],
1163
+ }, options?.gasLimit);
1164
+ };
1165
+ export const pausePool = async ({ chainId, userAddress, token0, token1, salt, options, }) => {
1166
+ const publicClient = createPublicClient({
1167
+ chain: CHAIN_MAP[chainId],
1168
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
1169
+ });
1170
+ const pool = options?.pool
1171
+ ? options.pool
1172
+ : (await fetchPool(publicClient, chainId, [token0, token1], salt, !!(options && options.useSubgraph))).toJson();
1173
+ if (!pool.isOpened) {
1174
+ throw new Error(`
1175
+ Open the pool before trying pause.
1176
+ import { openPool } from '@clober/v2-sdk'
1177
+
1178
+ const transaction = await openPool({
1179
+ chainId: ${chainId},
1180
+ tokenA: '${token0}',
1181
+ tokenB: '${token1}',
1182
+ salt: '0x0000000000000000000000000000000000000000000000000000000000000000',
1183
+ })
1184
+ `);
1185
+ }
1186
+ if (pool.paused) {
1187
+ return undefined;
1188
+ }
1189
+ return buildTransaction(publicClient, {
1190
+ chain: CHAIN_MAP[chainId],
1191
+ account: userAddress,
1192
+ address: CONTRACT_ADDRESSES[chainId].Rebalancer,
1193
+ abi: REBALANCER_ABI,
1194
+ functionName: 'pause',
1195
+ args: [pool.key],
1196
+ }, options?.gasLimit, options?.gasPriceLimit);
1197
+ };
1198
+ export const resumePool = async ({ chainId, userAddress, token0, token1, salt, options, }) => {
1199
+ const publicClient = createPublicClient({
1200
+ chain: CHAIN_MAP[chainId],
1201
+ transport: options?.rpcUrl ? http(options.rpcUrl) : http(),
1202
+ });
1203
+ const pool = options?.pool
1204
+ ? options.pool
1205
+ : (await fetchPool(publicClient, chainId, [token0, token1], salt, !!(options && options.useSubgraph))).toJson();
1206
+ if (!pool.isOpened) {
1207
+ throw new Error(`
1208
+ Open the pool before trying resume.
1209
+ import { openPool } from '@clober/v2-sdk'
1210
+
1211
+ const transaction = await openPool({
1212
+ chainId: ${chainId},
1213
+ tokenA: '${token0}',
1214
+ tokenB: '${token1}',
1215
+ salt: '0x0000000000000000000000000000000000000000000000000000000000000000',
1216
+ })
1217
+ `);
1218
+ }
1219
+ if (!pool.paused) {
1220
+ return undefined;
1221
+ }
1222
+ return buildTransaction(publicClient, {
1223
+ chain: CHAIN_MAP[chainId],
1224
+ account: userAddress,
1225
+ address: CONTRACT_ADDRESSES[chainId].Rebalancer,
1226
+ abi: REBALANCER_ABI,
1227
+ functionName: 'resume',
1228
+ args: [pool.key],
1229
+ }, options?.gasLimit, options?.gasPriceLimit);
1230
+ };
559
1231
  //# sourceMappingURL=call.js.map