@multiplatform.one/web3 7.23.1 → 7.24.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 (431) hide show
  1. package/README.md +150 -11
  2. package/dist/cjs/clients/evm.cjs +299 -11
  3. package/dist/cjs/clients/evm.native.js +500 -12
  4. package/dist/cjs/clients/evm.native.js.map +1 -1
  5. package/dist/cjs/clients/index.cjs +5 -0
  6. package/dist/cjs/clients/index.native.js +5 -0
  7. package/dist/cjs/clients/index.native.js.map +1 -1
  8. package/dist/cjs/clients/solana.cjs +39 -21
  9. package/dist/cjs/clients/solana.native.js +48 -23
  10. package/dist/cjs/clients/solana.native.js.map +1 -1
  11. package/dist/cjs/connectkit/GpgProvider.cjs +44 -0
  12. package/dist/cjs/connectkit/GpgProvider.native.js +51 -0
  13. package/dist/cjs/connectkit/GpgProvider.native.js.map +1 -0
  14. package/dist/cjs/connectkit/adapters/BitcoinAdapter.cjs +5 -14
  15. package/dist/cjs/connectkit/adapters/BitcoinAdapter.native.js +5 -15
  16. package/dist/cjs/connectkit/adapters/BitcoinAdapter.native.js.map +1 -1
  17. package/dist/cjs/connectkit/adapters/EthereumAdapter.cjs +6 -15
  18. package/dist/cjs/connectkit/adapters/EthereumAdapter.native.js +7 -16
  19. package/dist/cjs/connectkit/adapters/EthereumAdapter.native.js.map +1 -1
  20. package/dist/cjs/connectkit/adapters/SolanaAdapter.cjs +5 -14
  21. package/dist/cjs/connectkit/adapters/SolanaAdapter.native.js +5 -15
  22. package/dist/cjs/connectkit/adapters/SolanaAdapter.native.js.map +1 -1
  23. package/dist/cjs/connectkit/adapters/SuiAdapter.cjs +5 -14
  24. package/dist/cjs/connectkit/adapters/SuiAdapter.native.js +5 -15
  25. package/dist/cjs/connectkit/adapters/SuiAdapter.native.js.map +1 -1
  26. package/dist/cjs/connectkit/connectors/createWalletMessage.cjs +2 -2
  27. package/dist/cjs/connectkit/connectors/createWalletMessage.native.js +2 -2
  28. package/dist/cjs/connectkit/connectors/createWalletMessage.native.js.map +1 -1
  29. package/dist/cjs/connectkit/index.cjs +4 -3
  30. package/dist/cjs/connectkit/index.native.js +4 -3
  31. package/dist/cjs/connectkit/index.native.js.map +1 -1
  32. package/dist/cjs/connectkit/siwe/SIWEContext.native.js.map +1 -1
  33. package/dist/cjs/connectkit/siwe/SIWEProvider.cjs +18 -3
  34. package/dist/cjs/connectkit/siwe/SIWEProvider.native.js +18 -3
  35. package/dist/cjs/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  36. package/dist/cjs/index.cjs +1 -0
  37. package/dist/cjs/index.native.js +1 -0
  38. package/dist/cjs/index.native.js.map +1 -1
  39. package/dist/cjs/keycloak/KeycloakWalletLogin.cjs +255 -0
  40. package/dist/cjs/keycloak/KeycloakWalletLogin.native.js +33 -0
  41. package/dist/cjs/keycloak/KeycloakWalletLogin.native.js.map +1 -0
  42. package/dist/cjs/keycloak/browserFlow.cjs +83 -0
  43. package/dist/cjs/keycloak/browserFlow.native.js +90 -0
  44. package/dist/cjs/keycloak/browserFlow.native.js.map +1 -0
  45. package/dist/cjs/keycloak/device.cjs +36 -0
  46. package/dist/cjs/keycloak/device.native.js +45 -0
  47. package/dist/cjs/keycloak/device.native.js.map +1 -0
  48. package/dist/cjs/keycloak/directGrant.cjs +189 -0
  49. package/dist/cjs/keycloak/directGrant.native.js +233 -0
  50. package/dist/cjs/keycloak/directGrant.native.js.map +1 -0
  51. package/dist/cjs/keycloak/iife.cjs +4 -0
  52. package/dist/cjs/keycloak/iife.native.js +7 -0
  53. package/dist/cjs/keycloak/iife.native.js.map +1 -0
  54. package/dist/cjs/keycloak/index.cjs +53 -0
  55. package/dist/cjs/keycloak/index.native.js +56 -0
  56. package/dist/cjs/keycloak/index.native.js.map +1 -0
  57. package/dist/cjs/keycloak/keycloakWallet.cjs +214 -0
  58. package/dist/cjs/keycloak/keycloakWallet.native.js +285 -0
  59. package/dist/cjs/keycloak/keycloakWallet.native.js.map +1 -0
  60. package/dist/cjs/keycloak/mount.cjs +53 -0
  61. package/dist/cjs/keycloak/mount.native.js +33 -0
  62. package/dist/cjs/keycloak/mount.native.js.map +1 -0
  63. package/dist/cjs/keycloak/registerWallet.cjs +74 -0
  64. package/dist/cjs/keycloak/registerWallet.native.js +81 -0
  65. package/dist/cjs/keycloak/registerWallet.native.js.map +1 -0
  66. package/dist/cjs/keycloak/types.cjs +46 -0
  67. package/dist/cjs/keycloak/types.native.js +179 -0
  68. package/dist/cjs/keycloak/types.native.js.map +1 -0
  69. package/dist/cjs/keycloak/useDirectLogin.cjs +57 -0
  70. package/dist/cjs/keycloak/useDirectLogin.native.js +77 -0
  71. package/dist/cjs/keycloak/useDirectLogin.native.js.map +1 -0
  72. package/dist/cjs/keycloak/useWalletLogin.cjs +97 -0
  73. package/dist/cjs/keycloak/useWalletLogin.native.js +33 -0
  74. package/dist/cjs/keycloak/useWalletLogin.native.js.map +1 -0
  75. package/dist/cjs/message/buildWalletMessage.cjs +113 -0
  76. package/dist/cjs/message/buildWalletMessage.native.js +121 -0
  77. package/dist/cjs/message/buildWalletMessage.native.js.map +1 -0
  78. package/dist/cjs/message/index.cjs +29 -0
  79. package/dist/cjs/message/index.native.js +32 -0
  80. package/dist/cjs/message/index.native.js.map +1 -0
  81. package/dist/cjs/providers/WalletProvider.cjs +8 -2
  82. package/dist/cjs/siws/message.cjs +5 -16
  83. package/dist/cjs/siws/message.native.js +6 -16
  84. package/dist/cjs/siws/message.native.js.map +1 -1
  85. package/dist/cjs/solana.native.js.map +1 -1
  86. package/dist/esm/clients/evm.mjs +295 -12
  87. package/dist/esm/clients/evm.mjs.map +1 -1
  88. package/dist/esm/clients/evm.native.js +496 -13
  89. package/dist/esm/clients/evm.native.js.map +1 -1
  90. package/dist/esm/clients/index.mjs +2 -2
  91. package/dist/esm/clients/index.mjs.map +1 -1
  92. package/dist/esm/clients/index.native.js +2 -2
  93. package/dist/esm/clients/index.native.js.map +1 -1
  94. package/dist/esm/clients/solana.mjs +39 -21
  95. package/dist/esm/clients/solana.mjs.map +1 -1
  96. package/dist/esm/clients/solana.native.js +48 -23
  97. package/dist/esm/clients/solana.native.js.map +1 -1
  98. package/dist/esm/connectkit/GpgProvider.mjs +19 -0
  99. package/dist/esm/connectkit/GpgProvider.mjs.map +1 -0
  100. package/dist/esm/connectkit/GpgProvider.native.js +23 -0
  101. package/dist/esm/connectkit/GpgProvider.native.js.map +1 -0
  102. package/dist/esm/connectkit/adapters/BitcoinAdapter.mjs +5 -14
  103. package/dist/esm/connectkit/adapters/BitcoinAdapter.mjs.map +1 -1
  104. package/dist/esm/connectkit/adapters/BitcoinAdapter.native.js +5 -15
  105. package/dist/esm/connectkit/adapters/BitcoinAdapter.native.js.map +1 -1
  106. package/dist/esm/connectkit/adapters/EthereumAdapter.mjs +6 -15
  107. package/dist/esm/connectkit/adapters/EthereumAdapter.mjs.map +1 -1
  108. package/dist/esm/connectkit/adapters/EthereumAdapter.native.js +7 -16
  109. package/dist/esm/connectkit/adapters/EthereumAdapter.native.js.map +1 -1
  110. package/dist/esm/connectkit/adapters/SolanaAdapter.mjs +5 -14
  111. package/dist/esm/connectkit/adapters/SolanaAdapter.mjs.map +1 -1
  112. package/dist/esm/connectkit/adapters/SolanaAdapter.native.js +5 -15
  113. package/dist/esm/connectkit/adapters/SolanaAdapter.native.js.map +1 -1
  114. package/dist/esm/connectkit/adapters/SuiAdapter.mjs +5 -14
  115. package/dist/esm/connectkit/adapters/SuiAdapter.mjs.map +1 -1
  116. package/dist/esm/connectkit/adapters/SuiAdapter.native.js +5 -15
  117. package/dist/esm/connectkit/adapters/SuiAdapter.native.js.map +1 -1
  118. package/dist/esm/connectkit/connectors/createWalletMessage.mjs +1 -1
  119. package/dist/esm/connectkit/connectors/createWalletMessage.native.js +1 -1
  120. package/dist/esm/connectkit/index.mjs +3 -2
  121. package/dist/esm/connectkit/index.mjs.map +1 -1
  122. package/dist/esm/connectkit/index.native.js +3 -2
  123. package/dist/esm/connectkit/index.native.js.map +1 -1
  124. package/dist/esm/connectkit/siwe/SIWEContext.mjs.map +1 -1
  125. package/dist/esm/connectkit/siwe/SIWEContext.native.js.map +1 -1
  126. package/dist/esm/connectkit/siwe/SIWEProvider.mjs +19 -4
  127. package/dist/esm/connectkit/siwe/SIWEProvider.mjs.map +1 -1
  128. package/dist/esm/connectkit/siwe/SIWEProvider.native.js +19 -4
  129. package/dist/esm/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  130. package/dist/esm/index.mjs +1 -0
  131. package/dist/esm/index.mjs.map +1 -1
  132. package/dist/esm/index.native.js +1 -0
  133. package/dist/esm/index.native.js.map +1 -1
  134. package/dist/esm/keycloak/KeycloakWalletLogin.mjs +218 -0
  135. package/dist/esm/keycloak/KeycloakWalletLogin.mjs.map +1 -0
  136. package/dist/esm/keycloak/KeycloakWalletLogin.native.js +5 -0
  137. package/dist/esm/keycloak/KeycloakWalletLogin.native.js.map +1 -0
  138. package/dist/esm/keycloak/browserFlow.mjs +58 -0
  139. package/dist/esm/keycloak/browserFlow.mjs.map +1 -0
  140. package/dist/esm/keycloak/browserFlow.native.js +62 -0
  141. package/dist/esm/keycloak/browserFlow.native.js.map +1 -0
  142. package/dist/esm/keycloak/device.mjs +10 -0
  143. package/dist/esm/keycloak/device.mjs.map +1 -0
  144. package/dist/esm/keycloak/device.native.js +16 -0
  145. package/dist/esm/keycloak/device.native.js.map +1 -0
  146. package/dist/esm/keycloak/directGrant.mjs +164 -0
  147. package/dist/esm/keycloak/directGrant.mjs.map +1 -0
  148. package/dist/esm/keycloak/directGrant.native.js +205 -0
  149. package/dist/esm/keycloak/directGrant.native.js.map +1 -0
  150. package/dist/esm/keycloak/iife.mjs +5 -0
  151. package/dist/esm/keycloak/iife.mjs.map +1 -0
  152. package/dist/esm/keycloak/iife.native.js +5 -0
  153. package/dist/esm/keycloak/iife.native.js.map +1 -0
  154. package/dist/esm/keycloak/index.mjs +13 -0
  155. package/dist/esm/keycloak/index.mjs.map +1 -0
  156. package/dist/esm/keycloak/index.native.js +13 -0
  157. package/dist/esm/keycloak/index.native.js.map +1 -0
  158. package/dist/esm/keycloak/keycloakWallet.mjs +186 -0
  159. package/dist/esm/keycloak/keycloakWallet.mjs.map +1 -0
  160. package/dist/esm/keycloak/keycloakWallet.native.js +254 -0
  161. package/dist/esm/keycloak/keycloakWallet.native.js.map +1 -0
  162. package/dist/esm/keycloak/mount.mjs +28 -0
  163. package/dist/esm/keycloak/mount.mjs.map +1 -0
  164. package/dist/esm/keycloak/mount.native.js +5 -0
  165. package/dist/esm/keycloak/mount.native.js.map +1 -0
  166. package/dist/esm/keycloak/registerWallet.mjs +49 -0
  167. package/dist/esm/keycloak/registerWallet.mjs.map +1 -0
  168. package/dist/esm/keycloak/registerWallet.native.js +53 -0
  169. package/dist/esm/keycloak/registerWallet.native.js.map +1 -0
  170. package/dist/esm/keycloak/types.mjs +20 -0
  171. package/dist/esm/keycloak/types.mjs.map +1 -0
  172. package/dist/esm/keycloak/types.native.js +150 -0
  173. package/dist/esm/keycloak/types.native.js.map +1 -0
  174. package/dist/esm/keycloak/useDirectLogin.mjs +32 -0
  175. package/dist/esm/keycloak/useDirectLogin.mjs.map +1 -0
  176. package/dist/esm/keycloak/useDirectLogin.native.js +49 -0
  177. package/dist/esm/keycloak/useDirectLogin.native.js.map +1 -0
  178. package/dist/esm/keycloak/useWalletLogin.mjs +72 -0
  179. package/dist/esm/keycloak/useWalletLogin.mjs.map +1 -0
  180. package/dist/esm/keycloak/useWalletLogin.native.js +5 -0
  181. package/dist/esm/keycloak/useWalletLogin.native.js.map +1 -0
  182. package/dist/esm/message/buildWalletMessage.mjs +87 -0
  183. package/dist/esm/message/buildWalletMessage.mjs.map +1 -0
  184. package/dist/esm/message/buildWalletMessage.native.js +92 -0
  185. package/dist/esm/message/buildWalletMessage.native.js.map +1 -0
  186. package/dist/esm/message/index.mjs +3 -0
  187. package/dist/esm/message/index.mjs.map +1 -0
  188. package/dist/esm/message/index.native.js +3 -0
  189. package/dist/esm/message/index.native.js.map +1 -0
  190. package/dist/esm/providers/WalletProvider.mjs +9 -3
  191. package/dist/esm/providers/WalletProvider.mjs.map +1 -1
  192. package/dist/esm/siws/message.mjs +5 -16
  193. package/dist/esm/siws/message.mjs.map +1 -1
  194. package/dist/esm/siws/message.native.js +6 -16
  195. package/dist/esm/siws/message.native.js.map +1 -1
  196. package/dist/esm/solana.mjs.map +1 -1
  197. package/dist/esm/solana.native.js.map +1 -1
  198. package/dist/jsx/clients/evm.mjs +295 -12
  199. package/dist/jsx/clients/evm.mjs.map +1 -1
  200. package/dist/jsx/clients/evm.native.js +500 -12
  201. package/dist/jsx/clients/evm.native.js.map +1 -1
  202. package/dist/jsx/clients/index.mjs +2 -2
  203. package/dist/jsx/clients/index.mjs.map +1 -1
  204. package/dist/jsx/clients/index.native.js +5 -0
  205. package/dist/jsx/clients/index.native.js.map +1 -1
  206. package/dist/jsx/clients/solana.mjs +39 -21
  207. package/dist/jsx/clients/solana.mjs.map +1 -1
  208. package/dist/jsx/clients/solana.native.js +48 -23
  209. package/dist/jsx/clients/solana.native.js.map +1 -1
  210. package/dist/jsx/connectkit/GpgProvider.mjs +19 -0
  211. package/dist/jsx/connectkit/GpgProvider.mjs.map +1 -0
  212. package/dist/jsx/connectkit/GpgProvider.native.js +51 -0
  213. package/dist/jsx/connectkit/GpgProvider.native.js.map +1 -0
  214. package/dist/jsx/connectkit/adapters/BitcoinAdapter.mjs +5 -14
  215. package/dist/jsx/connectkit/adapters/BitcoinAdapter.mjs.map +1 -1
  216. package/dist/jsx/connectkit/adapters/BitcoinAdapter.native.js +5 -15
  217. package/dist/jsx/connectkit/adapters/BitcoinAdapter.native.js.map +1 -1
  218. package/dist/jsx/connectkit/adapters/EthereumAdapter.mjs +6 -15
  219. package/dist/jsx/connectkit/adapters/EthereumAdapter.mjs.map +1 -1
  220. package/dist/jsx/connectkit/adapters/EthereumAdapter.native.js +7 -16
  221. package/dist/jsx/connectkit/adapters/EthereumAdapter.native.js.map +1 -1
  222. package/dist/jsx/connectkit/adapters/SolanaAdapter.mjs +5 -14
  223. package/dist/jsx/connectkit/adapters/SolanaAdapter.mjs.map +1 -1
  224. package/dist/jsx/connectkit/adapters/SolanaAdapter.native.js +5 -15
  225. package/dist/jsx/connectkit/adapters/SolanaAdapter.native.js.map +1 -1
  226. package/dist/jsx/connectkit/adapters/SuiAdapter.mjs +5 -14
  227. package/dist/jsx/connectkit/adapters/SuiAdapter.mjs.map +1 -1
  228. package/dist/jsx/connectkit/adapters/SuiAdapter.native.js +5 -15
  229. package/dist/jsx/connectkit/adapters/SuiAdapter.native.js.map +1 -1
  230. package/dist/jsx/connectkit/connectors/createWalletMessage.mjs +1 -1
  231. package/dist/jsx/connectkit/connectors/createWalletMessage.native.js +2 -2
  232. package/dist/jsx/connectkit/index.mjs +3 -2
  233. package/dist/jsx/connectkit/index.mjs.map +1 -1
  234. package/dist/jsx/connectkit/index.native.js +4 -3
  235. package/dist/jsx/connectkit/index.native.js.map +1 -1
  236. package/dist/jsx/connectkit/siwe/SIWEContext.mjs.map +1 -1
  237. package/dist/jsx/connectkit/siwe/SIWEContext.native.js.map +1 -1
  238. package/dist/jsx/connectkit/siwe/SIWEProvider.mjs +19 -4
  239. package/dist/jsx/connectkit/siwe/SIWEProvider.mjs.map +1 -1
  240. package/dist/jsx/connectkit/siwe/SIWEProvider.native.js +18 -3
  241. package/dist/jsx/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  242. package/dist/jsx/index.js +1 -0
  243. package/dist/jsx/index.js.map +1 -1
  244. package/dist/jsx/index.mjs +1 -0
  245. package/dist/jsx/index.mjs.map +1 -1
  246. package/dist/jsx/index.native.js +1 -0
  247. package/dist/jsx/index.native.js.map +1 -1
  248. package/dist/jsx/keycloak/KeycloakWalletLogin.mjs +218 -0
  249. package/dist/jsx/keycloak/KeycloakWalletLogin.mjs.map +1 -0
  250. package/dist/jsx/keycloak/KeycloakWalletLogin.native.js +33 -0
  251. package/dist/jsx/keycloak/KeycloakWalletLogin.native.js.map +1 -0
  252. package/dist/jsx/keycloak/browserFlow.mjs +58 -0
  253. package/dist/jsx/keycloak/browserFlow.mjs.map +1 -0
  254. package/dist/jsx/keycloak/browserFlow.native.js +90 -0
  255. package/dist/jsx/keycloak/browserFlow.native.js.map +1 -0
  256. package/dist/jsx/keycloak/device.mjs +10 -0
  257. package/dist/jsx/keycloak/device.mjs.map +1 -0
  258. package/dist/jsx/keycloak/device.native.js +45 -0
  259. package/dist/jsx/keycloak/device.native.js.map +1 -0
  260. package/dist/jsx/keycloak/directGrant.mjs +164 -0
  261. package/dist/jsx/keycloak/directGrant.mjs.map +1 -0
  262. package/dist/jsx/keycloak/directGrant.native.js +233 -0
  263. package/dist/jsx/keycloak/directGrant.native.js.map +1 -0
  264. package/dist/jsx/keycloak/iife.mjs +5 -0
  265. package/dist/jsx/keycloak/iife.mjs.map +1 -0
  266. package/dist/jsx/keycloak/iife.native.js +7 -0
  267. package/dist/jsx/keycloak/iife.native.js.map +1 -0
  268. package/dist/jsx/keycloak/index.mjs +13 -0
  269. package/dist/jsx/keycloak/index.mjs.map +1 -0
  270. package/dist/jsx/keycloak/index.native.js +56 -0
  271. package/dist/jsx/keycloak/index.native.js.map +1 -0
  272. package/dist/jsx/keycloak/keycloakWallet.mjs +186 -0
  273. package/dist/jsx/keycloak/keycloakWallet.mjs.map +1 -0
  274. package/dist/jsx/keycloak/keycloakWallet.native.js +285 -0
  275. package/dist/jsx/keycloak/keycloakWallet.native.js.map +1 -0
  276. package/dist/jsx/keycloak/mount.mjs +28 -0
  277. package/dist/jsx/keycloak/mount.mjs.map +1 -0
  278. package/dist/jsx/keycloak/mount.native.js +33 -0
  279. package/dist/jsx/keycloak/mount.native.js.map +1 -0
  280. package/dist/jsx/keycloak/registerWallet.mjs +49 -0
  281. package/dist/jsx/keycloak/registerWallet.mjs.map +1 -0
  282. package/dist/jsx/keycloak/registerWallet.native.js +81 -0
  283. package/dist/jsx/keycloak/registerWallet.native.js.map +1 -0
  284. package/dist/jsx/keycloak/types.mjs +20 -0
  285. package/dist/jsx/keycloak/types.mjs.map +1 -0
  286. package/dist/jsx/keycloak/types.native.js +179 -0
  287. package/dist/jsx/keycloak/types.native.js.map +1 -0
  288. package/dist/jsx/keycloak/useDirectLogin.mjs +32 -0
  289. package/dist/jsx/keycloak/useDirectLogin.mjs.map +1 -0
  290. package/dist/jsx/keycloak/useDirectLogin.native.js +77 -0
  291. package/dist/jsx/keycloak/useDirectLogin.native.js.map +1 -0
  292. package/dist/jsx/keycloak/useWalletLogin.mjs +72 -0
  293. package/dist/jsx/keycloak/useWalletLogin.mjs.map +1 -0
  294. package/dist/jsx/keycloak/useWalletLogin.native.js +33 -0
  295. package/dist/jsx/keycloak/useWalletLogin.native.js.map +1 -0
  296. package/dist/jsx/message/buildWalletMessage.mjs +87 -0
  297. package/dist/jsx/message/buildWalletMessage.mjs.map +1 -0
  298. package/dist/jsx/message/buildWalletMessage.native.js +121 -0
  299. package/dist/jsx/message/buildWalletMessage.native.js.map +1 -0
  300. package/dist/jsx/message/index.mjs +3 -0
  301. package/dist/jsx/message/index.mjs.map +1 -0
  302. package/dist/jsx/message/index.native.js +32 -0
  303. package/dist/jsx/message/index.native.js.map +1 -0
  304. package/dist/jsx/providers/WalletProvider.mjs +9 -3
  305. package/dist/jsx/providers/WalletProvider.mjs.map +1 -1
  306. package/dist/jsx/siws/message.mjs +5 -16
  307. package/dist/jsx/siws/message.mjs.map +1 -1
  308. package/dist/jsx/siws/message.native.js +6 -16
  309. package/dist/jsx/siws/message.native.js.map +1 -1
  310. package/dist/jsx/solana.mjs.map +1 -1
  311. package/dist/jsx/solana.native.js.map +1 -1
  312. package/dist/keycloak/login.iife.js +3604 -0
  313. package/package.json +27 -8
  314. package/src/clients/evm.spec.ts +644 -10
  315. package/src/clients/evm.ts +498 -10
  316. package/src/clients/index.ts +8 -0
  317. package/src/clients/solana.spec.ts +116 -0
  318. package/src/clients/solana.ts +51 -31
  319. package/src/connectkit/GpgProvider.tsx +16 -0
  320. package/src/connectkit/adapters/BitcoinAdapter.ts +5 -16
  321. package/src/connectkit/adapters/EthereumAdapter.ts +6 -17
  322. package/src/connectkit/adapters/SolanaAdapter.ts +5 -16
  323. package/src/connectkit/adapters/SuiAdapter.ts +5 -16
  324. package/src/connectkit/connectors/createWalletMessage.ts +1 -1
  325. package/src/connectkit/index.ts +2 -6
  326. package/src/connectkit/openConnector/modal.spec.tsx +1 -1
  327. package/src/connectkit/siwe/SIWEContext.tsx +6 -2
  328. package/src/connectkit/siwe/SIWEProvider.tsx +22 -5
  329. package/src/index.ts +3 -0
  330. package/src/keycloak/KeycloakWalletLogin.native.tsx +7 -0
  331. package/src/keycloak/KeycloakWalletLogin.spec.tsx +168 -0
  332. package/src/keycloak/KeycloakWalletLogin.tsx +251 -0
  333. package/src/keycloak/browserFlow.spec.ts +108 -0
  334. package/src/keycloak/browserFlow.ts +84 -0
  335. package/src/keycloak/device.ts +17 -0
  336. package/src/keycloak/directGrant.spec.ts +331 -0
  337. package/src/keycloak/directGrant.ts +214 -0
  338. package/src/keycloak/iife.ts +3 -0
  339. package/src/keycloak/index.ts +44 -0
  340. package/src/keycloak/keycloakWallet.spec.ts +216 -0
  341. package/src/keycloak/keycloakWallet.ts +275 -0
  342. package/src/keycloak/mount.native.ts +11 -0
  343. package/src/keycloak/mount.tsx +45 -0
  344. package/src/keycloak/nonceReset.spec.tsx +205 -0
  345. package/src/keycloak/registerWallet.spec.ts +88 -0
  346. package/src/keycloak/registerWallet.ts +59 -0
  347. package/src/keycloak/types.ts +66 -0
  348. package/src/keycloak/useDirectLogin.spec.tsx +112 -0
  349. package/src/keycloak/useDirectLogin.ts +74 -0
  350. package/src/keycloak/useWalletLogin.native.ts +7 -0
  351. package/src/keycloak/useWalletLogin.ts +99 -0
  352. package/src/message/buildWalletMessage.spec.ts +291 -0
  353. package/src/message/buildWalletMessage.ts +150 -0
  354. package/src/message/index.ts +8 -0
  355. package/src/providers/WalletProvider.tsx +15 -2
  356. package/src/siws/message.ts +3 -22
  357. package/src/solana.ts +1 -0
  358. package/types/clients/evm.d.ts +144 -2
  359. package/types/clients/evm.d.ts.map +1 -1
  360. package/types/clients/index.d.ts +1 -1
  361. package/types/clients/index.d.ts.map +1 -1
  362. package/types/clients/solana.d.ts +14 -5
  363. package/types/clients/solana.d.ts.map +1 -1
  364. package/types/connectkit/GpgProvider.d.ts +10 -0
  365. package/types/connectkit/GpgProvider.d.ts.map +1 -0
  366. package/types/connectkit/adapters/BitcoinAdapter.d.ts.map +1 -1
  367. package/types/connectkit/adapters/EthereumAdapter.d.ts.map +1 -1
  368. package/types/connectkit/adapters/SolanaAdapter.d.ts.map +1 -1
  369. package/types/connectkit/adapters/SuiAdapter.d.ts.map +1 -1
  370. package/types/connectkit/connectors/createWalletMessage.d.ts +1 -1
  371. package/types/connectkit/connectors/createWalletMessage.d.ts.map +1 -1
  372. package/types/connectkit/index.d.ts +3 -2
  373. package/types/connectkit/index.d.ts.map +1 -1
  374. package/types/connectkit/siwe/SIWEContext.d.ts +2 -1
  375. package/types/connectkit/siwe/SIWEContext.d.ts.map +1 -1
  376. package/types/connectkit/siwe/SIWEProvider.d.ts.map +1 -1
  377. package/types/index.d.ts +1 -0
  378. package/types/index.d.ts.map +1 -1
  379. package/types/keycloak/KeycloakWalletLogin.d.ts +45 -0
  380. package/types/keycloak/KeycloakWalletLogin.d.ts.map +1 -0
  381. package/types/keycloak/KeycloakWalletLogin.native.d.ts +4 -0
  382. package/types/keycloak/KeycloakWalletLogin.native.d.ts.map +1 -0
  383. package/types/keycloak/browserFlow.d.ts +27 -0
  384. package/types/keycloak/browserFlow.d.ts.map +1 -0
  385. package/types/keycloak/device.d.ts +14 -0
  386. package/types/keycloak/device.d.ts.map +1 -0
  387. package/types/keycloak/directGrant.d.ts +43 -0
  388. package/types/keycloak/directGrant.d.ts.map +1 -0
  389. package/types/keycloak/iife.d.ts +2 -0
  390. package/types/keycloak/iife.d.ts.map +1 -0
  391. package/types/keycloak/index.d.ts +12 -0
  392. package/types/keycloak/index.d.ts.map +1 -0
  393. package/types/keycloak/keycloakWallet.d.ts +120 -0
  394. package/types/keycloak/keycloakWallet.d.ts.map +1 -0
  395. package/types/keycloak/mount.d.ts +16 -0
  396. package/types/keycloak/mount.d.ts.map +1 -0
  397. package/types/keycloak/mount.native.d.ts +5 -0
  398. package/types/keycloak/mount.native.d.ts.map +1 -0
  399. package/types/keycloak/registerWallet.d.ts +22 -0
  400. package/types/keycloak/registerWallet.d.ts.map +1 -0
  401. package/types/keycloak/types.d.ts +50 -0
  402. package/types/keycloak/types.d.ts.map +1 -0
  403. package/types/keycloak/useDirectLogin.d.ts +29 -0
  404. package/types/keycloak/useDirectLogin.d.ts.map +1 -0
  405. package/types/keycloak/useWalletLogin.d.ts +26 -0
  406. package/types/keycloak/useWalletLogin.d.ts.map +1 -0
  407. package/types/keycloak/useWalletLogin.native.d.ts +4 -0
  408. package/types/keycloak/useWalletLogin.native.d.ts.map +1 -0
  409. package/types/message/buildWalletMessage.d.ts +46 -0
  410. package/types/message/buildWalletMessage.d.ts.map +1 -0
  411. package/types/message/index.d.ts +2 -0
  412. package/types/message/index.d.ts.map +1 -0
  413. package/types/providers/WalletProvider.d.ts +8 -1
  414. package/types/providers/WalletProvider.d.ts.map +1 -1
  415. package/types/siws/message.d.ts.map +1 -1
  416. package/types/solana.d.ts +1 -1
  417. package/types/solana.d.ts.map +1 -1
  418. package/dist/cjs/connectkit/adapters/messages.cjs +0 -73
  419. package/dist/cjs/connectkit/adapters/messages.native.js +0 -79
  420. package/dist/cjs/connectkit/adapters/messages.native.js.map +0 -1
  421. package/dist/esm/connectkit/adapters/messages.mjs +0 -48
  422. package/dist/esm/connectkit/adapters/messages.mjs.map +0 -1
  423. package/dist/esm/connectkit/adapters/messages.native.js +0 -51
  424. package/dist/esm/connectkit/adapters/messages.native.js.map +0 -1
  425. package/dist/jsx/connectkit/adapters/messages.mjs +0 -48
  426. package/dist/jsx/connectkit/adapters/messages.mjs.map +0 -1
  427. package/dist/jsx/connectkit/adapters/messages.native.js +0 -79
  428. package/dist/jsx/connectkit/adapters/messages.native.js.map +0 -1
  429. package/src/connectkit/adapters/messages.ts +0 -84
  430. package/types/connectkit/adapters/messages.d.ts +0 -16
  431. package/types/connectkit/adapters/messages.d.ts.map +0 -1
