@unionlabs/payments 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (393) hide show
  1. package/Abi/package.json +6 -0
  2. package/Attestor/package.json +6 -0
  3. package/Constants/package.json +6 -0
  4. package/Domain/package.json +6 -0
  5. package/Error/package.json +6 -0
  6. package/EvmPublicClient/package.json +6 -0
  7. package/EvmWalletClient/package.json +6 -0
  8. package/Payment/package.json +6 -0
  9. package/PaymentError/package.json +6 -0
  10. package/Prover/package.json +6 -0
  11. package/PublicClient/package.json +6 -0
  12. package/README.md +1 -0
  13. package/Schema/package.json +6 -0
  14. package/Utils/package.json +6 -0
  15. package/WalletClient/package.json +6 -0
  16. package/attestation/package.json +6 -0
  17. package/cli/commands/balance/package.json +6 -0
  18. package/cli/commands/deposit/package.json +6 -0
  19. package/cli/commands/export-verifier/package.json +6 -0
  20. package/cli/commands/generate/package.json +6 -0
  21. package/cli/commands/history/package.json +6 -0
  22. package/cli/commands/prove/package.json +6 -0
  23. package/cli/commands/redeem/package.json +6 -0
  24. package/cli/commands/update-client/package.json +6 -0
  25. package/cli/config/package.json +6 -0
  26. package/cli/package.json +6 -0
  27. package/cli/utils/package.json +6 -0
  28. package/constants/ibc-core-registry/package.json +6 -0
  29. package/constants/services/package.json +6 -0
  30. package/constants/z-asset-registry/package.json +6 -0
  31. package/dist/cjs/Abi.js +270 -0
  32. package/dist/cjs/Abi.js.map +1 -0
  33. package/dist/cjs/Attestor.js +76 -0
  34. package/dist/cjs/Attestor.js.map +1 -0
  35. package/dist/cjs/Constants.js +8 -0
  36. package/dist/cjs/Constants.js.map +1 -0
  37. package/dist/cjs/Domain.js +24 -0
  38. package/dist/cjs/Domain.js.map +1 -0
  39. package/dist/cjs/Error.js +100 -0
  40. package/dist/cjs/Error.js.map +1 -0
  41. package/dist/cjs/EvmPublicClient.js +301 -0
  42. package/dist/cjs/EvmPublicClient.js.map +1 -0
  43. package/dist/cjs/EvmWalletClient.js +670 -0
  44. package/dist/cjs/EvmWalletClient.js.map +1 -0
  45. package/dist/cjs/Payment.js +333 -0
  46. package/dist/cjs/Payment.js.map +1 -0
  47. package/dist/cjs/PaymentError.js +32 -0
  48. package/dist/cjs/PaymentError.js.map +1 -0
  49. package/dist/cjs/Prover.js +153 -0
  50. package/dist/cjs/Prover.js.map +1 -0
  51. package/dist/cjs/PublicClient.js +39 -0
  52. package/dist/cjs/PublicClient.js.map +1 -0
  53. package/dist/cjs/Schema.js +38 -0
  54. package/dist/cjs/Schema.js.map +1 -0
  55. package/dist/cjs/Utils.js +33 -0
  56. package/dist/cjs/Utils.js.map +1 -0
  57. package/dist/cjs/WalletClient.js +39 -0
  58. package/dist/cjs/WalletClient.js.map +1 -0
  59. package/dist/cjs/attestation.js +49 -0
  60. package/dist/cjs/attestation.js.map +1 -0
  61. package/dist/cjs/cli/commands/balance.js +60 -0
  62. package/dist/cjs/cli/commands/balance.js.map +1 -0
  63. package/dist/cjs/cli/commands/deposit.js +58 -0
  64. package/dist/cjs/cli/commands/deposit.js.map +1 -0
  65. package/dist/cjs/cli/commands/export-verifier.js +27 -0
  66. package/dist/cjs/cli/commands/export-verifier.js.map +1 -0
  67. package/dist/cjs/cli/commands/generate.js +41 -0
  68. package/dist/cjs/cli/commands/generate.js.map +1 -0
  69. package/dist/cjs/cli/commands/history.js +59 -0
  70. package/dist/cjs/cli/commands/history.js.map +1 -0
  71. package/dist/cjs/cli/commands/prove.js +82 -0
  72. package/dist/cjs/cli/commands/prove.js.map +1 -0
  73. package/dist/cjs/cli/commands/redeem.js +152 -0
  74. package/dist/cjs/cli/commands/redeem.js.map +1 -0
  75. package/dist/cjs/cli/commands/update-client.js +62 -0
  76. package/dist/cjs/cli/commands/update-client.js.map +1 -0
  77. package/dist/cjs/cli/config.js +32 -0
  78. package/dist/cjs/cli/config.js.map +1 -0
  79. package/dist/cjs/cli/utils.js +108 -0
  80. package/dist/cjs/cli/utils.js.map +1 -0
  81. package/dist/cjs/cli.js +24 -0
  82. package/dist/cjs/cli.js.map +1 -0
  83. package/dist/cjs/constants/ibc-core-registry.js +30 -0
  84. package/dist/cjs/constants/ibc-core-registry.js.map +1 -0
  85. package/dist/cjs/constants/services.js +9 -0
  86. package/dist/cjs/constants/services.js.map +1 -0
  87. package/dist/cjs/constants/z-asset-registry.js +32 -0
  88. package/dist/cjs/constants/z-asset-registry.js.map +1 -0
  89. package/dist/cjs/gen/prover_pb.js +81 -0
  90. package/dist/cjs/gen/prover_pb.js.map +1 -0
  91. package/dist/cjs/index.js +32 -0
  92. package/dist/cjs/index.js.map +1 -0
  93. package/dist/cjs/internal/evm.js +191 -0
  94. package/dist/cjs/internal/evm.js.map +1 -0
  95. package/dist/cjs/internal/evmWalletClient.js +6 -0
  96. package/dist/cjs/internal/evmWalletClient.js.map +1 -0
  97. package/dist/cjs/internal/publicClient.js +49 -0
  98. package/dist/cjs/internal/publicClient.js.map +1 -0
  99. package/dist/cjs/internal/walletClient.js +43 -0
  100. package/dist/cjs/internal/walletClient.js.map +1 -0
  101. package/dist/cjs/legacy/client.js +1222 -0
  102. package/dist/cjs/legacy/client.js.map +1 -0
  103. package/dist/cjs/legacy/prover.js +112 -0
  104. package/dist/cjs/legacy/prover.js.map +1 -0
  105. package/dist/cjs/poseidon2.js +226 -0
  106. package/dist/cjs/poseidon2.js.map +1 -0
  107. package/dist/cjs/promises/Attestor.js +23 -0
  108. package/dist/cjs/promises/Attestor.js.map +1 -0
  109. package/dist/cjs/promises/EvmPublicClient.js +34 -0
  110. package/dist/cjs/promises/EvmPublicClient.js.map +1 -0
  111. package/dist/cjs/promises/EvmWalletClient.js +51 -0
  112. package/dist/cjs/promises/EvmWalletClient.js.map +1 -0
  113. package/dist/cjs/promises/Payment.js +22 -0
  114. package/dist/cjs/promises/Payment.js.map +1 -0
  115. package/dist/cjs/promises/Prover.js +26 -0
  116. package/dist/cjs/promises/Prover.js.map +1 -0
  117. package/dist/cjs/promises/PublicClient.js +53 -0
  118. package/dist/cjs/promises/PublicClient.js.map +1 -0
  119. package/dist/cjs/promises/WalletClient.js +44 -0
  120. package/dist/cjs/promises/WalletClient.js.map +1 -0
  121. package/dist/cjs/promises/index.js +22 -0
  122. package/dist/cjs/promises/index.js.map +1 -0
  123. package/dist/cjs/rpc.js +867 -0
  124. package/dist/cjs/rpc.js.map +1 -0
  125. package/dist/cjs/types.js +6 -0
  126. package/dist/cjs/types.js.map +1 -0
  127. package/dist/dts/Abi.d.ts +220 -0
  128. package/dist/dts/Abi.d.ts.map +1 -0
  129. package/dist/dts/Attestor.d.ts +42 -0
  130. package/dist/dts/Attestor.d.ts.map +1 -0
  131. package/dist/dts/Constants.d.ts +3 -0
  132. package/dist/dts/Constants.d.ts.map +1 -0
  133. package/dist/dts/Domain.d.ts +141 -0
  134. package/dist/dts/Domain.d.ts.map +1 -0
  135. package/dist/dts/Error.d.ts +102 -0
  136. package/dist/dts/Error.d.ts.map +1 -0
  137. package/dist/dts/EvmPublicClient.d.ts +61 -0
  138. package/dist/dts/EvmPublicClient.d.ts.map +1 -0
  139. package/dist/dts/EvmWalletClient.d.ts +67 -0
  140. package/dist/dts/EvmWalletClient.d.ts.map +1 -0
  141. package/dist/dts/Payment.d.ts +128 -0
  142. package/dist/dts/Payment.d.ts.map +1 -0
  143. package/dist/dts/PaymentError.d.ts +21 -0
  144. package/dist/dts/PaymentError.d.ts.map +1 -0
  145. package/dist/dts/Prover.d.ts +87 -0
  146. package/dist/dts/Prover.d.ts.map +1 -0
  147. package/dist/dts/PublicClient.d.ts +146 -0
  148. package/dist/dts/PublicClient.d.ts.map +1 -0
  149. package/dist/dts/Schema.d.ts +16 -0
  150. package/dist/dts/Schema.d.ts.map +1 -0
  151. package/dist/dts/Utils.d.ts +11 -0
  152. package/dist/dts/Utils.d.ts.map +1 -0
  153. package/dist/dts/WalletClient.d.ts +123 -0
  154. package/dist/dts/WalletClient.d.ts.map +1 -0
  155. package/dist/dts/attestation.d.ts +13 -0
  156. package/dist/dts/attestation.d.ts.map +1 -0
  157. package/dist/dts/cli/commands/balance.d.ts +3 -0
  158. package/dist/dts/cli/commands/balance.d.ts.map +1 -0
  159. package/dist/dts/cli/commands/deposit.d.ts +3 -0
  160. package/dist/dts/cli/commands/deposit.d.ts.map +1 -0
  161. package/dist/dts/cli/commands/export-verifier.d.ts +3 -0
  162. package/dist/dts/cli/commands/export-verifier.d.ts.map +1 -0
  163. package/dist/dts/cli/commands/generate.d.ts +3 -0
  164. package/dist/dts/cli/commands/generate.d.ts.map +1 -0
  165. package/dist/dts/cli/commands/history.d.ts +3 -0
  166. package/dist/dts/cli/commands/history.d.ts.map +1 -0
  167. package/dist/dts/cli/commands/prove.d.ts +3 -0
  168. package/dist/dts/cli/commands/prove.d.ts.map +1 -0
  169. package/dist/dts/cli/commands/redeem.d.ts +3 -0
  170. package/dist/dts/cli/commands/redeem.d.ts.map +1 -0
  171. package/dist/dts/cli/commands/update-client.d.ts +3 -0
  172. package/dist/dts/cli/commands/update-client.d.ts.map +1 -0
  173. package/dist/dts/cli/config.d.ts +14 -0
  174. package/dist/dts/cli/config.d.ts.map +1 -0
  175. package/dist/dts/cli/utils.d.ts +11 -0
  176. package/dist/dts/cli/utils.d.ts.map +1 -0
  177. package/dist/dts/cli.d.ts +3 -0
  178. package/dist/dts/cli.d.ts.map +1 -0
  179. package/dist/dts/constants/ibc-core-registry.d.ts +11 -0
  180. package/dist/dts/constants/ibc-core-registry.d.ts.map +1 -0
  181. package/dist/dts/constants/services.d.ts +3 -0
  182. package/dist/dts/constants/services.d.ts.map +1 -0
  183. package/dist/dts/constants/z-asset-registry.d.ts +13 -0
  184. package/dist/dts/constants/z-asset-registry.d.ts.map +1 -0
  185. package/dist/dts/gen/prover_pb.d.ts +300 -0
  186. package/dist/dts/gen/prover_pb.d.ts.map +1 -0
  187. package/dist/dts/index.d.ts +21 -0
  188. package/dist/dts/index.d.ts.map +1 -0
  189. package/dist/dts/internal/evm.d.ts +250 -0
  190. package/dist/dts/internal/evm.d.ts.map +1 -0
  191. package/dist/dts/internal/evmWalletClient.d.ts +2 -0
  192. package/dist/dts/internal/evmWalletClient.d.ts.map +1 -0
  193. package/dist/dts/internal/publicClient.d.ts +2 -0
  194. package/dist/dts/internal/publicClient.d.ts.map +1 -0
  195. package/dist/dts/internal/walletClient.d.ts +2 -0
  196. package/dist/dts/internal/walletClient.d.ts.map +1 -0
  197. package/dist/dts/legacy/client.d.ts +313 -0
  198. package/dist/dts/legacy/client.d.ts.map +1 -0
  199. package/dist/dts/legacy/prover.d.ts +30 -0
  200. package/dist/dts/legacy/prover.d.ts.map +1 -0
  201. package/dist/dts/poseidon2.d.ts +18 -0
  202. package/dist/dts/poseidon2.d.ts.map +1 -0
  203. package/dist/dts/promises/Attestor.d.ts +17 -0
  204. package/dist/dts/promises/Attestor.d.ts.map +1 -0
  205. package/dist/dts/promises/EvmPublicClient.d.ts +3709 -0
  206. package/dist/dts/promises/EvmPublicClient.d.ts.map +1 -0
  207. package/dist/dts/promises/EvmWalletClient.d.ts +4502 -0
  208. package/dist/dts/promises/EvmWalletClient.d.ts.map +1 -0
  209. package/dist/dts/promises/Payment.d.ts +33 -0
  210. package/dist/dts/promises/Payment.d.ts.map +1 -0
  211. package/dist/dts/promises/Prover.d.ts +14 -0
  212. package/dist/dts/promises/Prover.d.ts.map +1 -0
  213. package/dist/dts/promises/PublicClient.d.ts +23 -0
  214. package/dist/dts/promises/PublicClient.d.ts.map +1 -0
  215. package/dist/dts/promises/WalletClient.d.ts +57 -0
  216. package/dist/dts/promises/WalletClient.d.ts.map +1 -0
  217. package/dist/dts/promises/index.d.ts +8 -0
  218. package/dist/dts/promises/index.d.ts.map +1 -0
  219. package/dist/dts/rpc.d.ts +148 -0
  220. package/dist/dts/rpc.d.ts.map +1 -0
  221. package/dist/dts/types.d.ts +263 -0
  222. package/dist/dts/types.d.ts.map +1 -0
  223. package/dist/esm/Abi.js +264 -0
  224. package/dist/esm/Abi.js.map +1 -0
  225. package/dist/esm/Attestor.js +68 -0
  226. package/dist/esm/Attestor.js.map +1 -0
  227. package/dist/esm/Constants.js +2 -0
  228. package/dist/esm/Constants.js.map +1 -0
  229. package/dist/esm/Domain.js +17 -0
  230. package/dist/esm/Domain.js.map +1 -0
  231. package/dist/esm/Error.js +89 -0
  232. package/dist/esm/Error.js.map +1 -0
  233. package/dist/esm/EvmPublicClient.js +292 -0
  234. package/dist/esm/EvmPublicClient.js.map +1 -0
  235. package/dist/esm/EvmWalletClient.js +659 -0
  236. package/dist/esm/EvmWalletClient.js.map +1 -0
  237. package/dist/esm/Payment.js +323 -0
  238. package/dist/esm/Payment.js.map +1 -0
  239. package/dist/esm/PaymentError.js +24 -0
  240. package/dist/esm/PaymentError.js.map +1 -0
  241. package/dist/esm/Prover.js +142 -0
  242. package/dist/esm/Prover.js.map +1 -0
  243. package/dist/esm/PublicClient.js +30 -0
  244. package/dist/esm/PublicClient.js.map +1 -0
  245. package/dist/esm/Schema.js +31 -0
  246. package/dist/esm/Schema.js.map +1 -0
  247. package/dist/esm/Utils.js +27 -0
  248. package/dist/esm/Utils.js.map +1 -0
  249. package/dist/esm/WalletClient.js +30 -0
  250. package/dist/esm/WalletClient.js.map +1 -0
  251. package/dist/esm/attestation.js +42 -0
  252. package/dist/esm/attestation.js.map +1 -0
  253. package/dist/esm/cli/commands/balance.js +54 -0
  254. package/dist/esm/cli/commands/balance.js.map +1 -0
  255. package/dist/esm/cli/commands/deposit.js +52 -0
  256. package/dist/esm/cli/commands/deposit.js.map +1 -0
  257. package/dist/esm/cli/commands/export-verifier.js +21 -0
  258. package/dist/esm/cli/commands/export-verifier.js.map +1 -0
  259. package/dist/esm/cli/commands/generate.js +35 -0
  260. package/dist/esm/cli/commands/generate.js.map +1 -0
  261. package/dist/esm/cli/commands/history.js +53 -0
  262. package/dist/esm/cli/commands/history.js.map +1 -0
  263. package/dist/esm/cli/commands/prove.js +76 -0
  264. package/dist/esm/cli/commands/prove.js.map +1 -0
  265. package/dist/esm/cli/commands/redeem.js +146 -0
  266. package/dist/esm/cli/commands/redeem.js.map +1 -0
  267. package/dist/esm/cli/commands/update-client.js +56 -0
  268. package/dist/esm/cli/commands/update-client.js.map +1 -0
  269. package/dist/esm/cli/config.js +26 -0
  270. package/dist/esm/cli/config.js.map +1 -0
  271. package/dist/esm/cli/utils.js +94 -0
  272. package/dist/esm/cli/utils.js.map +1 -0
  273. package/dist/esm/cli.js +22 -0
  274. package/dist/esm/cli.js.map +1 -0
  275. package/dist/esm/constants/ibc-core-registry.js +21 -0
  276. package/dist/esm/constants/ibc-core-registry.js.map +1 -0
  277. package/dist/esm/constants/services.js +3 -0
  278. package/dist/esm/constants/services.js.map +1 -0
  279. package/dist/esm/constants/z-asset-registry.js +23 -0
  280. package/dist/esm/constants/z-asset-registry.js.map +1 -0
  281. package/dist/esm/gen/prover_pb.js +74 -0
  282. package/dist/esm/gen/prover_pb.js.map +1 -0
  283. package/dist/esm/index.js +22 -0
  284. package/dist/esm/index.js.map +1 -0
  285. package/dist/esm/internal/evm.js +169 -0
  286. package/dist/esm/internal/evm.js.map +1 -0
  287. package/dist/esm/internal/evmWalletClient.js +2 -0
  288. package/dist/esm/internal/evmWalletClient.js.map +1 -0
  289. package/dist/esm/internal/publicClient.js +41 -0
  290. package/dist/esm/internal/publicClient.js.map +1 -0
  291. package/dist/esm/internal/walletClient.js +35 -0
  292. package/dist/esm/internal/walletClient.js.map +1 -0
  293. package/dist/esm/legacy/client.js +1212 -0
  294. package/dist/esm/legacy/client.js.map +1 -0
  295. package/dist/esm/legacy/prover.js +105 -0
  296. package/dist/esm/legacy/prover.js.map +1 -0
  297. package/dist/esm/package.json +4 -0
  298. package/dist/esm/poseidon2.js +218 -0
  299. package/dist/esm/poseidon2.js.map +1 -0
  300. package/dist/esm/promises/Attestor.js +14 -0
  301. package/dist/esm/promises/Attestor.js.map +1 -0
  302. package/dist/esm/promises/EvmPublicClient.js +26 -0
  303. package/dist/esm/promises/EvmPublicClient.js.map +1 -0
  304. package/dist/esm/promises/EvmWalletClient.js +43 -0
  305. package/dist/esm/promises/EvmWalletClient.js.map +1 -0
  306. package/dist/esm/promises/Payment.js +13 -0
  307. package/dist/esm/promises/Payment.js.map +1 -0
  308. package/dist/esm/promises/Prover.js +17 -0
  309. package/dist/esm/promises/Prover.js.map +1 -0
  310. package/dist/esm/promises/PublicClient.js +45 -0
  311. package/dist/esm/promises/PublicClient.js.map +1 -0
  312. package/dist/esm/promises/WalletClient.js +36 -0
  313. package/dist/esm/promises/WalletClient.js.map +1 -0
  314. package/dist/esm/promises/index.js +8 -0
  315. package/dist/esm/promises/index.js.map +1 -0
  316. package/dist/esm/rpc.js +850 -0
  317. package/dist/esm/rpc.js.map +1 -0
  318. package/dist/esm/types.js +2 -0
  319. package/dist/esm/types.js.map +1 -0
  320. package/gen/prover_pb/package.json +6 -0
  321. package/index/package.json +6 -0
  322. package/legacy/client/package.json +6 -0
  323. package/legacy/prover/package.json +6 -0
  324. package/package.json +397 -44
  325. package/poseidon2/package.json +6 -0
  326. package/promises/Attestor/package.json +6 -0
  327. package/promises/EvmPublicClient/package.json +6 -0
  328. package/promises/EvmWalletClient/package.json +6 -0
  329. package/promises/Payment/package.json +6 -0
  330. package/promises/Prover/package.json +6 -0
  331. package/promises/PublicClient/package.json +6 -0
  332. package/promises/WalletClient/package.json +6 -0
  333. package/promises/index/package.json +6 -0
  334. package/promises/package.json +6 -0
  335. package/rpc/package.json +6 -0
  336. package/src/Abi.ts +195 -0
  337. package/src/Attestor.ts +113 -0
  338. package/src/Constants.ts +4 -0
  339. package/src/Domain.ts +52 -0
  340. package/src/Error.ts +163 -0
  341. package/src/EvmPublicClient.ts +549 -0
  342. package/src/EvmWalletClient.ts +1034 -0
  343. package/src/Payment.ts +523 -0
  344. package/src/PaymentError.ts +39 -0
  345. package/src/Prover.ts +240 -0
  346. package/src/PublicClient.ts +196 -0
  347. package/src/Schema.ts +36 -0
  348. package/src/Utils.ts +43 -0
  349. package/src/WalletClient.ts +172 -0
  350. package/src/attestation.ts +69 -0
  351. package/src/cli/commands/balance.ts +88 -0
  352. package/src/cli/commands/deposit.ts +104 -0
  353. package/src/cli/commands/export-verifier.ts +28 -0
  354. package/src/cli/commands/generate.ts +86 -0
  355. package/src/cli/commands/history.ts +91 -0
  356. package/src/cli/commands/prove.ts +133 -0
  357. package/src/cli/commands/redeem.ts +277 -0
  358. package/src/cli/commands/update-client.ts +96 -0
  359. package/src/cli/config.ts +55 -0
  360. package/src/cli/utils.ts +136 -0
  361. package/src/cli.ts +31 -0
  362. package/src/constants/ibc-core-registry.ts +44 -0
  363. package/src/constants/services.ts +4 -0
  364. package/src/constants/z-asset-registry.ts +47 -0
  365. package/src/gen/prover_pb.ts +375 -0
  366. package/src/index.ts +23 -0
  367. package/src/internal/evm.ts +361 -0
  368. package/src/internal/evmWalletClient.ts +0 -0
  369. package/src/internal/publicClient.ts +57 -0
  370. package/src/internal/walletClient.ts +50 -0
  371. package/src/legacy/client.ts +1652 -0
  372. package/src/legacy/prover.ts +135 -0
  373. package/src/poseidon2.ts +246 -0
  374. package/src/promises/Attestor.ts +25 -0
  375. package/src/promises/EvmPublicClient.ts +39 -0
  376. package/src/promises/EvmWalletClient.ts +63 -0
  377. package/src/promises/Payment.ts +86 -0
  378. package/src/promises/Prover.ts +26 -0
  379. package/src/promises/PublicClient.ts +47 -0
  380. package/src/promises/WalletClient.ts +38 -0
  381. package/src/promises/index.ts +7 -0
  382. package/src/rpc.ts +994 -0
  383. package/src/types.ts +281 -0
  384. package/types/package.json +6 -0
  385. package/dist/LICENSE +0 -1
  386. package/dist/chunk-37PNLRA6.js +0 -2418
  387. package/dist/cli.cjs +0 -3031
  388. package/dist/cli.js +0 -675
  389. package/dist/index.cjs +0 -2451
  390. package/dist/index.js +0 -1
  391. package/dist/package.json +0 -18
  392. package/dist/payments.d.ts +0 -835
  393. /package/{dist → src}/tsdoc-metadata.json +0 -0
