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