package/README.md CHANGED
@@ -22,8 +22,10 @@ Peers: `react`, `@tanstack/react-query`.
22
22
  `useBalance`, `useConnect`, `useSignMessage`, `useSwitchChain`, …)
23
23
  - **Components** — `ConnectKitButton`, `WalletButton`, `WalletAvatar`,
24
24
  `WalletStatus`, `NetworkSwitcher`
25
- - **Subpaths** — `./native` (WebView wallet bridge), `./connectkit`, `./vite`
26
- and `./esbuild` (bundler plugins, below)
25
+ - **Subpaths** — `./native` (WebView wallet bridge), `./connectkit`,
26
+ `./message` (the wallet sign-in messages), `./keycloak` (wallet login
27
+ against the Keycloak wallet SPI), `./vite` and `./esbuild` (bundler
28
+ plugins, below)
27
29
 
28
30
  ## Per-chain clients
29
31
 
@@ -34,12 +36,12 @@ or a provider's `request`. Every client shares
34
36
  verifiers take: EVM 0x hex, Solana base58, Sui base64, Bitcoin base64 BIP-322,
35
37
  GPG the armored signature plus the armored public key.
36
38
 
37
- | Hook / factory | What it adds |
38
- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
39
- | `useEvmClient()` / `evmClient({ walletClient } \| { provider, account, chain })` | viem `walletClient` + `publicClient`, `sendTransaction`, `writeContract`, `waitForTransactionReceipt`, `erc20.{transfer, approve, ensureAllowance, balanceOf, allowance, decimals}`, safe for tokens like USDT that return nothing or refuse a non-zero to non-zero approve |
40
- | `useSolanaClient()` / `solanaClient({ signer, rpcUrl?, chain? })` from `./solana` | web only: `@solana/kit` `rpc`, `signTransaction`, `signAndSendTransaction`, `sendTransaction`, `confirmTransaction`, `getBalance`, `transferSol` |
41
- | `useGpgSigner()` / `createGpgSigner()` | the copy/paste GPG signer: `signMessage` parks a request with its terminal `command`; `submit(pasted, request)` resolves it only while `request` is still the pending one and the pasted signature covers its message |
42
- | `useSuiClient()`, `useBitcoinClient()` | message signing only; `signTransaction` / `signPsbt` reject with `UnsupportedClientMethodError` until transactions land |
39
+ | Hook / factory | What it adds |
40
+ | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
41
+ | `useEvmClient()` / `evmClient({ walletClient } \| { provider, account, chain })` | viem `walletClient` + `publicClient`, `sendTransaction`, `writeContract`, `waitForTransactionReceipt`, `confirmTransaction`, `explorerTxUrl`, `erc20.{transfer, approve, ensureAllowance, balanceOf, allowance, decimals}`, safe for tokens like USDT that return nothing or refuse a non-zero to non-zero approve |
42
+ | `useSolanaClient()` / `solanaClient({ signer, rpcUrl?, chain? })` from `./solana` | web only: `@solana/kit` `rpc`, `signTransaction`, `signAndSendTransaction`, `sendTransaction`, `confirmTransaction`, `getBalance`, `transferSol` |
43
+ | `useGpgSigner()` / `createGpgSigner()` | the copy/paste GPG signer: `signMessage` parks a request with its terminal `command`; `submit(pasted, request)` resolves it only while `request` is still the pending one and the pasted signature covers its message |
44
+ | `useSuiClient()`, `useBitcoinClient()` | message signing only; `signTransaction` / `signPsbt` reject with `UnsupportedClientMethodError` until transactions land |
43
45
 