@@ -0,0 +1,1212 @@
1
+ import { Duration, Effect, pipe, Schedule } from "effect";
2
+ import { createPublicClient, encodeAbiParameters, hexToBigInt, http, keccak256, toRlp } from "viem";
3
+ import { AttestationClient } from "../attestation.js";
4
+ import { Z_ASSET_REGISTRY } from "../constants/z-asset-registry.js";
5
+ import * as evm from "../internal/evm.js";
6
+ import { computeNullifier, computeUnspendableAddress } from "../poseidon2.js";
7
+ import { computeStorageSlot, deterministicShuffleClients, fetchLightClients, fetchMptProof, IBC_STORE_ABI, parseProofJson, proofJsonToRedeemParams, RpcClient } from "../rpc.js";
8
+ import { ProverClient } from "./prover.js";
9
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
10
+ const commonRetry = {
11
+ schedule: /*#__PURE__*/Schedule.linear(/*#__PURE__*/Duration.seconds(2)),
12
+ times: 6
13
+ };
14
+ /**
15
+ * Construct a {@link UnionPrivatePayments} client.
16
+ *
17
+ * @throws Error if asset is unrecognized.
18
+ * @public
19
+ */
20
+ export const make = options => {
21
+ const proverUrl = options.proverUrl?.toString() ?? "https://prover.payments.union.build";
22
+ const attestorUrl = options.attestationUrl?.toString() ?? "https://attestor.payments.union.build/functions/v1/attest";
23
+ const zAssetAddress =
24
+ // @ts-expect-error
25
+ Z_ASSET_REGISTRY[`${options.chainId}`][options.assetAddress];
26
+ if (!zAssetAddress) throw new Error("Invalid asset address");
27
+ if (!options.attestorApiKey) throw new Error("No attestor API key");
28
+ return new UnionPrivatePayments({
29
+ proverUrl,
30
+ sourceRpcUrl: options.rpcUrl.toString(),
31
+ destinationRpcUrl: options.rpcUrl.toString(),
32
+ srcZAssetAddress: zAssetAddress,
33
+ dstZAssetAddress: zAssetAddress,
34
+ sourceChainId: options.chainId,
35
+ destinationChainId: options.chainId,
36
+ attestorUrl: attestorUrl,
37
+ attestorApiKey: options.attestorApiKey
38
+ });
39
+ };
40
+ /**
41
+ * Union Private Payments client
42
+ *
43
+ * This class provides a high-level interface for performing private transfers
44
+ * using the Union protocol. It handles:
45
+ *
46
+ * - Generating unspendable addresses for deposits
47
+ *
48
+ * - Querying balances (confirmed, pending, redeemed, available)
49
+ *
50
+ * - Building witness data for proof generation
51
+ *
52
+ * - Communicating with the prover server
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * import { UnionPrivatePayments } from '@unionlabs/payments';
57
+ *
58
+ * const client = new UnionPrivatePayments({
59
+ * proverUrl: 'http://localhost:8080',
60
+ * sourceRpcUrl: 'https://eth-mainnet.alchemyapi.io/v2/...',
61
+ * destinationRpcUrl: 'https://arbitrum-mainnet.alchemyapi.io/v2/...',
62
+ * srcZAssetAddress: '0x...', // ZAsset on source chain
63
+ * dstZAssetAddress: '0x...', // ZAsset on destination chain
64
+ * sourceChainId: 1n,
65
+ * destinationChainId: 42161n,
66
+ * });
67
+ *
68
+ * // Generate deposit address
69
+ * const address = client.getDepositAddress(secret, beneficiaries);
70
+ *
71
+ * // Check balance
72
+ * const balance = await client.getBalance({ depositAddress, nullifier, clientId });
73
+ *
74
+ * // Generate proof for redemption
75
+ * const proof = await client.generateProof(secret, beneficiaries, beneficiary, amount, clientIds);
76
+ * ```
77
+ * @public
78
+ */
79
+ export class UnionPrivatePayments {
80
+ config;
81
+ srcClient;
82
+ dstClient;
83
+ proverClient;
84
+ constructor(config) {
85
+ this.config = config;
86
+ this.srcClient = new RpcClient(config.sourceRpcUrl);
87
+ this.dstClient = new RpcClient(config.destinationRpcUrl);
88
+ this.proverClient = new ProverClient(config.proverUrl);
89
+ }
90
+ /**
91
+ * Get the deposit address for a given secret and beneficiaries
92
+ *
93
+ * The returned address is an "unspendable" address derived from the secret.
94
+ * Tokens sent to this address can only be redeemed via ZK proof.
95
+ *
96
+ * @param secret - The 32-byte secret as a hex string
97
+ * @param beneficiaries - Array of 1-4 beneficiary addresses (remaining slots zero-padded)
98
+ * @returns The unspendable deposit address
99
+ */
100
+ getDepositAddress(secret, beneficiaries) {
101
+ const paddedBeneficiaries = this.padBeneficiaries(beneficiaries);
102
+ return computeUnspendableAddress(secret, this.config.destinationChainId, paddedBeneficiaries);
103
+ }
104
+ /**
105
+ * Get the nullifier for a given paymentKey
106
+ *
107
+ * The nullifier is used to prevent double-spending. Each (paymentKey, chainId) pair
108
+ * produces a unique nullifier that is recorded on-chain when funds are redeemed.
109
+ *
110
+ * @param paymentKey - The 32-byte paymentKey as a hex string
111
+ * @returns The nullifier as a bigint
112
+ */
113
+ getNullifier(paymentKey) {
114
+ return computeNullifier(paymentKey, this.config.destinationChainId);
115
+ }
116
+ /**
117
+ * Get balance information
118
+ *
119
+ * Returns:
120
+ * - confirmed: balance visible to light client (provable)
121
+ * - redeemed: amount already redeemed via nullifier
122
+ * - available: amount that can be redeemed now (confirmed - redeemed)
123
+ * - pending: deposits not yet visible to light client
124
+ *
125
+ * @param options - Options for getting balance
126
+ * @returns Balance information
127
+ */
128
+ async getBalance(options) {
129
+ const {
130
+ depositAddress,
131
+ nullifier,
132
+ clientId
133
+ } = options;
134
+ console.log(options);
135
+ console.log({
136
+ dstZAssetAddress: this.config.dstZAssetAddress
137
+ });
138
+ const ibcHandlerAddress = await this.dstClient.getIbcHandlerAddress(this.config.dstZAssetAddress);
139
+ const lightClientAddress = await this.dstClient.getLightClientAddress(ibcHandlerAddress, clientId);
140
+ const lightClientHeight = await this.dstClient.getLatestHeight(lightClientAddress, clientId);
141
+ const balance = await this.getBalanceAtHeight(depositAddress, nullifier, lightClientHeight);
142
+ return {
143
+ ...balance,
144
+ lightClientHeight
145
+ };
146
+ }
147
+ /**
148
+ * Get balance information at a specific block height
149
+ *
150
+ * @param depositAddress - The deposit address (unspendable address)
151
+ * @param nullifier - The nullifier for this secret
152
+ * @param height - The block height to query confirmed balance at
153
+ * @returns Balance information at the given height
154
+ */
155
+ async getBalanceAtHeight(depositAddress, nullifier, height) {
156
+ const latestHeight = await this.srcClient.getLatestBlockNumber();
157
+ const [balanceAtTip, confirmed, redeemed] = await Promise.all([this.srcClient.getBalance(this.config.srcZAssetAddress, depositAddress), this.srcClient.getBalance(this.config.srcZAssetAddress, depositAddress, height), this.dstClient.getNullifierBalance(this.config.dstZAssetAddress, nullifier)]);
158
+ const available = confirmed > redeemed ? confirmed - redeemed : 0n;
159
+ const pending = balanceAtTip > confirmed ? balanceAtTip - confirmed : 0n;
160
+ return {
161
+ confirmed,
162
+ redeemed,
163
+ available,
164
+ pending,
165
+ latestHeight
166
+ };
167
+ }
168
+ /**
169
+ * Generate a proof for redeeming funds
170
+ *
171
+ * This method:
172
+ * 1. Fetches light client data from the destination chain
173
+ * 2. Deterministically shuffles clients for privacy
174
+ * 3. Fetches MPT proof from the source chain
175
+ * 4. Builds the witness data
176
+ * 5. Sends the witness to the prover server
177
+ * 6. Polls until the proof is ready
178
+ *
179
+ * @param secret - The 32-byte secret as a hex string
180
+ * @param beneficiaries - Array of 0-4 beneficiary addresses (empty array = unbounded mode)
181
+ * @param beneficiary - The beneficiary address to redeem to
182
+ * @param amount - Amount to redeem
183
+ * @param clientIds - Light client IDs to include in the proof (for anonymity set)
184
+ * @param selectedClientId - The specific light client ID to use for the proof
185
+ * @returns GenerateProofResult containing proof result and client-side metadata
186
+ */
187
+ async generateProof(secret, beneficiaries, beneficiary, amount, clientIds, selectedClientId) {
188
+ // Validate inputs
189
+ if (!clientIds.includes(selectedClientId)) {
190
+ return {
191
+ proof: {
192
+ success: false,
193
+ error: `selectedClientId ${selectedClientId} not in clientIds`
194
+ }
195
+ };
196
+ }
197
+ if (beneficiary === ZERO_ADDRESS) {
198
+ return {
199
+ proof: {
200
+ success: false,
201
+ error: "Beneficiary address cannot be zero"
202
+ }
203
+ };
204
+ }
205
+ const paddedBeneficiaries = this.padBeneficiaries(beneficiaries);
206
+ const depositAddress = this.getDepositAddress(secret, beneficiaries);
207
+ const lightClients = await fetchLightClients(this.dstClient, this.config.dstZAssetAddress, clientIds);
208
+ if (lightClients.length === 0) {
209
+ return {
210
+ proof: {
211
+ success: false,
212
+ error: "No valid light clients found"
213
+ }
214
+ };
215
+ }
216
+ // Deterministic shuffle: same secret always produces the same ordering for privacy
217
+ const shuffled = deterministicShuffleClients(lightClients, secret);
218
+ const selectedClientIndex = shuffled.findIndex(c => c.clientId === selectedClientId);
219
+ if (selectedClientIndex === -1) {
220
+ return {
221
+ proof: {
222
+ success: false,
223
+ error: `Client ${selectedClientId} not found after fetching`
224
+ }
225
+ };
226
+ }
227
+ const selectedClient = shuffled[selectedClientIndex];
228
+ const {
229
+ tokenAddressKey,
230
+ balanceSlot
231
+ } = await this.dstClient.getCounterparty(this.config.dstZAssetAddress, selectedClientId);
232
+ // Check if counterparty is configured for this light client
233
+ const ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
234
+ if (balanceSlot === ZERO_BYTES32 || tokenAddressKey === ZERO_BYTES32) {
235
+ return {
236
+ proof: {
237
+ success: false,
238
+ error: `Light client ${selectedClientId} is not configured as a counterparty on the destination ZAsset. ` + `Please call setCounterparty() on the ZAsset contract first.`
239
+ }
240
+ };
241
+ }
242
+ const mappingSlot = hexToBigInt(balanceSlot);
243
+ const nullifier = this.getNullifier(secret);
244
+ // Check balance at the selected light client's height
245
+ const balance = await this.getBalanceAtHeight(depositAddress, nullifier, selectedClient.height);
246
+ if (amount > balance.available) {
247
+ return {
248
+ proof: {
249
+ success: false,
250
+ error: `Insufficient available balance. Requested: ${amount}, Available: ${balance.available} ` + `(Confirmed at height ${selectedClient.height}: ${balance.confirmed}, Already redeemed: ${balance.redeemed})`
251
+ }
252
+ };
253
+ }
254
+ const storageSlot = computeStorageSlot(depositAddress, mappingSlot);
255
+ const mptProof = await fetchMptProof(this.srcClient, this.config.srcZAssetAddress, storageSlot, selectedClient.height);
256
+ const witness = {
257
+ secret,
258
+ dstChainId: this.config.destinationChainId,
259
+ beneficiaries: paddedBeneficiaries,
260
+ beneficiary,
261
+ redeemAmount: amount,
262
+ alreadyRedeemed: balance.redeemed,
263
+ lightClients: shuffled,
264
+ selectedClientIndex,
265
+ mptProof,
266
+ srcZAssetAddress: this.config.srcZAssetAddress,
267
+ mappingSlot: `0x${mappingSlot.toString(16)}`
268
+ };
269
+ const proofResult = await this.proverClient.generateProof(witness);
270
+ if (proofResult.success) {
271
+ return {
272
+ proof: proofResult,
273
+ metadata: {
274
+ depositAddress,
275
+ beneficiary,
276
+ value: amount,
277
+ lightClients: shuffled,
278
+ nullifier
279
+ }
280
+ };
281
+ }
282
+ return {
283
+ proof: proofResult
284
+ };
285
+ }
286
+ /**
287
+ * Export the verifier contract from the prover server
288
+ *
289
+ * The verifier contract is used to verify proofs on-chain.
290
+ * It is circuit-specific and does not change between proofs.
291
+ *
292
+ * @returns The Solidity verifier contract source code
293
+ */
294
+ async exportVerifier() {
295
+ return this.proverClient.exportVerifier();
296
+ }
297
+ /**
298
+ * Get source ZAsset token information
299
+ *
300
+ * @returns Token symbol and decimals
301
+ */
302
+ async getSrcZAssetInfo() {
303
+ const [symbol, decimals] = await Promise.all([this.srcClient.getSymbol(this.config.srcZAssetAddress), this.srcClient.getDecimals(this.config.srcZAssetAddress)]);
304
+ return {
305
+ symbol,
306
+ decimals
307
+ };
308
+ }
309
+ /**
310
+ * Get destination ZAsset token information
311
+ *
312
+ * @returns Token symbol and decimals
313
+ */
314
+ async getDstZAssetInfo() {
315
+ const [symbol, decimals] = await Promise.all([this.dstClient.getSymbol(this.config.dstZAssetAddress), this.dstClient.getDecimals(this.config.dstZAssetAddress)]);
316
+ return {
317
+ symbol,
318
+ decimals
319
+ };
320
+ }
321
+ /**
322
+ * Deposit underlying tokens to ZAsset and transfer to deposit address
323
+ *
324
+ * Executes 3 transactions: approve → deposit → transfer.
325
+ * The wallet client must be connected to the source chain.
326
+ *
327
+ * @param secret - The 32-byte secret as a hex string
328
+ * @param beneficiaries - Array of 0-4 beneficiary addresses
329
+ * @param amount - Amount to deposit (in underlying token's smallest unit)
330
+ * @param walletClient - viem WalletClient with account and chain configured
331
+ * @returns Transaction hash, deposit address, underlying token, and chain ID
332
+ */
333
+ async deposit(options) {
334
+ const {
335
+ paymentKey,
336
+ beneficiaries,
337
+ amount,
338
+ walletClient
339
+ } = options;
340
+ if (!walletClient.account) {
341
+ throw new Error("WalletClient must have an account");
342
+ }
343
+ if (!walletClient.chain) {
344
+ throw new Error("WalletClient must have a chain configured");
345
+ }
346
+ return Effect.gen(this, function* () {
347
+ const depositAddress = this.getDepositAddress(paymentKey, beneficiaries);
348
+ // Get underlying token address
349
+ const underlyingToken = yield* pipe(evm.readContract({
350
+ address: this.config.srcZAssetAddress,
351
+ abi: [{
352
+ inputs: [],
353
+ name: "underlying",
354
+ outputs: [{
355
+ name: "",
356
+ type: "address"
357
+ }],
358
+ stateMutability: "view",
359
+ type: "function"
360
+ }],
361
+ functionName: "underlying"
362
+ }), Effect.retry(commonRetry), Effect.provideService(evm.PublicClient, {
363
+ client: this.srcClient.getClient()
364
+ }));
365
+ if (underlyingToken === ZERO_ADDRESS) {
366
+ return yield* Effect.fail(Error("ZAsset is not a wrapped token (underlying is zero address)"));
367
+ }
368
+ const ERC20_ABI = [{
369
+ inputs: [{
370
+ name: "spender",
371
+ type: "address"
372
+ }, {
373
+ name: "amount",
374
+ type: "uint256"
375
+ }],
376
+ name: "approve",
377
+ outputs: [{
378
+ name: "",
379
+ type: "bool"
380
+ }],
381
+ stateMutability: "nonpayable",
382
+ type: "function"
383
+ }];
384
+ const ZASSET_ABI = [{
385
+ inputs: [{
386
+ name: "amount",
387
+ type: "uint256"
388
+ }],
389
+ name: "deposit",
390
+ outputs: [],
391
+ stateMutability: "nonpayable",
392
+ type: "function"
393
+ }, {
394
+ inputs: [{
395
+ name: "to",
396
+ type: "address"
397
+ }, {
398
+ name: "amount",
399
+ type: "uint256"
400
+ }],
401
+ name: "transfer",
402
+ outputs: [{
403
+ name: "",
404
+ type: "bool"
405
+ }],
406
+ stateMutability: "nonpayable",
407
+ type: "function"
408
+ }];
409
+ // 1. Approve ZAsset to spend underlying tokens
410
+ const approveHash = yield* pipe(evm.writeContract({
411
+ address: underlyingToken,
412
+ abi: ERC20_ABI,
413
+ functionName: "approve",
414
+ args: [this.config.srcZAssetAddress, amount],
415
+ chain: walletClient.chain,
416
+ account: walletClient.account
417
+ }), Effect.retry(commonRetry));
418
+ const approveReceipt = yield* pipe(evm.waitForTransactionReceipt(approveHash), Effect.retry(commonRetry));
419
+ if (approveReceipt.status === "reverted") {
420
+ return yield* Effect.fail(Error(`Approve transaction reverted: ${approveHash}`));
421
+ }
422
+ // 2. Deposit underlying to get ZAsset
423
+ const depositHash = yield* pipe(evm.writeContract({
424
+ address: this.config.srcZAssetAddress,
425
+ abi: ZASSET_ABI,
426
+ functionName: "deposit",
427
+ args: [amount],
428
+ chain: walletClient.chain,
429
+ account: walletClient.account
430
+ }), Effect.retry(commonRetry));
431
+ const depositReceipt = yield* evm.waitForTransactionReceipt(depositHash).pipe(Effect.retry(commonRetry));
432
+ if (depositReceipt.status === "reverted") {
433
+ throw new Error(`Deposit transaction reverted: ${depositHash}`);
434
+ }
435
+ // 3. Transfer ZAsset to deposit address
436
+ const transferHash = yield* pipe(evm.writeContract({
437
+ address: this.config.srcZAssetAddress,
438
+ abi: ZASSET_ABI,
439
+ functionName: "transfer",
440
+ args: [depositAddress, amount],
441
+ chain: walletClient.chain,
442
+ account: walletClient.account
443
+ }), Effect.retry(commonRetry));
444
+ const transferReceipt = yield* evm.waitForTransactionReceipt(transferHash);
445
+ if (transferReceipt.status === "reverted") {
446
+ throw new Error(`Transfer transaction reverted: ${transferHash}`);
447
+ }
448
+ return {
449
+ txHash: transferHash,
450
+ depositAddress,
451
+ underlyingToken,
452
+ chainId: this.config.sourceChainId,
453
+ height: transferReceipt.blockNumber
454
+ };
455
+ }).pipe(Effect.provide(evm.PublicClient.Live({
456
+ chain: options.walletClient.chain,
457
+ transport: http(this.config.sourceRpcUrl)
458
+ })), Effect.provideService(evm.WalletClient, {
459
+ client: options.walletClient,
460
+ account: options.walletClient.account,
461
+ chain: options.walletClient.chain
462
+ }), Effect.runPromise);
463
+ }
464
+ /**
465
+ * Deposit underlying tokens to ZAsset and transfer to deposit address
466
+ *
467
+ * Executes 3 transactions: approve → deposit → transfer.
468
+ * The wallet client must be connected to the source chain.
469
+ *
470
+ * @param secret - The 32-byte secret as a hex string
471
+ * @param beneficiaries - Array of 0-4 beneficiary addresses
472
+ * @param amount - Amount to deposit (in underlying token's smallest unit)
473
+ * @param walletClient - viem WalletClient with account and chain configured
474
+ * @returns Transaction hash, deposit address, underlying token, and chain ID
475
+ */
476
+ async unsafeDeposit(options) {
477
+ const {
478
+ paymentKey,
479
+ beneficiaries,
480
+ amount,
481
+ walletClient
482
+ } = options;
483
+ if (!walletClient.account) {
484
+ throw new Error("WalletClient must have an account");
485
+ }
486
+ if (!walletClient.chain) {
487
+ throw new Error("WalletClient must have a chain configured");
488
+ }
489
+ const depositAddress = this.getDepositAddress(paymentKey, beneficiaries);
490
+ const publicClient = createPublicClient({
491
+ chain: walletClient.chain,
492
+ transport: http(this.config.sourceRpcUrl)
493
+ });
494
+ // Get underlying token address
495
+ const underlyingToken = await this.srcClient.getClient().readContract({
496
+ address: this.config.srcZAssetAddress,
497
+ abi: [{
498
+ inputs: [],
499
+ name: "underlying",
500
+ outputs: [{
501
+ name: "",
502
+ type: "address"
503
+ }],
504
+ stateMutability: "view",
505
+ type: "function"
506
+ }],
507
+ functionName: "underlying"
508
+ });
509
+ if (underlyingToken === ZERO_ADDRESS) {
510
+ throw new Error("ZAsset is not a wrapped token (underlying is zero address)");
511
+ }
512
+ const ERC20_ABI = [{
513
+ inputs: [{
514
+ name: "spender",
515
+ type: "address"
516
+ }, {
517
+ name: "amount",
518
+ type: "uint256"
519
+ }],
520
+ name: "approve",
521
+ outputs: [{
522
+ name: "",
523
+ type: "bool"
524
+ }],
525
+ stateMutability: "nonpayable",
526
+ type: "function"
527
+ }];
528
+ const ZASSET_ABI = [{
529
+ inputs: [{
530
+ name: "amount",
531
+ type: "uint256"
532
+ }],
533
+ name: "deposit",
534
+ outputs: [],
535
+ stateMutability: "nonpayable",
536
+ type: "function"
537
+ }, {
538
+ inputs: [{
539
+ name: "to",
540
+ type: "address"
541
+ }, {
542
+ name: "amount",
543
+ type: "uint256"
544
+ }],
545
+ name: "transfer",
546
+ outputs: [{
547
+ name: "",
548
+ type: "bool"
549
+ }],
550
+ stateMutability: "nonpayable",
551
+ type: "function"
552
+ }];
553
+ // 1. Approve ZAsset to spend underlying tokens
554
+ const approveHash = await walletClient.writeContractSync({
555
+ address: underlyingToken,
556
+ abi: ERC20_ABI,
557
+ functionName: "approve",
558
+ args: [this.config.srcZAssetAddress, amount],
559
+ chain: walletClient.chain,
560
+ account: walletClient.account
561
+ }).then(x => x.transactionHash);
562
+ const approveReceipt = await publicClient.waitForTransactionReceipt({
563
+ hash: approveHash
564
+ });
565
+ if (approveReceipt.status === "reverted") {
566
+ throw new Error(`Approve transaction reverted: ${approveHash}`);
567
+ }
568
+ // 2. Deposit underlying to get ZAsset
569
+ const depositHash = await walletClient.writeContractSync({
570
+ address: this.config.srcZAssetAddress,
571
+ abi: ZASSET_ABI,
572
+ functionName: "deposit",
573
+ args: [amount],
574
+ chain: walletClient.chain,
575
+ account: walletClient.account
576
+ }).then(x => x.transactionHash);
577
+ const depositReceipt = await publicClient.waitForTransactionReceipt({
578
+ hash: depositHash
579
+ });
580
+ if (depositReceipt.status === "reverted") {
581
+ throw new Error(`Deposit transaction reverted: ${depositHash}`);
582
+ }
583
+ // 3. Transfer ZAsset to deposit address
584
+ const transferHash = await walletClient.writeContractSync({
585
+ address: this.config.srcZAssetAddress,
586
+ abi: ZASSET_ABI,
587
+ functionName: "transfer",
588
+ args: [depositAddress, amount],
589
+ chain: walletClient.chain,
590
+ account: walletClient.account
591
+ }).then(x => x.transactionHash);
592
+ const transferReceipt = await publicClient.waitForTransactionReceipt({
593
+ hash: transferHash
594
+ });
595
+ if (transferReceipt.status === "reverted") {
596
+ throw new Error(`Transfer transaction reverted: ${transferHash}`);
597
+ }
598
+ return {
599
+ txHash: transferHash,
600
+ depositAddress,
601
+ underlyingToken,
602
+ chainId: this.config.sourceChainId,
603
+ height: transferReceipt.blockNumber
604
+ };
605
+ }
606
+ /**
607
+ * Update loopback light client to a specific block height
608
+ *
609
+ * Fetches the IBC handler address internally from the destination ZAsset.
610
+ * The wallet client must be connected to the destination chain.
611
+ *
612
+ * @returns Transaction hash, block number, state root, and chain ID
613
+ */
614
+ async updateLightClient(options) {
615
+ const {
616
+ clientId,
617
+ height,
618
+ walletClient
619
+ } = options;
620
+ if (!walletClient.account) {
621
+ throw new Error("WalletClient must have an account");
622
+ }
623
+ if (!walletClient.chain) {
624
+ throw new Error("WalletClient must have a chain configured");
625
+ }
626
+ return Effect.gen(this, function* () {
627
+ const publicClient = createPublicClient({
628
+ chain: walletClient.chain,
629
+ transport: http(this.config.destinationRpcUrl)
630
+ });
631
+ // Get IBC handler address from ZAsset
632
+ const ibcHandlerAddress = yield* Effect.tryPromise({
633
+ try: () => this.dstClient.getIbcHandlerAddress(this.config.dstZAssetAddress),
634
+ catch: cause => Effect.fail(cause)
635
+ });
636
+ // Get the block number
637
+ const blockNumber = height === "latest" ? yield* pipe(Effect.tryPromise(() => publicClient.getBlockNumber()), Effect.retry(commonRetry)) : height;
638
+ // Get the block for metadata
639
+ const block = yield* pipe(Effect.tryPromise(() => publicClient.getBlock({
640
+ blockNumber
641
+ })), Effect.retry(commonRetry));
642
+ if (!block.number) {
643
+ throw new Error("Block number is null");
644
+ }
645
+ // Helper to convert bigint/number to minimal RLP hex encoding
646
+ const toRlpHex = value => {
647
+ if (value === undefined || value === null || value === 0n || value === 0) {
648
+ return "0x";
649
+ }
650
+ let hex = typeof value === "bigint" ? value.toString(16) : value.toString(16);
651
+ if (hex.length % 2 !== 0) {
652
+ hex = "0" + hex;
653
+ }
654
+ return `0x${hex}`;
655
+ };
656
+ // Build header fields in order (pre-merge + post-merge fields)
657
+ const headerFields = [block.parentHash, block.sha3Uncles, block.miner, block.stateRoot, block.transactionsRoot, block.receiptsRoot, block.logsBloom ?? "0x" + "00".repeat(256), toRlpHex(block.difficulty), toRlpHex(block.number), toRlpHex(block.gasLimit), toRlpHex(block.gasUsed), toRlpHex(block.timestamp), block.extraData, block.mixHash ?? "0x0000000000000000000000000000000000000000000000000000000000000000", block.nonce ?? "0x0000000000000000"];
658
+ // Post-merge fields
659
+ if (block.baseFeePerGas !== undefined && block.baseFeePerGas !== null) {
660
+ headerFields.push(toRlpHex(block.baseFeePerGas));
661
+ }
662
+ if (block.withdrawalsRoot) {
663
+ headerFields.push(block.withdrawalsRoot);
664
+ }
665
+ if (block.blobGasUsed !== undefined && block.blobGasUsed !== null) {
666
+ headerFields.push(toRlpHex(block.blobGasUsed));
667
+ }
668
+ if (block.excessBlobGas !== undefined && block.excessBlobGas !== null) {
669
+ headerFields.push(toRlpHex(block.excessBlobGas));
670
+ }
671
+ if (block.parentBeaconBlockRoot) {
672
+ headerFields.push(block.parentBeaconBlockRoot);
673
+ }
674
+ const blockAny = block;
675
+ if (blockAny.requestsHash) {
676
+ headerFields.push(blockAny.requestsHash);
677
+ }
678
+ const rlpEncoded = toRlp(headerFields);
679
+ // Verify the encoding produces the correct block hash
680
+ const computedHash = keccak256(rlpEncoded);
681
+ if (computedHash !== block.hash) {
682
+ throw new Error(`RLP encoding mismatch: computed hash ${computedHash} does not match block hash ${block.hash}`);
683
+ }
684
+ // Encode the Header struct: (uint64 height, bytes encodedHeader)
685
+ const clientMessage = encodeAbiParameters([{
686
+ type: "uint64",
687
+ name: "height"
688
+ }, {
689
+ type: "bytes",
690
+ name: "encodedHeader"
691
+ }], [block.number, rlpEncoded]);
692
+ const LIGHTCLIENT_ABI = [{
693
+ inputs: [{
694
+ name: "caller",
695
+ type: "address"
696
+ }, {
697
+ name: "clientId",
698
+ type: "uint32"
699
+ }, {
700
+ name: "clientMessage",
701
+ type: "bytes"
702
+ }, {
703
+ name: "relayer",
704
+ type: "address"
705
+ }],
706
+ name: "updateClient",
707
+ outputs: [],
708
+ stateMutability: "nonpayable",
709
+ type: "function"
710
+ }];
711
+ // Wait for the next block so the fetched block's hash is verifiable on-chain
712
+ let currentBlock = yield* pipe(Effect.tryPromise(() => publicClient.getBlockNumber()), Effect.retry(commonRetry));
713
+ while (currentBlock <= blockNumber) {
714
+ yield* Effect.sleep("1 second");
715
+ currentBlock = yield* Effect.tryPromise(() => publicClient.getBlockNumber());
716
+ }
717
+ const loopbackClient = yield* pipe(evm.readContract({
718
+ address: ibcHandlerAddress,
719
+ abi: IBC_STORE_ABI,
720
+ functionName: "getClient",
721
+ args: [clientId]
722
+ }), Effect.retry(commonRetry));
723
+ // Submit the transaction
724
+ const txHash = yield* pipe(evm.writeContract({
725
+ address: loopbackClient,
726
+ abi: LIGHTCLIENT_ABI,
727
+ functionName: "updateClient",
728
+ args: [walletClient.account.address, clientId, clientMessage, walletClient.account.address],
729
+ chain: walletClient.chain,
730
+ account: walletClient.account
731
+ }), Effect.retry(commonRetry));
732
+ const chainId = yield* Effect.sync(() => this.config.destinationChainId);
733
+ return {
734
+ txHash,
735
+ blockNumber: block.number,
736
+ stateRoot: block.stateRoot,
737
+ chainId
738
+ };
739
+ }).pipe(Effect.provide(evm.PublicClient.Live({
740
+ chain: walletClient.chain,
741
+ transport: http(this.config.destinationRpcUrl)
742
+ })), Effect.provideService(evm.WalletClient, {
743
+ client: options.walletClient,
744
+ account: options.walletClient.account,
745
+ chain: options.walletClient.chain
746
+ }), Effect.runPromise);
747
+ }
748
+ /**
749
+ * Update loopback light client to a specific block height
750
+ *
751
+ * Fetches the IBC handler address internally from the destination ZAsset.
752
+ * The wallet client must be connected to the destination chain.
753
+ *
754
+ * @returns Transaction hash, block number, state root, and chain ID
755
+ */
756
+ async unsafeUpdateLightClient(options) {
757
+ const {
758
+ clientId,
759
+ height,
760
+ walletClient
761
+ } = options;
762
+ if (!walletClient.account) {
763
+ throw new Error("WalletClient must have an account");
764
+ }
765
+ if (!walletClient.chain) {
766
+ throw new Error("WalletClient must have a chain configured");
767
+ }
768
+ const publicClient = createPublicClient({
769
+ chain: walletClient.chain,
770
+ transport: http(this.config.destinationRpcUrl)
771
+ });
772
+ // Get IBC handler address from ZAsset
773
+ const ibcHandlerAddress = await this.dstClient.getIbcHandlerAddress(this.config.dstZAssetAddress);
774
+ // Get the block number
775
+ const blockNumber = height === "latest" ? await publicClient.getBlockNumber() : height;
776
+ // Get the block for metadata
777
+ const block = await publicClient.getBlock({
778
+ blockNumber
779
+ });
780
+ if (!block.number) {
781
+ throw new Error("Block number is null");
782
+ }
783
+ // Helper to convert bigint/number to minimal RLP hex encoding
784
+ const toRlpHex = value => {
785
+ if (value === undefined || value === null || value === 0n || value === 0) {
786
+ return "0x";
787
+ }
788
+ let hex = typeof value === "bigint" ? value.toString(16) : value.toString(16);
789
+ if (hex.length % 2 !== 0) {
790
+ hex = "0" + hex;
791
+ }
792
+ return `0x${hex}`;
793
+ };
794
+ // Build header fields in order (pre-merge + post-merge fields)
795
+ const headerFields = [block.parentHash, block.sha3Uncles, block.miner, block.stateRoot, block.transactionsRoot, block.receiptsRoot, block.logsBloom ?? "0x" + "00".repeat(256), toRlpHex(block.difficulty), toRlpHex(block.number), toRlpHex(block.gasLimit), toRlpHex(block.gasUsed), toRlpHex(block.timestamp), block.extraData, block.mixHash ?? "0x0000000000000000000000000000000000000000000000000000000000000000", block.nonce ?? "0x0000000000000000"];
796
+ // Post-merge fields
797
+ if (block.baseFeePerGas !== undefined && block.baseFeePerGas !== null) {
798
+ headerFields.push(toRlpHex(block.baseFeePerGas));
799
+ }
800
+ if (block.withdrawalsRoot) {
801
+ headerFields.push(block.withdrawalsRoot);
802
+ }
803
+ if (block.blobGasUsed !== undefined && block.blobGasUsed !== null) {
804
+ headerFields.push(toRlpHex(block.blobGasUsed));
805
+ }
806
+ if (block.excessBlobGas !== undefined && block.excessBlobGas !== null) {
807
+ headerFields.push(toRlpHex(block.excessBlobGas));
808
+ }
809
+ if (block.parentBeaconBlockRoot) {
810
+ headerFields.push(block.parentBeaconBlockRoot);
811
+ }
812
+ const blockAny = block;
813
+ if (blockAny.requestsHash) {
814
+ headerFields.push(blockAny.requestsHash);
815
+ }
816
+ const rlpEncoded = toRlp(headerFields);
817
+ // Verify the encoding produces the correct block hash
818
+ const computedHash = keccak256(rlpEncoded);
819
+ if (computedHash !== block.hash) {
820
+ throw new Error(`RLP encoding mismatch: computed hash ${computedHash} does not match block hash ${block.hash}`);
821
+ }
822
+ // Encode the Header struct: (uint64 height, bytes encodedHeader)
823
+ const clientMessage = encodeAbiParameters([{
824
+ type: "uint64",
825
+ name: "height"
826
+ }, {
827
+ type: "bytes",
828
+ name: "encodedHeader"
829
+ }], [block.number, rlpEncoded]);
830
+ const LIGHTCLIENT_ABI = [{
831
+ inputs: [{
832
+ name: "caller",
833
+ type: "address"
834
+ }, {
835
+ name: "clientId",
836
+ type: "uint32"
837
+ }, {
838
+ name: "clientMessage",
839
+ type: "bytes"
840
+ }, {
841
+ name: "relayer",
842
+ type: "address"
843
+ }],
844
+ name: "updateClient",
845
+ outputs: [],
846
+ stateMutability: "nonpayable",
847
+ type: "function"
848
+ }];
849
+ // Wait for the next block so the fetched block's hash is verifiable on-chain
850
+ let currentBlock = await publicClient.getBlockNumber();
851
+ while (currentBlock <= blockNumber) {
852
+ await new Promise(resolve => setTimeout(resolve, 1000));
853
+ currentBlock = await publicClient.getBlockNumber();
854
+ }
855
+ const loopbackClient = await publicClient.readContract({
856
+ address: ibcHandlerAddress,
857
+ abi: IBC_STORE_ABI,
858
+ functionName: "getClient",
859
+ args: [clientId]
860
+ });
861
+ // Submit the transaction
862
+ const txHash = await walletClient.writeContractSync({
863
+ address: loopbackClient,
864
+ abi: LIGHTCLIENT_ABI,
865
+ functionName: "updateClient",
866
+ args: [walletClient.account.address, clientId, clientMessage, walletClient.account.address],
867
+ chain: walletClient.chain,
868
+ account: walletClient.account
869
+ }).then(x => x.transactionHash);
870
+ return {
871
+ txHash,
872
+ blockNumber: block.number,
873
+ stateRoot: block.stateRoot,
874
+ chainId: this.config.destinationChainId
875
+ };
876
+ }
877
+ /**
878
+ * Get redemption history for a secret
879
+ *
880
+ * Queries the Redeemed events filtered by the nullifier derived from the secret.
881
+ * This is a read-only operation that doesn't require a wallet.
882
+ *
883
+ * @param secret - The 32-byte secret as a hex string
884
+ * @param fromBlock - Start block number (default: earliest)
885
+ * @param toBlock - End block number (default: latest)
886
+ * @returns Array of redemption transactions
887
+ */
888
+ getRedemptionHistory(secret, fromBlock, toBlock) {
889
+ return Effect.gen(this, function* () {
890
+ const nullifier = this.getNullifier(secret);
891
+ return yield* pipe(Effect.tryPromise(() => this.dstClient.getRedemptionHistory(this.config.dstZAssetAddress, nullifier, fromBlock, toBlock)), Effect.retry(commonRetry));
892
+ }).pipe(Effect.runPromise);
893
+ }
894
+ /**
895
+ * Get redemption history for a secret
896
+ *
897
+ * Queries the Redeemed events filtered by the nullifier derived from the secret.
898
+ * This is a read-only operation that doesn't require a wallet.
899
+ *
900
+ * @param secret - The 32-byte secret as a hex string
901
+ * @param fromBlock - Start block number (default: earliest)
902
+ * @param toBlock - End block number (default: latest)
903
+ * @returns Array of redemption transactions
904
+ */
905
+ async unsafeGetRedemptionHistory(secret, fromBlock, toBlock) {
906
+ const nullifier = this.getNullifier(secret);
907
+ return this.dstClient.getRedemptionHistory(this.config.dstZAssetAddress, nullifier, fromBlock, toBlock);
908
+ }
909
+ /**
910
+ * Full redeem flow: generate proof + get attestation + submit transaction
911
+ *
912
+ * This method orchestrates the entire redemption process:
913
+ * 1. Generates a ZK proof via the prover server
914
+ * 2. Gets attestation from the attestation service
915
+ * 3. Submits the redeem transaction
916
+ *
917
+ * The wallet client must be connected to the destination chain.
918
+ *
919
+ * @returns Transaction hash, proof, and metadata
920
+ */
921
+ redeem(options) {
922
+ const {
923
+ paymentKey,
924
+ beneficiaries,
925
+ beneficiary,
926
+ amount,
927
+ clientIds,
928
+ selectedClientId,
929
+ walletClient,
930
+ unwrap = true
931
+ } = options;
932
+ // Resolve attestation URL and API key from options or stored config
933
+ const attestationUrl = this.config.attestorUrl;
934
+ const attestorApiKey = this.config.attestorApiKey;
935
+ if (!attestationUrl) {
936
+ throw Error("Attestation URL must be provided either in redeem options or ClientOptions");
937
+ }
938
+ if (!attestorApiKey) {
939
+ throw Error("Attestation API key must be provided either in redeem options or ClientOptions");
940
+ }
941
+ if (!walletClient.account) {
942
+ throw Error("WalletClient must have an account");
943
+ }
944
+ if (!walletClient.chain) {
945
+ throw Error("WalletClient must have a chain configured");
946
+ }
947
+ return Effect.gen(this, function* () {
948
+ // 1. Generate proof
949
+ const proofResult = yield* Effect.tryPromise({
950
+ try: () => this.generateProof(paymentKey, beneficiaries, beneficiary, amount, clientIds, selectedClientId),
951
+ catch: cause => Effect.fail(cause)
952
+ }).pipe(Effect.retry(commonRetry));
953
+ if (!proofResult.proof.success || !proofResult.proof.proofJson || !proofResult.metadata) {
954
+ return yield* Effect.fail(Error(proofResult.proof.error ?? "Proof generation failed"));
955
+ }
956
+ const proofJson = parseProofJson(proofResult.proof.proofJson);
957
+ const metadata = proofResult.metadata;
958
+ const depositAddress = this.getDepositAddress(paymentKey, beneficiaries);
959
+ // 2. Get attestation
960
+ const attestationClient = new AttestationClient(attestationUrl, attestorApiKey);
961
+ const attestationResponse = yield* Effect.tryPromise({
962
+ try: () => attestationClient.getAttestation(depositAddress, beneficiary),
963
+ catch: cause => Effect.fail(cause)
964
+ }).pipe(Effect.retry(commonRetry));
965
+ // 3. Build redeem params
966
+ const redeemParams = proofJsonToRedeemParams(proofJson, {
967
+ lightClients: metadata.lightClients,
968
+ nullifier: metadata.nullifier,
969
+ value: metadata.value,
970
+ beneficiary: metadata.beneficiary,
971
+ attestedMessage: attestationResponse.attestedMessage,
972
+ signature: attestationResponse.signature
973
+ });
974
+ // 4. Submit transaction
975
+ const ZASSET_ABI = [{
976
+ inputs: [{
977
+ name: "proof",
978
+ type: "uint256[8]"
979
+ }, {
980
+ name: "commitments",
981
+ type: "uint256[2]"
982
+ }, {
983
+ name: "commitmentPok",
984
+ type: "uint256[2]"
985
+ }, {
986
+ name: "lightClients",
987
+ type: "tuple[]",
988
+ components: [{
989
+ name: "clientId",
990
+ type: "uint32"
991
+ }, {
992
+ name: "height",
993
+ type: "uint64"
994
+ }]
995
+ }, {
996
+ name: "nullifier",
997
+ type: "uint256"
998
+ }, {
999
+ name: "value",
1000
+ type: "uint256"
1001
+ }, {
1002
+ name: "beneficiary",
1003
+ type: "address"
1004
+ }, {
1005
+ name: "attestedMessage",
1006
+ type: "bytes32"
1007
+ }, {
1008
+ name: "signature",
1009
+ type: "bytes"
1010
+ }, {
1011
+ name: "unwrap",
1012
+ type: "bool"
1013
+ }],
1014
+ name: "redeem",
1015
+ outputs: [],
1016
+ stateMutability: "nonpayable",
1017
+ type: "function"
1018
+ }];
1019
+ const txHash = yield* pipe(evm.writeContract({
1020
+ address: this.config.dstZAssetAddress,
1021
+ abi: ZASSET_ABI,
1022
+ functionName: "redeem",
1023
+ args: [redeemParams.proof, redeemParams.commitments, redeemParams.commitmentPok, redeemParams.lightClients, redeemParams.nullifier, redeemParams.value, redeemParams.beneficiary, redeemParams.attestedMessage, redeemParams.signature, unwrap],
1024
+ chain: walletClient.chain,
1025
+ account: walletClient.account
1026
+ }), Effect.retry(commonRetry));
1027
+ return {
1028
+ txHash,
1029
+ proof: proofJson,
1030
+ metadata
1031
+ };
1032
+ }).pipe(Effect.provide(evm.PublicClient.Live({
1033
+ chain: options.walletClient.chain,
1034
+ transport: http(this.config.destinationRpcUrl)
1035
+ })), Effect.provideService(evm.WalletClient, {
1036
+ client: options.walletClient,
1037
+ account: options.walletClient.account,
1038
+ chain: options.walletClient.chain
1039
+ }), Effect.runPromise);
1040
+ }
1041
+ /**
1042
+ * Full redeem flow: generate proof + get attestation + submit transaction
1043
+ *
1044
+ * This method orchestrates the entire redemption process:
1045
+ * 1. Generates a ZK proof via the prover server
1046
+ * 2. Gets attestation from the attestation service
1047
+ * 3. Submits the redeem transaction
1048
+ *
1049
+ * The wallet client must be connected to the destination chain.
1050
+ *
1051
+ * @returns Transaction hash, proof, and metadata
1052
+ */
1053
+ async unsafeRedeem(options) {
1054
+ const {
1055
+ paymentKey,
1056
+ beneficiaries,
1057
+ beneficiary,
1058
+ amount,
1059
+ clientIds,
1060
+ selectedClientId,
1061
+ walletClient,
1062
+ unwrap = true
1063
+ } = options;
1064
+ // Resolve attestation URL and API key from options or stored config
1065
+ const attestationUrl = this.config.attestorUrl;
1066
+ const attestorApiKey = this.config.attestorApiKey;
1067
+ if (!attestationUrl) {
1068
+ throw new Error("Attestation URL must be provided either in redeem options or ClientOptions");
1069
+ }
1070
+ if (!attestorApiKey) {
1071
+ throw new Error("Attestation API key must be provided either in redeem options or ClientOptions");
1072
+ }
1073
+ if (!walletClient.account) {
1074
+ throw new Error("WalletClient must have an account");
1075
+ }
1076
+ if (!walletClient.chain) {
1077
+ throw new Error("WalletClient must have a chain configured");
1078
+ }
1079
+ // 1. Generate proof
1080
+ const proofResult = await this.generateProof(paymentKey, beneficiaries, beneficiary, amount, clientIds, selectedClientId);
1081
+ if (!proofResult.proof.success || !proofResult.proof.proofJson || !proofResult.metadata) {
1082
+ throw new Error(proofResult.proof.error ?? "Proof generation failed");
1083
+ }
1084
+ const proofJson = parseProofJson(proofResult.proof.proofJson);
1085
+ const metadata = proofResult.metadata;
1086
+ const depositAddress = this.getDepositAddress(paymentKey, beneficiaries);
1087
+ // 2. Get attestation
1088
+ const attestationClient = new AttestationClient(attestationUrl, attestorApiKey);
1089
+ const attestationResponse = await attestationClient.getAttestation(depositAddress, beneficiary);
1090
+ // 3. Build redeem params
1091
+ const redeemParams = proofJsonToRedeemParams(proofJson, {
1092
+ lightClients: metadata.lightClients,
1093
+ nullifier: metadata.nullifier,
1094
+ value: metadata.value,
1095
+ beneficiary: metadata.beneficiary,
1096
+ attestedMessage: attestationResponse.attestedMessage,
1097
+ signature: attestationResponse.signature
1098
+ });
1099
+ // 4. Submit transaction
1100
+ const publicClient = createPublicClient({
1101
+ chain: walletClient.chain,
1102
+ transport: http(this.config.destinationRpcUrl)
1103
+ });
1104
+ const ZASSET_ABI = [{
1105
+ inputs: [{
1106
+ name: "proof",
1107
+ type: "uint256[8]"
1108
+ }, {
1109
+ name: "commitments",
1110
+ type: "uint256[2]"
1111
+ }, {
1112
+ name: "commitmentPok",
1113
+ type: "uint256[2]"
1114
+ }, {
1115
+ name: "lightClients",
1116
+ type: "tuple[]",
1117
+ components: [{
1118
+ name: "clientId",
1119
+ type: "uint32"
1120
+ }, {
1121
+ name: "height",
1122
+ type: "uint64"
1123
+ }]
1124
+ }, {
1125
+ name: "nullifier",
1126
+ type: "uint256"
1127
+ }, {
1128
+ name: "value",
1129
+ type: "uint256"
1130
+ }, {
1131
+ name: "beneficiary",
1132
+ type: "address"
1133
+ }, {
1134
+ name: "attestedMessage",
1135
+ type: "bytes32"
1136
+ }, {
1137
+ name: "signature",
1138
+ type: "bytes"
1139
+ }, {
1140
+ name: "unwrap",
1141
+ type: "bool"
1142
+ }],
1143
+ name: "redeem",
1144
+ outputs: [],
1145
+ stateMutability: "nonpayable",
1146
+ type: "function"
1147
+ }];
1148
+ const txHash = await walletClient.writeContractSync({
1149
+ address: this.config.dstZAssetAddress,
1150
+ abi: ZASSET_ABI,
1151
+ functionName: "redeem",
1152
+ args: [redeemParams.proof, redeemParams.commitments, redeemParams.commitmentPok, redeemParams.lightClients, redeemParams.nullifier, redeemParams.value, redeemParams.beneficiary, redeemParams.attestedMessage, redeemParams.signature, unwrap],
1153
+ chain: walletClient.chain,
1154
+ account: walletClient.account
1155
+ }).then(x => x.transactionHash);
1156
+ const receipt = await publicClient.waitForTransactionReceipt({
1157
+ hash: txHash
1158
+ });
1159
+ if (receipt.status === "reverted") {
1160
+ throw new Error(`Redeem transaction reverted: ${txHash}`);
1161
+ }
1162
+ return {
1163
+ txHash,
1164
+ proof: proofJson,
1165
+ metadata
1166
+ };
1167
+ }
1168
+ /**
1169
+ * Pad beneficiaries array to exactly 4 addresses
1170
+ * Empty array = unbounded mode (all zeros, any beneficiary allowed)
1171
+ */
1172
+ padBeneficiaries(beneficiaries) {
1173
+ if (beneficiaries.length > 4) {
1174
+ throw new Error("Maximum 4 beneficiaries allowed");
1175
+ }
1176
+ const padded = [beneficiaries[0] ?? ZERO_ADDRESS, beneficiaries[1] ?? ZERO_ADDRESS, beneficiaries[2] ?? ZERO_ADDRESS, beneficiaries[3] ?? ZERO_ADDRESS];
1177
+ return padded;
1178
+ }
1179
+ }
1180
+ /**
1181
+ * Wait for predicate on block height
1182
+ * @public
1183
+ */
1184
+ export const waitForBlockCondition = (publicClient, predicate, options) => {
1185
+ const timeoutMs = options?.timeoutMs ?? 60_000;
1186
+ return new Promise((resolve, reject) => {
1187
+ let done = false;
1188
+ const unwatch = publicClient.watchBlockNumber({
1189
+ onBlockNumber(blockNumber) {
1190
+ if (done) return;
1191
+ if (predicate(blockNumber)) {
1192
+ done = true;
1193
+ unwatch();
1194
+ resolve(blockNumber);
1195
+ }
1196
+ },
1197
+ onError(error) {
1198
+ if (done) return;
1199
+ done = true;
1200
+ unwatch();
1201
+ reject(error);
1202
+ }
1203
+ });
1204
+ setTimeout(() => {
1205
+ if (done) return;
1206
+ done = true;
1207
+ unwatch();
1208
+ reject(new Error("Timed out waiting for block condition"));
1209
+ }, timeoutMs);
1210
+ });
1211
+ };
1212
+ //# sourceMappingURL=client.js.map