44
46
  ```tsx
45
47
  import { useEvmClient } from "@multiplatform.one/web3";
@@ -56,9 +58,13 @@ await sol?.confirmTransaction(sent!);
56
58
 
57
59
  `transferSol` returns the signature with the blockhash's `lastValidBlockHeight`,
58
60
  and `confirmTransaction` waits until the chain passes that height before it
59
- gives up. Its `SolanaConfirmationError` has `mayStillLand`: `false` means the
60
- transaction failed or expired and a retry is safe; `true` (only when there was
61
- no `lastValidBlockHeight` to judge by) means resending can pay twice.
61
+ gives up. Its `SolanaConfirmationError` has a `reason` and `mayStillLand`.
62
+ `failed` and `expired` set it `false`: the transaction will not land and a retry
63
+ is safe. `timeout` (there was no `lastValidBlockHeight` to judge by) and `rpc`
64
+ (a `getSignatureStatuses` or `getBlockHeight` poll failed, with the transport
65
+ error as `cause`) set it `true`: resending can pay twice, so call
66
+ `confirmTransaction` again on the same submission instead. `lastStatus` is the
67
+ last `confirmationStatus` the poll saw, `null` when it never saw the signature.
62
68
 
63
69
  A Solana client runs over a byte-level `SolanaSigner`: `standardSolanaSigner`
64
70
  (Wallet Standard: Phantom, Solflare, Backpack), `injectedSolanaSigner` (what the
@@ -72,6 +78,107 @@ signs Solana through the WebView bridge, so the root never imports
72
78
  through `solanaMessageClient`, so a login page carries no kit.
73
79
  `tests/clients/importGraph.spec.ts` holds both lines, for native and web.
74
80
 
81
+ ### EVM payments: pending is not failed
82
+
83
+ A sent transaction can sit in the mempool for minutes and still land. viem's
84
+ receipt wait gives up after 180 s with an error that reads like a failure, so
85
+ an app would offer "try again" and the user would pay twice. The EVM client
86
+ never does that:
87
+
88
+ - `waitForTransactionReceipt(hash)` and `confirmTransaction(hash)` wait with
89
+ no timeout. Pass `{ timeout }` for a deadline, which holds even while an
90
+ RPC call hangs. Running out rejects with
91
+ `ReceiptPendingError` (`hash`, `chainId`, `explorerUrl`, `nonce` once the
92
+ node has seen it, `mayStillLand: true`), never a generic error. A failing
93
+ RPC never ends the wait: it backs off, up to 30 s between polls, and
94
+ retries.
95
+ - Pass `{ signal }` and abort it when the screen unmounts. A wait with no
96
+ timeout otherwise polls until the transaction settles, which for a dropped
97
+ one is forever. It rejects with `ReceiptWaitAbortedError`, an `AbortError`.
98
+ - `confirmTransaction` also rejects a reverted receipt with
99
+ `TransactionRevertedError`. `waitForTransactionReceipt` still resolves it,
100
+ as it always has.
101
+ - When another transaction takes the nonce, both reject with
102
+ `TransactionReplacedError`: `reason` is `cancelled` (the wallet's cancel),
103
+ `replaced` (a different transaction), or `unmatched` (the original was never
104
+ seen, so it could be a speed-up). A speed-up resolves with the faster copy's
105
+ receipt. The wait binary-searches the nonce's block however long it slept,
106
+ so resuming one far back needs an RPC that serves state that old, an
107
+ archive node. A chain's default public RPC often keeps only the last 128
108
+ blocks, and past that the wait stays pending.
109
+ - `erc20.ensureAllowance` confirms its approvals the same way and takes the
110
+ same `timeout` and `signal`. `erc20.transfer` and `approve` return once the wallet sends,
111
+ and their rejections classify too.
112
+
113
+ `classifyTxError(error)` sorts any of these, and viem's own errors, into what
114
+ to show:
115
+
116
+ | Kind | Meaning | Show |
117
+ | --------------- | --------------------------------------------------------------------- | ---------------------------------------------- |
118
+ | `user-rejected` | declined or cancelled in the wallet; nothing paid | "Cancelled", buy enabled |
119
+ | `reverted` | the contract refused it, in simulation or on chain; nothing paid | the reason, buy enabled |
120
+ | `pending` | sent with no receipt yet, or its nonce went to what may be a speed-up | "Pending" with the explorer link, buy disabled |
121
+ | `aborted` | the app stopped waiting; the transaction is as pending as it was | nothing; keep the pending hash |
122
+ | `failed` | anything else: no hash came back, or a different transaction won | the error, buy enabled |
123
+
124
+ `failed` with no hash usually means nothing was sent. A wallet that errors
125
+ after the user approved may still have broadcast it, so tell the user to
126
+ check the wallet's activity before paying again.
127
+
128
+ Persist the hash from the moment the wallet returns it, and what `onTrack`
129
+ hands over: the nonce once the node has seen the transaction, and a speed-up's
130
+ hash when one replaces it. A wait resumed after a reload needs the nonce to
131
+ notice a cancel or replacement that landed while the app was closed; without
132
+ it, a transaction the node has forgotten stays pending. A speed-up the page
133
+ never saw can't be told from a replacement after a reload, so it stays
134
+ pending too. Refuse a second buy while one is pending:
135
+
136
+ ```tsx
137
+ import { classifyTxError, useEvmClient } from "@multiplatform.one/web3";
138
+
139
+ const evm = useEvmClient();
140
+ const [pending, setPending] = usePersistedState<{ hash: Hash; nonce?: number } | null>("buy", null);
141
+
142
+ async function settle(hash: Hash, nonce: number | undefined, signal: AbortSignal) {
143
+ try {
144
+ await evm.confirmTransaction(hash, { nonce, signal, onTrack: setPending });
145
+ setPending(null);
146
+ showPaid();
147
+ } catch (error) {
148
+ const kind = classifyTxError(error);
149
+ // aborted: unmounted, and the next mount resumes it. pending: superseded,
150
+ // maybe sped up, so keep it locked.
151
+ if (kind === "aborted" || kind === "pending") return;
152
+ setPending(null);
153
+ showFailure(kind, error);
154
+ }
155
+ }
156
+
157
+ // Every wait belongs to a mounted screen, and stops when it unmounts.
158
+ useEffect(() => {
159
+ if (!evm || !pending) return;
160
+ const controller = new AbortController();
161
+ void settle(pending.hash, pending.nonce, controller.signal);
162
+ return () => controller.abort();
163
+ }, [evm, pending?.hash]);
164
+
165
+ async function buy() {
166
+ if (!evm || pending) return;
167
+ try {
168
+ await evm.erc20.ensureAllowance({ token: qcc, spender: store, amount });
169
+ const hash = await evm.writeContract({ address: store, abi, functionName: "buy", args: [id] });
170
+ setPending({ hash });
171
+ } catch (error) {
172
+ showFailure(classifyTxError(error), error);
173
+ }
174
+ }
175
+ ```
176
+
177
+ While `pending` is set, disable buy and link `evm.explorerTxUrl(pending.hash)`.
178
+ The effect settles it on mount and after a reload; a "check again" button can
179
+ remount it. When the client can't settle it, your backend, which sees the
180
+ purchase land, is the one to release the lock.
181
+
75
182
  ### Solana on mobile (follow-up)
76
183
 
77
184
  The web path is done. A native app cannot reach Phantom through the WebView
@@ -155,6 +262,38 @@ export function App() {
155
262
  }
156
263
  ```
157
264
 
265
+ ## Keycloak direct login and onboarding
266
+
267
+ `kc.directGrant({ clientId })` trades a wallet signature for tokens without a
268
+ browser. A brand-new user, or a realm that later adds a required profile
269
+ field, has required actions Keycloak cannot run on a direct grant: it answers
270
+ 400 "Account is not fully set up", which `login()` rejects as
271
+ `ProfileIncompleteError` and `useDirectLogin` reports as
272
+ `status: "profile-incomplete"`. Open the `url` of `kc.browserLoginUrl({
273
+ clientId, redirectUri })` in the system browser or a WebView page, where
274
+ Keycloak shows its own onboarding form, then call `signIn()` again once it
275
+ redirects back.
276
+
277
+ `browserLoginUrl` draws a fresh `state` and a PKCE S256 verifier on every call
278
+ and returns `{ url, state, codeVerifier }`. Keep `state` and accept the
279
+ redirect only when it matches; `codeVerifier` is for a caller that exchanges
280
+ the code at `kc.tokenUrl`. The client needs `standardFlowEnabled` and the
281
+ redirect URI registered exactly, with no wildcard. A direct-grant client does
282
+ not qualify: mpo's `siwe-public` and `siws-public` have `standardFlowEnabled:
283
+ false`, so mpo's realm carries a separate public client, `wallet-onboarding`
284
+ (PKCE S256 required, redirect URIs `http://localhost:8000/wallet`,
285
+ `http://localhost:3456/wallet` and `multiplatform-one://wallet`). The wallet
286
+ screen in `features/wallet` takes this path on its own.
287
+
288
+ ```tsx
289
+ const { status, signIn } = useDirectLogin(grant);
290
+ if (status === "profile-incomplete") {
291
+ const login = kc.browserLoginUrl({ clientId: "wallet-onboarding", redirectUri: "app://auth" });
292
+ await saveState(login.state);
293
+ await Linking.openURL(login.url);
294
+ }
295
+ ```
296
+
158
297
  ## License
159
298
 
160
299
  Apache-2.0
@@ -22,10 +22,98 @@ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
22
22
  }), mod);
23
23
  var evm_exports = {};
24
24
  __export(evm_exports, {
25
+ ReceiptPendingError: () => ReceiptPendingError,
26
+ ReceiptWaitAbortedError: () => ReceiptWaitAbortedError,
27
+ TransactionReplacedError: () => TransactionReplacedError,
28
+ TransactionRevertedError: () => TransactionRevertedError,
29
+ classifyTxError: () => classifyTxError,
25
30
  evmClient: () => evmClient
26
31
  });
27
32
  module.exports = __toCommonJS(evm_exports);
28
33
  var import_viem = require("viem");
34
+ class ReceiptPendingError extends Error {
35
+ constructor(hash, chainId, options) {
36
+ super(`${options.label ?? "transaction"} ${hash} on chain ${chainId} ${options.detail}; it may still land, so do not resend it`, {
37
+ cause: options.cause
38
+ });
39
+ this.hash = hash;
40
+ this.chainId = chainId;
41
+ this.name = "ReceiptPendingError";
42
+ this.explorerUrl = options.explorerUrl;
43
+ this.nonce = options.nonce;
44
+ }
45
+ hash;
46
+ chainId;
47
+ mayStillLand = true;
48
+ explorerUrl;
49
+ /** Known once the node has seen the transaction. Keep it with the hash to resume the wait. */
50
+ nonce;
51
+ }
52
+ class ReceiptWaitAbortedError extends Error {
53
+ constructor(hash, chainId, nonce, cause) {
54
+ super(`stopped waiting for transaction ${hash} on chain ${chainId}`, {
55
+ cause
56
+ });
57
+ this.hash = hash;
58
+ this.chainId = chainId;
59
+ this.nonce = nonce;
60
+ this.name = "AbortError";
61
+ }
62
+ hash;
63
+ chainId;
64
+ nonce;
65
+ mayStillLand = true;
66
+ }
67
+ class TransactionRevertedError extends Error {
68
+ constructor(receipt, chainId, label = "transaction") {
69
+ super(`${label} ${receipt.transactionHash} reverted in block ${receipt.blockNumber}`);
70
+ this.receipt = receipt;
71
+ this.chainId = chainId;
72
+ this.name = "TransactionRevertedError";
73
+ this.hash = receipt.transactionHash;
74
+ }
75
+ receipt;
76
+ chainId;
77
+ mayStillLand = false;
78
+ hash;
79
+ }
80
+ class TransactionReplacedError extends Error {
81
+ constructor(hash, chainId, reason, replacement) {
82
+ super(`transaction ${hash} was ${reason === "unmatched" ? "superseded" : reason}${replacement ? ` by ${replacement.transactionHash}` : ""}: another transaction took its nonce`);
83
+ this.hash = hash;
84
+ this.chainId = chainId;
85
+ this.reason = reason;
86
+ this.replacement = replacement;
87
+ this.name = "TransactionReplacedError";
88
+ }
89
+ hash;
90
+ chainId;
91
+ reason;
92
+ replacement;
93
+ mayStillLand = false;
94
+ }
95
+ function causes(error) {
96
+ const chain = [];
97
+ for (let e = error; e && typeof e === "object" && chain.length < 16; e = e.cause) {
98
+ if (chain.includes(e)) break;
99
+ chain.push(e);
100
+ }
101
+ return chain;
102
+ }
103
+ function classifyTxError(error) {
104
+ const chain = causes(error);
105
+ const pendingAt = chain.findIndex(e => e.mayStillLand === true || e.name === "WaitForTransactionReceiptTimeoutError" || e.name === "TransactionReplacedError" && e.reason === "unmatched");
106
+ const abortedAt = chain.findIndex(e => e.name === "AbortError" && typeof e.mayStillLand === "boolean");
107
+ if (abortedAt >= 0 && (pendingAt < 0 || abortedAt <= pendingAt)) return "aborted";
108
+ if (pendingAt >= 0) return "pending";
109
+ if (chain.some(e => e.name === "UserRejectedRequestError" || e.code === 4001 || e.name === "TransactionReplacedError" && e.reason === "cancelled")) {
110
+ return "user-rejected";
111
+ }
112
+ if (chain.some(e => e.name === "ContractFunctionRevertedError" || e.name === "ExecutionRevertedError" || e.receipt?.status === "reverted")) {
113
+ return "reverted";
114
+ }
115
+ return "failed";
116
+ }
29
117
  const erc20WriteAbi = [{
30
118
  type: "function",
31
119
  name: "transfer",
@@ -86,16 +174,208 @@ function evmClient(config) {
86
174
  chain
87
175
  });
88
176
  };
89
- const approveAndWait = async (token, spender, amount) => {
177
+ const explorer = chain.blockExplorers?.default.url.replace(/\/+$/, "");
178
+ const explorerTxUrl = hash => explorer ? `${explorer}/tx/${hash}` : void 0;
179
+ const missing = name => error => {
180
+ if (error?.name === name) return void 0;
181
+ throw error;
182
+ };
183
+ const getReceipt = hash => publicClient.getTransactionReceipt({
184
+ hash
185
+ }).catch(missing("TransactionReceiptNotFoundError"));
186
+ const getTransaction = hash => publicClient.getTransaction({
187
+ hash
188
+ }).catch(missing("TransactionNotFoundError"));
189
+ const sameAddress = (a, b) => !!a && !!b && a.toLowerCase() === b.toLowerCase();
190
+ const nonceBlock = async (count, nonce, taken, free) => {
191
+ let hi = taken;
192
+ let lo = -1n;
193
+ if (free !== void 0 && free < hi) lo = free;else {
194
+ for (let step = 1n; hi - step >= 0n; step *= 2n) {
195
+ const probe = hi - step;
196
+ if ((await count(probe)) <= nonce) {
197
+ lo = probe;
198
+ break;
199
+ }
200
+ hi = probe;
201
+ }
202
+ }
203
+ while (hi - lo > 1n) {
204
+ const mid = (lo + hi) / 2n;
205
+ if ((await count(mid)) > nonce) hi = mid;else lo = mid;
206
+ }
207
+ return {
208
+ block: hi,
209
+ free: lo >= 0n ? lo : void 0
210
+ };
211
+ };
212
+ const replacementReason = (taker, original) => {
213
+ if (original && sameAddress(taker.to, original.to) && taker.value === original.value && taker.input === original.input) {
214
+ return "repriced";
215
+ }
216
+ if (sameAddress(taker.to, taker.from) && taker.value === 0n) return "cancelled";
217
+ return original ? "replaced" : "unmatched";
218
+ };
219
+ const after = (ms, fire) => {
220
+ const step = 2 ** 31 - 1;
221
+ let cancel = () => {};
222
+ const arm = left => {
223
+ const id = setTimeout(() => left > step ? arm(left - step) : fire(), Math.min(left, step));
224
+ cancel = () => clearTimeout(id);
225
+ };
226
+ arm(Math.max(0, ms));
227
+ return () => cancel();
228
+ };
229
+ const backoff = failures => {
230
+ const ceiling = Math.min(3e4, Math.max(1, publicClient.pollingInterval) * 2 ** Math.min(failures - 1, 16));
231
+ return ceiling / 2 + Math.random() * ceiling / 2;
232
+ };
233
+ const waitForReceipt = async (hash, options = {}, label) => {
234
+ const {
235
+ signal
236
+ } = options;
237
+ const confirmations = BigInt(Math.max(1, options.confirmations ?? 1));
238
+ const {
239
+ timeout
240
+ } = options;
241
+ const deadline = timeout !== void 0 && Number.isFinite(timeout) && timeout > 0 ? Date.now() + timeout : void 0;
242
+ let target = hash;
243
+ let original;
244
+ let nonce = options.nonce;
245
+ let freeBlock;
246
+ let failures = 0;
247
+ let lastError;
248
+ const aborted = () => new ReceiptWaitAbortedError(hash, chain.id, nonce, signal?.reason);
249
+ const timedOut = () => new ReceiptPendingError(hash, chain.id, {
250
+ detail: `has no receipt after ${timeout} ms`,
251
+ explorerUrl: explorerTxUrl(hash),
252
+ nonce,
253
+ cause: lastError,
254
+ label
255
+ });
256
+ let ended = false;
257
+ const track = () => {
258
+ if (ended || signal?.aborted || nonce === void 0) return;
259
+ try {
260
+ options.onTrack?.({
261
+ hash: target,
262
+ nonce
263
+ });
264
+ } catch {}
265
+ };
266
+ if (signal?.aborted) throw aborted();
267
+ const guard = (promise, onStop = () => {}) => new Promise((resolve, reject) => {
268
+ let cancelTimer = () => {};
269
+ const cleanup = () => {
270
+ cancelTimer();
271
+ signal?.removeEventListener("abort", stop);
272
+ };
273
+ const give = error => {
274
+ cleanup();
275
+ onStop();
276
+ reject(error);
277
+ };
278
+ const stop = () => give(aborted());
279
+ promise.then(resolve, reject).finally(cleanup);
280
+ if (signal?.aborted) return stop();
281
+ signal?.addEventListener("abort", stop, {
282
+ once: true
283
+ });
284
+ if (deadline !== void 0) cancelTimer = after(deadline - Date.now(), () => give(timedOut()));
285
+ });
286
+ const rpc = call => {
287
+ if (ended || signal?.aborted) throw aborted();
288
+ return call();
289
+ };
290
+ const countAt = (address, blockNumber) => rpc(() => publicClient.getTransactionCount({
291
+ address,
292
+ blockNumber
293
+ }));
294
+ const poll = async () => {
295
+ const head = await rpc(() => publicClient.getBlockNumber({
296
+ cacheTime: 0
297
+ }));
298
+ const receipt = await rpc(() => getReceipt(target));
299
+ if (receipt) return head - receipt.blockNumber + 1n >= confirmations ? receipt : void 0;
300
+ if (!original) {
301
+ original = await rpc(() => getTransaction(target));
302
+ if (original && original.nonce !== nonce) {
303
+ nonce = original.nonce;
304
+ track();
305
+ }
306
+ }
307
+ if (nonce === void 0) return void 0;
308
+ const from = original?.from ?? account.address;
309
+ if ((await countAt(from, head)) <= nonce) {
310
+ freeBlock = head;
311
+ return void 0;
312
+ }
313
+ const found = await nonceBlock(n => countAt(from, n), nonce, head, freeBlock);
314
+ freeBlock = found.free;
315
+ const block = await rpc(() => publicClient.getBlock({
316
+ blockNumber: found.block,
317
+ includeTransactions: true
318
+ }));
319
+ const taker = block.transactions.find(tx => sameAddress(tx.from, from) && tx.nonce === nonce);
320
+ if (!taker || taker.hash === target) {
321
+ if (!taker) freeBlock = void 0;
322
+ return void 0;
323
+ }
324
+ const reason = replacementReason(taker, original);
325
+ if (reason === "repriced") {
326
+ target = taker.hash;
327
+ original = taker;
328
+ track();
329
+ return void 0;
330
+ }
331
+ if (head - found.block + 1n < confirmations) return void 0;
332
+ const replacement = await rpc(() => getReceipt(taker.hash));
333
+ throw new TransactionReplacedError(hash, chain.id, reason, replacement);
334
+ };
335
+ try {
336
+ for (;;) {
337
+ try {
338
+ const receipt = await guard(poll());
339
+ if (receipt) return receipt;
340
+ failures = 0;
341
+ } catch (error) {
342
+ if (error instanceof TransactionReplacedError || error instanceof ReceiptWaitAbortedError || error instanceof ReceiptPendingError) {
343
+ throw error;
344
+ }
345
+ lastError = error;
346
+ failures++;
347
+ }
348
+ if (deadline !== void 0 && Date.now() >= deadline) throw timedOut();
349
+ const pause = failures ? backoff(failures) : publicClient.pollingInterval;
350
+ let wake = () => {};
351
+ await guard(new Promise(resolve => {
352
+ wake = after(pause, () => resolve(void 0));
353
+ }), () => wake());
354
+ }
355
+ } finally {
356
+ ended = true;
357
+ }
358
+ };
359
+ const confirmTransaction = async (hash, options, label) => {
360
+ const receipt = await waitForReceipt(hash, options, label);
361
+ if (receipt.status !== "success") throw new TransactionRevertedError(receipt, chain.id, label);
362
+ return receipt;
363
+ };
364
+ const approveAndWait = async (token, spender, amount, options) => {
365
+ if (options.signal?.aborted) {
366
+ throw Object.assign(new Error("stopped before sending the approval", {
367
+ cause: options.signal.reason
368
+ }), {
369
+ name: "AbortError",
370
+ mayStillLand: false
371
+ });
372
+ }
90
373
  const hash = await erc20.approve({
91
374
  token,
92
375
  spender,
93
376
  amount
94
377
  });
95
- const receipt = await publicClient.waitForTransactionReceipt({
96
- hash
97
- });
98
- if (receipt.status !== "success") throw new Error(`approve ${hash} reverted`);
378
+ await confirmTransaction(hash, options, "approve");
99
379
  return hash;
100
380
  };
101
381
  const erc20 = {
@@ -137,12 +417,20 @@ function evmClient(config) {
137
417
  async ensureAllowance({
138
418
  token,
139
419
  spender,
140
- amount
420
+ amount,
421
+ timeout,
422
+ signal
141
423
  }) {
142
424
  const current = await erc20.allowance(token, spender);
143
425
  if (current >= amount) return null;
144
- if (current > 0n) await approveAndWait(token, spender, 0n);
145
- return approveAndWait(token, spender, amount);
426
+ if (current > 0n) await approveAndWait(token, spender, 0n, {
427
+ timeout,
428
+ signal
429
+ });
430
+ return approveAndWait(token, spender, amount, {
431
+ timeout,
432
+ signal
433
+ });
146
434
  }
147
435
  };
148
436
  return {
@@ -163,9 +451,9 @@ function evmClient(config) {
163
451
  ...parameters
164
452
  }),
165
453
  writeContract,
166
- waitForTransactionReceipt: hash => publicClient.waitForTransactionReceipt({
167
- hash
168
- }),
454
+ waitForTransactionReceipt: (hash, options) => waitForReceipt(hash, options),
455
+ confirmTransaction: (hash, options) => confirmTransaction(hash, options),
456
+ explorerTxUrl,
169
457
  erc20
170
458
  };
171
459
  }