@multiplatform.one/web3 7.17.0 → 7.19.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 (421) hide show
  1. package/README.md +60 -0
  2. package/dist/cjs/clients/adapter.cjs +33 -0
  3. package/dist/cjs/clients/adapter.native.js +36 -0
  4. package/dist/cjs/clients/adapter.native.js.map +1 -0
  5. package/dist/cjs/clients/bitcoin.cjs +46 -0
  6. package/dist/cjs/clients/bitcoin.native.js +51 -0
  7. package/dist/cjs/clients/bitcoin.native.js.map +1 -0
  8. package/dist/cjs/clients/connector.cjs +45 -0
  9. package/dist/cjs/clients/connector.native.js +49 -0
  10. package/dist/cjs/clients/connector.native.js.map +1 -0
  11. package/dist/cjs/clients/evm.cjs +171 -0
  12. package/dist/cjs/clients/evm.native.js +198 -0
  13. package/dist/cjs/clients/evm.native.js.map +1 -0
  14. package/dist/cjs/clients/gpg.cjs +31 -0
  15. package/dist/cjs/clients/gpg.native.js +34 -0
  16. package/dist/cjs/clients/gpg.native.js.map +1 -0
  17. package/dist/cjs/clients/hooks.cjs +78 -0
  18. package/dist/cjs/clients/hooks.native.js +85 -0
  19. package/dist/cjs/clients/hooks.native.js.map +1 -0
  20. package/dist/cjs/clients/index.cjs +49 -0
  21. package/dist/cjs/clients/index.native.js +52 -0
  22. package/dist/cjs/clients/index.native.js.map +1 -0
  23. package/dist/cjs/clients/solana.cjs +322 -0
  24. package/dist/cjs/clients/solana.native.js +511 -0
  25. package/dist/cjs/clients/solana.native.js.map +1 -0
  26. package/dist/cjs/clients/solanaMessage.cjs +38 -0
  27. package/dist/cjs/clients/solanaMessage.native.js +44 -0
  28. package/dist/cjs/clients/solanaMessage.native.js.map +1 -0
  29. package/dist/cjs/clients/sui.cjs +46 -0
  30. package/dist/cjs/clients/sui.native.js +51 -0
  31. package/dist/cjs/clients/sui.native.js.map +1 -0
  32. package/dist/cjs/clients/types.cjs +37 -0
  33. package/dist/cjs/clients/types.native.js +160 -0
  34. package/dist/cjs/clients/types.native.js.map +1 -0
  35. package/dist/cjs/clients/useSolanaClient.cjs +50 -0
  36. package/dist/cjs/clients/useSolanaClient.native.js +57 -0
  37. package/dist/cjs/clients/useSolanaClient.native.js.map +1 -0
  38. package/dist/cjs/clients/walletStandard.cjs +63 -0
  39. package/dist/cjs/clients/walletStandard.native.js +71 -0
  40. package/dist/cjs/clients/walletStandard.native.js.map +1 -0
  41. package/dist/cjs/connectkit/components/Common/ConnectorList/index.cjs +33 -5
  42. package/dist/cjs/connectkit/components/Common/ConnectorList/index.native.js +38 -5
  43. package/dist/cjs/connectkit/components/Common/ConnectorList/index.native.js.map +1 -1
  44. package/dist/cjs/connectkit/components/ConnectButton/index.cjs +5 -0
  45. package/dist/cjs/connectkit/components/ConnectButton/index.native.js +5 -0
  46. package/dist/cjs/connectkit/components/ConnectButton/index.native.js.map +1 -1
  47. package/dist/cjs/connectkit/components/ConnectModal/ConnectWithInjector/index.cjs +9 -4
  48. package/dist/cjs/connectkit/components/ConnectModal/ConnectWithInjector/index.native.js +12 -7
  49. package/dist/cjs/connectkit/components/ConnectModal/ConnectWithInjector/index.native.js.map +1 -1
  50. package/dist/cjs/connectkit/connectors/walletAdapterConnector.cjs +2 -0
  51. package/dist/cjs/connectkit/connectors/walletAdapterConnector.native.js +2 -0
  52. package/dist/cjs/connectkit/connectors/walletAdapterConnector.native.js.map +1 -1
  53. package/dist/cjs/connectkit/index.cjs +5 -0
  54. package/dist/cjs/connectkit/index.native.js +5 -0
  55. package/dist/cjs/connectkit/index.native.js.map +1 -1
  56. package/dist/cjs/connectkit/openConnector/context.cjs +146 -0
  57. package/dist/cjs/connectkit/openConnector/context.native.js +188 -0
  58. package/dist/cjs/connectkit/openConnector/context.native.js.map +1 -0
  59. package/dist/cjs/connectkit/openConnector/device.cjs +42 -0
  60. package/dist/cjs/connectkit/openConnector/device.native.js +51 -0
  61. package/dist/cjs/connectkit/openConnector/device.native.js.map +1 -0
  62. package/dist/cjs/connectkit/openConnector/index.cjs +35 -0
  63. package/dist/cjs/connectkit/openConnector/index.native.js +38 -0
  64. package/dist/cjs/connectkit/openConnector/index.native.js.map +1 -0
  65. package/dist/cjs/connectkit/openConnector/launcher.cjs +133 -0
  66. package/dist/cjs/connectkit/openConnector/launcher.native.js +158 -0
  67. package/dist/cjs/connectkit/openConnector/launcher.native.js.map +1 -0
  68. package/dist/cjs/connectkit/screens.cjs +1 -10
  69. package/dist/cjs/connectkit/screens.native.js +1 -12
  70. package/dist/cjs/connectkit/screens.native.js.map +1 -1
  71. package/dist/cjs/connectkit/siwe/SIWEProvider.cjs +4 -5
  72. package/dist/cjs/connectkit/siwe/SIWEProvider.native.js +4 -5
  73. package/dist/cjs/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  74. package/dist/cjs/connectkit/siwe/connectIntent.cjs +9 -5
  75. package/dist/cjs/connectkit/siwe/connectIntent.native.js +10 -3
  76. package/dist/cjs/connectkit/siwe/connectIntent.native.js.map +1 -1
  77. package/dist/cjs/connectkit/useWeb3Modal.cjs +21 -0
  78. package/dist/cjs/connectkit/useWeb3Modal.native.js +22 -0
  79. package/dist/cjs/connectkit/useWeb3Modal.native.js.map +1 -1
  80. package/dist/cjs/connectkit/web3Bridge.cjs +4 -1
  81. package/dist/cjs/connectkit/web3Bridge.native.js +4 -1
  82. package/dist/cjs/connectkit/web3Bridge.native.js.map +1 -1
  83. package/dist/cjs/connectkit/web3Provider.native.js.map +1 -1
  84. package/dist/cjs/index.cjs +2 -1
  85. package/dist/cjs/index.native.js +1 -0
  86. package/dist/cjs/index.native.js.map +1 -1
  87. package/dist/cjs/solana.cjs +41 -0
  88. package/dist/cjs/solana.native.js +44 -0
  89. package/dist/cjs/solana.native.js.map +1 -0
  90. package/dist/esm/clients/adapter.mjs +8 -0
  91. package/dist/esm/clients/adapter.mjs.map +1 -0
  92. package/dist/esm/clients/adapter.native.js +8 -0
  93. package/dist/esm/clients/adapter.native.js.map +1 -0
  94. package/dist/esm/clients/bitcoin.mjs +21 -0
  95. package/dist/esm/clients/bitcoin.mjs.map +1 -0
  96. package/dist/esm/clients/bitcoin.native.js +23 -0
  97. package/dist/esm/clients/bitcoin.native.js.map +1 -0
  98. package/dist/esm/clients/connector.mjs +20 -0
  99. package/dist/esm/clients/connector.mjs.map +1 -0
  100. package/dist/esm/clients/connector.native.js +21 -0
  101. package/dist/esm/clients/connector.native.js.map +1 -0
  102. package/dist/esm/clients/evm.mjs +146 -0
  103. package/dist/esm/clients/evm.mjs.map +1 -0
  104. package/dist/esm/clients/evm.native.js +170 -0
  105. package/dist/esm/clients/evm.native.js.map +1 -0
  106. package/dist/esm/clients/gpg.mjs +3 -0
  107. package/dist/esm/clients/gpg.mjs.map +1 -0
  108. package/dist/esm/clients/gpg.native.js +3 -0
  109. package/dist/esm/clients/gpg.native.js.map +1 -0
  110. package/dist/esm/clients/hooks.mjs +51 -0
  111. package/dist/esm/clients/hooks.mjs.map +1 -0
  112. package/dist/esm/clients/hooks.native.js +55 -0
  113. package/dist/esm/clients/hooks.native.js.map +1 -0
  114. package/dist/esm/clients/index.mjs +11 -0
  115. package/dist/esm/clients/index.mjs.map +1 -0
  116. package/dist/esm/clients/index.native.js +11 -0
  117. package/dist/esm/clients/index.native.js.map +1 -0
  118. package/dist/esm/clients/solana.mjs +289 -0
  119. package/dist/esm/clients/solana.mjs.map +1 -0
  120. package/dist/esm/clients/solana.native.js +475 -0
  121. package/dist/esm/clients/solana.native.js.map +1 -0
  122. package/dist/esm/clients/solanaMessage.mjs +13 -0
  123. package/dist/esm/clients/solanaMessage.mjs.map +1 -0
  124. package/dist/esm/clients/solanaMessage.native.js +16 -0
  125. package/dist/esm/clients/solanaMessage.native.js.map +1 -0
  126. package/dist/esm/clients/sui.mjs +21 -0
  127. package/dist/esm/clients/sui.mjs.map +1 -0
  128. package/dist/esm/clients/sui.native.js +23 -0
  129. package/dist/esm/clients/sui.native.js.map +1 -0
  130. package/dist/esm/clients/types.mjs +12 -0
  131. package/dist/esm/clients/types.mjs.map +1 -0
  132. package/dist/esm/clients/types.native.js +132 -0
  133. package/dist/esm/clients/types.native.js.map +1 -0
  134. package/dist/esm/clients/useSolanaClient.mjs +25 -0
  135. package/dist/esm/clients/useSolanaClient.mjs.map +1 -0
  136. package/dist/esm/clients/useSolanaClient.native.js +29 -0
  137. package/dist/esm/clients/useSolanaClient.native.js.map +1 -0
  138. package/dist/esm/clients/walletStandard.mjs +33 -0
  139. package/dist/esm/clients/walletStandard.mjs.map +1 -0
  140. package/dist/esm/clients/walletStandard.native.js +38 -0
  141. package/dist/esm/clients/walletStandard.native.js.map +1 -0
  142. package/dist/esm/connectkit/components/Common/ConnectorList/index.mjs +34 -6
  143. package/dist/esm/connectkit/components/Common/ConnectorList/index.mjs.map +1 -1
  144. package/dist/esm/connectkit/components/Common/ConnectorList/index.native.js +39 -6
  145. package/dist/esm/connectkit/components/Common/ConnectorList/index.native.js.map +1 -1
  146. package/dist/esm/connectkit/components/ConnectButton/index.mjs +5 -0
  147. package/dist/esm/connectkit/components/ConnectButton/index.mjs.map +1 -1
  148. package/dist/esm/connectkit/components/ConnectButton/index.native.js +5 -0
  149. package/dist/esm/connectkit/components/ConnectButton/index.native.js.map +1 -1
  150. package/dist/esm/connectkit/components/ConnectModal/ConnectWithInjector/index.mjs +9 -4
  151. package/dist/esm/connectkit/components/ConnectModal/ConnectWithInjector/index.mjs.map +1 -1
  152. package/dist/esm/connectkit/components/ConnectModal/ConnectWithInjector/index.native.js +12 -7
  153. package/dist/esm/connectkit/components/ConnectModal/ConnectWithInjector/index.native.js.map +1 -1
  154. package/dist/esm/connectkit/connectors/walletAdapterConnector.mjs +2 -0
  155. package/dist/esm/connectkit/connectors/walletAdapterConnector.mjs.map +1 -1
  156. package/dist/esm/connectkit/connectors/walletAdapterConnector.native.js +2 -0
  157. package/dist/esm/connectkit/connectors/walletAdapterConnector.native.js.map +1 -1
  158. package/dist/esm/connectkit/index.mjs +3 -1
  159. package/dist/esm/connectkit/index.mjs.map +1 -1
  160. package/dist/esm/connectkit/index.native.js +3 -1
  161. package/dist/esm/connectkit/index.native.js.map +1 -1
  162. package/dist/esm/connectkit/openConnector/context.mjs +118 -0
  163. package/dist/esm/connectkit/openConnector/context.mjs.map +1 -0
  164. package/dist/esm/connectkit/openConnector/context.native.js +146 -0
  165. package/dist/esm/connectkit/openConnector/context.native.js.map +1 -0
  166. package/dist/esm/connectkit/openConnector/device.mjs +16 -0
  167. package/dist/esm/connectkit/openConnector/device.mjs.map +1 -0
  168. package/dist/esm/connectkit/openConnector/device.native.js +22 -0
  169. package/dist/esm/connectkit/openConnector/device.native.js.map +1 -0
  170. package/dist/esm/connectkit/openConnector/index.mjs +4 -0
  171. package/dist/esm/connectkit/openConnector/index.mjs.map +1 -0
  172. package/dist/esm/connectkit/openConnector/index.native.js +4 -0
  173. package/dist/esm/connectkit/openConnector/index.native.js.map +1 -0
  174. package/dist/esm/connectkit/openConnector/launcher.mjs +106 -0
  175. package/dist/esm/connectkit/openConnector/launcher.mjs.map +1 -0
  176. package/dist/esm/connectkit/openConnector/launcher.native.js +128 -0
  177. package/dist/esm/connectkit/openConnector/launcher.native.js.map +1 -0
  178. package/dist/esm/connectkit/screens.mjs +2 -11
  179. package/dist/esm/connectkit/screens.mjs.map +1 -1
  180. package/dist/esm/connectkit/screens.native.js +2 -13
  181. package/dist/esm/connectkit/screens.native.js.map +1 -1
  182. package/dist/esm/connectkit/siwe/SIWEProvider.mjs +4 -5
  183. package/dist/esm/connectkit/siwe/SIWEProvider.mjs.map +1 -1
  184. package/dist/esm/connectkit/siwe/SIWEProvider.native.js +4 -5
  185. package/dist/esm/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  186. package/dist/esm/connectkit/siwe/connectIntent.mjs +9 -6
  187. package/dist/esm/connectkit/siwe/connectIntent.mjs.map +1 -1
  188. package/dist/esm/connectkit/siwe/connectIntent.native.js +10 -4
  189. package/dist/esm/connectkit/siwe/connectIntent.native.js.map +1 -1
  190. package/dist/esm/connectkit/useWeb3Modal.mjs +22 -1
  191. package/dist/esm/connectkit/useWeb3Modal.mjs.map +1 -1
  192. package/dist/esm/connectkit/useWeb3Modal.native.js +23 -1
  193. package/dist/esm/connectkit/useWeb3Modal.native.js.map +1 -1
  194. package/dist/esm/connectkit/web3Bridge.mjs +4 -1
  195. package/dist/esm/connectkit/web3Bridge.mjs.map +1 -1
  196. package/dist/esm/connectkit/web3Bridge.native.js +4 -1
  197. package/dist/esm/connectkit/web3Bridge.native.js.map +1 -1
  198. package/dist/esm/connectkit/web3Provider.mjs.map +1 -1
  199. package/dist/esm/connectkit/web3Provider.native.js.map +1 -1
  200. package/dist/esm/index.mjs +1 -0
  201. package/dist/esm/index.mjs.map +1 -1
  202. package/dist/esm/index.native.js +1 -0
  203. package/dist/esm/index.native.js.map +1 -1
  204. package/dist/esm/solana.mjs +5 -0
  205. package/dist/esm/solana.mjs.map +1 -0
  206. package/dist/esm/solana.native.js +5 -0
  207. package/dist/esm/solana.native.js.map +1 -0
  208. package/dist/jsx/clients/adapter.mjs +8 -0
  209. package/dist/jsx/clients/adapter.mjs.map +1 -0
  210. package/dist/jsx/clients/adapter.native.js +36 -0
  211. package/dist/jsx/clients/adapter.native.js.map +1 -0
  212. package/dist/jsx/clients/bitcoin.mjs +21 -0
  213. package/dist/jsx/clients/bitcoin.mjs.map +1 -0
  214. package/dist/jsx/clients/bitcoin.native.js +51 -0
  215. package/dist/jsx/clients/bitcoin.native.js.map +1 -0
  216. package/dist/jsx/clients/connector.mjs +20 -0
  217. package/dist/jsx/clients/connector.mjs.map +1 -0
  218. package/dist/jsx/clients/connector.native.js +49 -0
  219. package/dist/jsx/clients/connector.native.js.map +1 -0
  220. package/dist/jsx/clients/evm.mjs +146 -0
  221. package/dist/jsx/clients/evm.mjs.map +1 -0
  222. package/dist/jsx/clients/evm.native.js +198 -0
  223. package/dist/jsx/clients/evm.native.js.map +1 -0
  224. package/dist/jsx/clients/gpg.mjs +3 -0
  225. package/dist/jsx/clients/gpg.mjs.map +1 -0
  226. package/dist/jsx/clients/gpg.native.js +34 -0
  227. package/dist/jsx/clients/gpg.native.js.map +1 -0
  228. package/dist/jsx/clients/hooks.mjs +51 -0
  229. package/dist/jsx/clients/hooks.mjs.map +1 -0
  230. package/dist/jsx/clients/hooks.native.js +85 -0
  231. package/dist/jsx/clients/hooks.native.js.map +1 -0
  232. package/dist/jsx/clients/index.mjs +11 -0
  233. package/dist/jsx/clients/index.mjs.map +1 -0
  234. package/dist/jsx/clients/index.native.js +52 -0
  235. package/dist/jsx/clients/index.native.js.map +1 -0
  236. package/dist/jsx/clients/solana.mjs +289 -0
  237. package/dist/jsx/clients/solana.mjs.map +1 -0
  238. package/dist/jsx/clients/solana.native.js +511 -0
  239. package/dist/jsx/clients/solana.native.js.map +1 -0
  240. package/dist/jsx/clients/solanaMessage.mjs +13 -0
  241. package/dist/jsx/clients/solanaMessage.mjs.map +1 -0
  242. package/dist/jsx/clients/solanaMessage.native.js +44 -0
  243. package/dist/jsx/clients/solanaMessage.native.js.map +1 -0
  244. package/dist/jsx/clients/sui.mjs +21 -0
  245. package/dist/jsx/clients/sui.mjs.map +1 -0
  246. package/dist/jsx/clients/sui.native.js +51 -0
  247. package/dist/jsx/clients/sui.native.js.map +1 -0
  248. package/dist/jsx/clients/types.mjs +12 -0
  249. package/dist/jsx/clients/types.mjs.map +1 -0
  250. package/dist/jsx/clients/types.native.js +160 -0
  251. package/dist/jsx/clients/types.native.js.map +1 -0
  252. package/dist/jsx/clients/useSolanaClient.mjs +25 -0
  253. package/dist/jsx/clients/useSolanaClient.mjs.map +1 -0
  254. package/dist/jsx/clients/useSolanaClient.native.js +57 -0
  255. package/dist/jsx/clients/useSolanaClient.native.js.map +1 -0
  256. package/dist/jsx/clients/walletStandard.mjs +33 -0
  257. package/dist/jsx/clients/walletStandard.mjs.map +1 -0
  258. package/dist/jsx/clients/walletStandard.native.js +71 -0
  259. package/dist/jsx/clients/walletStandard.native.js.map +1 -0
  260. package/dist/jsx/connectkit/components/Common/ConnectorList/index.mjs +34 -6
  261. package/dist/jsx/connectkit/components/Common/ConnectorList/index.mjs.map +1 -1
  262. package/dist/jsx/connectkit/components/Common/ConnectorList/index.native.js +38 -5
  263. package/dist/jsx/connectkit/components/Common/ConnectorList/index.native.js.map +1 -1
  264. package/dist/jsx/connectkit/components/ConnectButton/index.mjs +5 -0
  265. package/dist/jsx/connectkit/components/ConnectButton/index.mjs.map +1 -1
  266. package/dist/jsx/connectkit/components/ConnectButton/index.native.js +5 -0
  267. package/dist/jsx/connectkit/components/ConnectButton/index.native.js.map +1 -1
  268. package/dist/jsx/connectkit/components/ConnectModal/ConnectWithInjector/index.mjs +9 -4
  269. package/dist/jsx/connectkit/components/ConnectModal/ConnectWithInjector/index.mjs.map +1 -1
  270. package/dist/jsx/connectkit/components/ConnectModal/ConnectWithInjector/index.native.js +12 -7
  271. package/dist/jsx/connectkit/components/ConnectModal/ConnectWithInjector/index.native.js.map +1 -1
  272. package/dist/jsx/connectkit/connectors/walletAdapterConnector.mjs +2 -0
  273. package/dist/jsx/connectkit/connectors/walletAdapterConnector.mjs.map +1 -1
  274. package/dist/jsx/connectkit/connectors/walletAdapterConnector.native.js +2 -0
  275. package/dist/jsx/connectkit/connectors/walletAdapterConnector.native.js.map +1 -1
  276. package/dist/jsx/connectkit/index.mjs +3 -1
  277. package/dist/jsx/connectkit/index.mjs.map +1 -1
  278. package/dist/jsx/connectkit/index.native.js +5 -0
  279. package/dist/jsx/connectkit/index.native.js.map +1 -1
  280. package/dist/jsx/connectkit/openConnector/context.mjs +118 -0
  281. package/dist/jsx/connectkit/openConnector/context.mjs.map +1 -0
  282. package/dist/jsx/connectkit/openConnector/context.native.js +188 -0
  283. package/dist/jsx/connectkit/openConnector/context.native.js.map +1 -0
  284. package/dist/jsx/connectkit/openConnector/device.mjs +16 -0
  285. package/dist/jsx/connectkit/openConnector/device.mjs.map +1 -0
  286. package/dist/jsx/connectkit/openConnector/device.native.js +51 -0
  287. package/dist/jsx/connectkit/openConnector/device.native.js.map +1 -0
  288. package/dist/jsx/connectkit/openConnector/index.mjs +4 -0
  289. package/dist/jsx/connectkit/openConnector/index.mjs.map +1 -0
  290. package/dist/jsx/connectkit/openConnector/index.native.js +38 -0
  291. package/dist/jsx/connectkit/openConnector/index.native.js.map +1 -0
  292. package/dist/jsx/connectkit/openConnector/launcher.mjs +106 -0
  293. package/dist/jsx/connectkit/openConnector/launcher.mjs.map +1 -0
  294. package/dist/jsx/connectkit/openConnector/launcher.native.js +158 -0
  295. package/dist/jsx/connectkit/openConnector/launcher.native.js.map +1 -0
  296. package/dist/jsx/connectkit/screens.mjs +2 -11
  297. package/dist/jsx/connectkit/screens.mjs.map +1 -1
  298. package/dist/jsx/connectkit/screens.native.js +1 -12
  299. package/dist/jsx/connectkit/screens.native.js.map +1 -1
  300. package/dist/jsx/connectkit/siwe/SIWEProvider.mjs +4 -5
  301. package/dist/jsx/connectkit/siwe/SIWEProvider.mjs.map +1 -1
  302. package/dist/jsx/connectkit/siwe/SIWEProvider.native.js +4 -5
  303. package/dist/jsx/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  304. package/dist/jsx/connectkit/siwe/connectIntent.mjs +9 -6
  305. package/dist/jsx/connectkit/siwe/connectIntent.mjs.map +1 -1
  306. package/dist/jsx/connectkit/siwe/connectIntent.native.js +10 -3
  307. package/dist/jsx/connectkit/siwe/connectIntent.native.js.map +1 -1
  308. package/dist/jsx/connectkit/useWeb3Modal.mjs +22 -1
  309. package/dist/jsx/connectkit/useWeb3Modal.mjs.map +1 -1
  310. package/dist/jsx/connectkit/useWeb3Modal.native.js +22 -0
  311. package/dist/jsx/connectkit/useWeb3Modal.native.js.map +1 -1
  312. package/dist/jsx/connectkit/web3Bridge.mjs +4 -1
  313. package/dist/jsx/connectkit/web3Bridge.mjs.map +1 -1
  314. package/dist/jsx/connectkit/web3Bridge.native.js +4 -1
  315. package/dist/jsx/connectkit/web3Bridge.native.js.map +1 -1
  316. package/dist/jsx/connectkit/web3Provider.mjs.map +1 -1
  317. package/dist/jsx/connectkit/web3Provider.native.js.map +1 -1
  318. package/dist/jsx/index.js +1 -0
  319. package/dist/jsx/index.js.map +1 -1
  320. package/dist/jsx/index.mjs +1 -0
  321. package/dist/jsx/index.mjs.map +1 -1
  322. package/dist/jsx/index.native.js +1 -0
  323. package/dist/jsx/index.native.js.map +1 -1
  324. package/dist/jsx/solana.mjs +5 -0
  325. package/dist/jsx/solana.mjs.map +1 -0
  326. package/dist/jsx/solana.native.js +44 -0
  327. package/dist/jsx/solana.native.js.map +1 -0
  328. package/package.json +14 -6
  329. package/src/clients/adapter.ts +13 -0
  330. package/src/clients/bitcoin.ts +42 -0
  331. package/src/clients/connector.spec.ts +78 -0
  332. package/src/clients/connector.ts +36 -0
  333. package/src/clients/evm.spec.ts +265 -0
  334. package/src/clients/evm.ts +223 -0
  335. package/src/clients/gpg.spec.ts +169 -0
  336. package/src/clients/gpg.ts +8 -0
  337. package/src/clients/hooks.spec.tsx +113 -0
  338. package/src/clients/hooks.ts +51 -0
  339. package/src/clients/index.ts +40 -0
  340. package/src/clients/solana.spec.ts +444 -0
  341. package/src/clients/solana.ts +465 -0
  342. package/src/clients/solanaMessage.ts +34 -0
  343. package/src/clients/sui.ts +42 -0
  344. package/src/clients/types.ts +40 -0
  345. package/src/clients/useSolanaClient.ts +31 -0
  346. package/src/clients/walletStandard.ts +87 -0
  347. package/src/connectkit/components/Common/ConnectorList/index.tsx +30 -2
  348. package/src/connectkit/components/ConnectButton/index.tsx +5 -0
  349. package/src/connectkit/components/ConnectModal/ConnectWithInjector/index.tsx +13 -8
  350. package/src/connectkit/connectors/walletAdapterConnector.ts +2 -0
  351. package/src/connectkit/index.ts +8 -0
  352. package/src/connectkit/openConnector/context.tsx +176 -0
  353. package/src/connectkit/openConnector/device.spec.ts +86 -0
  354. package/src/connectkit/openConnector/device.ts +37 -0
  355. package/src/connectkit/openConnector/index.ts +18 -0
  356. package/src/connectkit/openConnector/launcher.spec.ts +325 -0
  357. package/src/connectkit/openConnector/launcher.ts +203 -0
  358. package/src/connectkit/openConnector/modal.spec.tsx +330 -0
  359. package/src/connectkit/screens.tsx +2 -11
  360. package/src/connectkit/siwe/SIWEProvider.spec.tsx +112 -0
  361. package/src/connectkit/siwe/SIWEProvider.tsx +6 -10
  362. package/src/connectkit/siwe/connectIntent.spec.ts +90 -0
  363. package/src/connectkit/siwe/connectIntent.ts +19 -6
  364. package/src/connectkit/useWeb3Modal.ts +25 -1
  365. package/src/connectkit/web3Bridge.tsx +4 -1
  366. package/src/connectkit/web3Provider.tsx +4 -1
  367. package/src/index.ts +4 -0
  368. package/src/solana.ts +30 -0
  369. package/types/clients/adapter.d.ts +5 -0
  370. package/types/clients/adapter.d.ts.map +1 -0
  371. package/types/clients/bitcoin.d.ts +21 -0
  372. package/types/clients/bitcoin.d.ts.map +1 -0
  373. package/types/clients/connector.d.ts +14 -0
  374. package/types/clients/connector.d.ts.map +1 -0
  375. package/types/clients/evm.d.ts +68 -0
  376. package/types/clients/evm.d.ts.map +1 -0
  377. package/types/clients/gpg.d.ts +2 -0
  378. package/types/clients/gpg.d.ts.map +1 -0
  379. package/types/clients/hooks.d.ts +16 -0
  380. package/types/clients/hooks.d.ts.map +1 -0
  381. package/types/clients/index.d.ts +10 -0
  382. package/types/clients/index.d.ts.map +1 -0
  383. package/types/clients/solana.d.ts +111 -0
  384. package/types/clients/solana.d.ts.map +1 -0
  385. package/types/clients/solanaMessage.d.ts +18 -0
  386. package/types/clients/solanaMessage.d.ts.map +1 -0
  387. package/types/clients/sui.d.ts +21 -0
  388. package/types/clients/sui.d.ts.map +1 -0
  389. package/types/clients/types.d.ts +27 -0
  390. package/types/clients/types.d.ts.map +1 -0
  391. package/types/clients/useSolanaClient.d.ts +11 -0
  392. package/types/clients/useSolanaClient.d.ts.map +1 -0
  393. package/types/clients/walletStandard.d.ts +63 -0
  394. package/types/clients/walletStandard.d.ts.map +1 -0
  395. package/types/connectkit/components/Common/ConnectorList/index.d.ts.map +1 -1
  396. package/types/connectkit/components/ConnectButton/index.d.ts.map +1 -1
  397. package/types/connectkit/components/ConnectModal/ConnectWithInjector/index.d.ts.map +1 -1
  398. package/types/connectkit/connectors/walletAdapterConnector.d.ts.map +1 -1
  399. package/types/connectkit/index.d.ts +2 -0
  400. package/types/connectkit/index.d.ts.map +1 -1
  401. package/types/connectkit/openConnector/context.d.ts +48 -0
  402. package/types/connectkit/openConnector/context.d.ts.map +1 -0
  403. package/types/connectkit/openConnector/device.d.ts +18 -0
  404. package/types/connectkit/openConnector/device.d.ts.map +1 -0
  405. package/types/connectkit/openConnector/index.d.ts +3 -0
  406. package/types/connectkit/openConnector/index.d.ts.map +1 -0
  407. package/types/connectkit/openConnector/launcher.d.ts +64 -0
  408. package/types/connectkit/openConnector/launcher.d.ts.map +1 -0
  409. package/types/connectkit/screens.d.ts.map +1 -1
  410. package/types/connectkit/siwe/SIWEProvider.d.ts.map +1 -1
  411. package/types/connectkit/siwe/connectIntent.d.ts +8 -3
  412. package/types/connectkit/siwe/connectIntent.d.ts.map +1 -1
  413. package/types/connectkit/useWeb3Modal.d.ts +16 -0
  414. package/types/connectkit/useWeb3Modal.d.ts.map +1 -1
  415. package/types/connectkit/web3Bridge.d.ts.map +1 -1
  416. package/types/connectkit/web3Provider.d.ts +4 -1
  417. package/types/connectkit/web3Provider.d.ts.map +1 -1
  418. package/types/index.d.ts +1 -0
  419. package/types/index.d.ts.map +1 -1
  420. package/types/solana.d.ts +4 -0
  421. package/types/solana.d.ts.map +1 -0
@@ -0,0 +1,265 @@
1
+ import { beforeEach, describe, expect, it } from "vitest";
2
+ import {
3
+ createPublicClient,
4
+ custom,
5
+ decodeFunctionData,
6
+ encodeAbiParameters,
7
+ erc20Abi,
8
+ toHex,
9
+ type Address,
10
+ type Hex,
11
+ } from "viem";
12
+ import { mainnet } from "viem/chains";
13
+ import { evmClient } from "./evm";
14
+
15
+ const account = "0x1111111111111111111111111111111111111111" as Address;
16
+ const token = "0x2222222222222222222222222222222222222222" as Address;
17
+ const spender = "0x3333333333333333333333333333333333333333" as Address;
18
+ const txHash = `0x${"ab".repeat(32)}` as Hex;
19
+ const hashFor = (n: number) => `0x${n.toString(16).padStart(64, "0")}` as Hex;
20
+
21
+ interface Call {
22
+ method: string;
23
+ params?: unknown;
24
+ }
25
+
26
+ interface ChainState {
27
+ allowance: bigint;
28
+ balance: bigint;
29
+ /** USDT: transfer/approve return no data, and approve reverts non-zero to non-zero. */
30
+ usdt?: boolean;
31
+ /** Hashes whose receipt comes back reverted. */
32
+ reverted?: Set<Hex>;
33
+ }
34
+
35
+ const revert = () => Object.assign(new Error("execution reverted"), { code: 3, data: "0x" as Hex });
36
+
37
+ function mockProvider(state: ChainState) {
38
+ const calls: Call[] = [];
39
+ const sent: Hex[] = [];
40
+ const provider = {
41
+ async request({ method, params }: Call) {
42
+ calls.push({ method, params });
43
+ switch (method) {
44
+ case "eth_chainId":
45
+ return toHex(mainnet.id);
46
+ case "personal_sign":
47
+ return "0xsigned";
48
+ case "eth_sendTransaction": {
49
+ const [{ data }] = params as [{ data?: Hex }];
50
+ const hash = sent.length === 0 ? txHash : hashFor(sent.length + 1);
51
+ sent.push(hash);
52
+ if (data) {
53
+ const { functionName, args } = decodeFunctionData({ abi: erc20Abi, data });
54
+ if (functionName === "approve" && !state.reverted?.has(hash)) {
55
+ state.allowance = (args as [Address, bigint])[1];
56
+ }
57
+ }
58
+ return hash;
59
+ }
60
+ case "eth_getTransactionReceipt": {
61
+ const [hash] = params as [Hex];
62
+ if (!sent.includes(hash)) return null;
63
+ return {
64
+ transactionHash: hash,
65
+ transactionIndex: "0x0",
66
+ blockHash: `0x${"cd".repeat(32)}`,
67
+ blockNumber: "0x10",
68
+ from: account,
69
+ to: token,
70
+ cumulativeGasUsed: "0x5208",
71
+ gasUsed: "0x5208",
72
+ effectiveGasPrice: "0x1",
73
+ contractAddress: null,
74
+ logs: [],
75
+ logsBloom: `0x${"00".repeat(256)}`,
76
+ status: state.reverted?.has(hash) ? "0x0" : "0x1",
77
+ type: "0x2",
78
+ };
79
+ }
80
+ case "eth_estimateGas":
81
+ return "0x5208";
82
+ case "eth_blockNumber":
83
+ return "0x10";
84
+ case "eth_call": {
85
+ const [{ data }] = params as [{ data: Hex }];
86
+ const { functionName, args } = decodeFunctionData({ abi: erc20Abi, data });
87
+ if (functionName === "allowance")
88
+ return encodeAbiParameters([{ type: "uint256" }], [state.allowance]);
89
+ if (functionName === "balanceOf")
90
+ return encodeAbiParameters([{ type: "uint256" }], [state.balance]);
91
+ if (functionName === "decimals") return encodeAbiParameters([{ type: "uint8" }], [18]);
92
+ if (!state.usdt) return encodeAbiParameters([{ type: "bool" }], [true]);
93
+ if (
94
+ functionName === "approve" &&
95
+ state.allowance > 0n &&
96
+ (args as [Address, bigint])[1] > 0n
97
+ ) {
98
+ throw revert();
99
+ }
100
+ return "0x";
101
+ }
102
+ default:
103
+ throw new Error(`unmocked ${method}`);
104
+ }
105
+ },
106
+ };
107
+ const sentTransaction = <T>() => {
108
+ const call = calls.find((c) => c.method === "eth_sendTransaction");
109
+ if (!call) throw new Error("no eth_sendTransaction");
110
+ return (call.params as [T])[0];
111
+ };
112
+ /** Each ERC-20 approve amount sent, in order. */
113
+ const approvals = () =>
114
+ calls
115
+ .filter((c) => c.method === "eth_sendTransaction")
116
+ .map((c) =>
117
+ decodeFunctionData({ abi: erc20Abi, data: (c.params as [{ data: Hex }])[0].data }),
118
+ )
119
+ .filter((d) => d.functionName === "approve")
120
+ .map((d) => (d.args as [Address, bigint])[1]);
121
+ return { provider, calls, sent, sentTransaction, approvals };
122
+ }
123
+
124
+ describe("evmClient", () => {
125
+ let state: ChainState;
126
+ let mock: ReturnType<typeof mockProvider>;
127
+ let client: ReturnType<typeof evmClient>;
128
+
129
+ beforeEach(() => {
130
+ state = { allowance: 0n, balance: 5n * 10n ** 18n };
131
+ mock = mockProvider(state);
132
+ client = evmClient({
133
+ provider: mock.provider as never,
134
+ account,
135
+ chain: mainnet,
136
+ publicClient: createPublicClient({
137
+ chain: mainnet,
138
+ pollingInterval: 1,
139
+ transport: custom(mock.provider),
140
+ }),
141
+ });
142
+ });
143
+
144
+ it("shares the common client shape", () => {
145
+ expect(client.family).toBe("evm");
146
+ expect(client.address).toBe(account);
147
+ expect(client.chainId).toBe(1);
148
+ expect(client.capabilities).toEqual(["signMessage", "sendTransaction", "writeContract"]);
149
+ });
150
+
151
+ it("signs with personal_sign on the connected account", async () => {
152
+ await expect(client.signMessage("hello")).resolves.toBe("0xsigned");
153
+ const call = mock.calls.find((c) => c.method === "personal_sign");
154
+ expect(call?.params).toEqual([toHex("hello"), account]);
155
+ });
156
+
157
+ it("sends a transaction from the connected account", async () => {
158
+ await expect(client.sendTransaction({ to: spender, value: 1n })).resolves.toBe(txHash);
159
+ const tx = mock.sentTransaction<{ from: Address; to: Address; value: Hex }>();
160
+ expect(tx.from.toLowerCase()).toBe(account.toLowerCase());
161
+ expect(tx.to).toBe(spender);
162
+ expect(tx.value).toBe("0x1");
163
+ });
164
+
165
+ it("writes a contract call", async () => {
166
+ await client.writeContract({
167
+ address: token,
168
+ abi: erc20Abi,
169
+ functionName: "transfer",
170
+ args: [spender, 7n],
171
+ });
172
+ const tx = mock.sentTransaction<{ to: Address; data: Hex }>();
173
+ expect(tx.to).toBe(token);
174
+ expect(decodeFunctionData({ abi: erc20Abi, data: tx.data })).toEqual({
175
+ functionName: "transfer",
176
+ args: [spender, 7n],
177
+ });
178
+ });
179
+
180
+ it("simulates an ERC-20 transfer before sending it", async () => {
181
+ await expect(client.erc20.transfer({ token, to: spender, amount: 3n })).resolves.toBe(txHash);
182
+ const methods = mock.calls.map((c) => c.method);
183
+ expect(methods.indexOf("eth_call")).toBeLessThan(methods.indexOf("eth_sendTransaction"));
184
+ const tx = mock.sentTransaction<{ data: Hex }>();
185
+ expect(decodeFunctionData({ abi: erc20Abi, data: tx.data })).toEqual({
186
+ functionName: "transfer",
187
+ args: [spender, 3n],
188
+ });
189
+ });
190
+
191
+ it("approves a spender", async () => {
192
+ await client.erc20.approve({ token, spender, amount: 9n });
193
+ const tx = mock.sentTransaction<{ data: Hex }>();
194
+ expect(decodeFunctionData({ abi: erc20Abi, data: tx.data })).toEqual({
195
+ functionName: "approve",
196
+ args: [spender, 9n],
197
+ });
198
+ });
199
+
200
+ it("reads balance, allowance and decimals", async () => {
201
+ state.allowance = 4n;
202
+ await expect(client.erc20.balanceOf(token)).resolves.toBe(5n * 10n ** 18n);
203
+ await expect(client.erc20.allowance(token, spender)).resolves.toBe(4n);
204
+ await expect(client.erc20.decimals(token)).resolves.toBe(18);
205
+ });
206
+
207
+ it("skips the approval when the allowance already covers the amount", async () => {
208
+ state.allowance = 100n;
209
+ await expect(client.erc20.ensureAllowance({ token, spender, amount: 50n })).resolves.toBeNull();
210
+ expect(mock.calls.some((c) => c.method === "eth_sendTransaction")).toBe(false);
211
+ });
212
+
213
+ it("sends transfer and approve to a token that returns nothing, as USDT does", async () => {
214
+ state.usdt = true;
215
+ await expect(client.erc20.transfer({ token, to: spender, amount: 3n })).resolves.toBe(txHash);
216
+ await expect(client.erc20.approve({ token, spender, amount: 9n })).resolves.toBe(hashFor(2));
217
+ });
218
+
219
+ it("approves from a zero allowance and waits for the approval to be mined", async () => {
220
+ await expect(client.erc20.ensureAllowance({ token, spender, amount: 50n })).resolves.toBe(
221
+ txHash,
222
+ );
223
+ expect(mock.approvals()).toEqual([50n]);
224
+ const methods = mock.calls.map((c) => c.method);
225
+ expect(methods.indexOf("eth_getTransactionReceipt")).toBeGreaterThan(
226
+ methods.indexOf("eth_sendTransaction"),
227
+ );
228
+ });
229
+
230
+ it("resets a non-zero allowance to 0 before raising it, which USDT requires", async () => {
231
+ state.usdt = true;
232
+ state.allowance = 5n;
233
+ await expect(client.erc20.ensureAllowance({ token, spender, amount: 50n })).resolves.toBe(
234
+ hashFor(2),
235
+ );
236
+ expect(mock.approvals()).toEqual([0n, 50n]);
237
+ expect(state.allowance).toBe(50n);
238
+ const receipts = mock.calls.filter((c) => c.method === "eth_getTransactionReceipt");
239
+ expect(receipts.map((c) => (c.params as [Hex])[0])).toContain(txHash);
240
+ });
241
+
242
+ it("throws when the approval reverts", async () => {
243
+ state.reverted = new Set([txHash]);
244
+ await expect(client.erc20.ensureAllowance({ token, spender, amount: 50n })).rejects.toThrow(
245
+ `approve ${txHash} reverted`,
246
+ );
247
+ expect(state.allowance).toBe(0n);
248
+ });
249
+
250
+ it("stops at a reverted reset and never sends the second approval", async () => {
251
+ state.usdt = true;
252
+ state.allowance = 5n;
253
+ state.reverted = new Set([txHash]);
254
+ await expect(client.erc20.ensureAllowance({ token, spender, amount: 50n })).rejects.toThrow(
255
+ /reverted/,
256
+ );
257
+ expect(mock.approvals()).toEqual([0n]);
258
+ });
259
+
260
+ it("wraps an existing viem wallet client", () => {
261
+ const wrapped = evmClient({ walletClient: client.walletClient });
262
+ expect(wrapped.address).toBe(account);
263
+ expect(wrapped.chain.id).toBe(1);
264
+ });
265
+ });
@@ -0,0 +1,223 @@
1
+ import {
2
+ createPublicClient,
3
+ createWalletClient,
4
+ custom,
5
+ erc20Abi,
6
+ http,
7
+ type Abi,
8
+ type Account,
9
+ type Address,
10
+ type Chain,
11
+ type ContractFunctionArgs,
12
+ type ContractFunctionName,
13
+ type EIP1193Provider,
14
+ type Hash,
15
+ type Hex,
16
+ type PublicClient,
17
+ type SendTransactionParameters,
18
+ type TransactionReceipt,
19
+ type Transport,
20
+ type WalletClient,
21
+ type WriteContractParameters,
22
+ } from "viem";
23
+ import type { ChainClient, ClientCapability } from "./types";
24
+
25
+ /** A viem wallet client with its account and chain hoisted, the shape wagmi's getWalletClient returns. */
26
+ export type EvmWalletClient = WalletClient<Transport, Chain, Account>;
27
+
28
+ type WritableFunctionName<abi extends Abi | readonly unknown[]> = ContractFunctionName<
29
+ abi,
30
+ "nonpayable" | "payable"
31
+ >;
32
+
33
+ export type EvmWriteContractParameters<
34
+ abi extends Abi | readonly unknown[] = Abi,
35
+ functionName extends WritableFunctionName<abi> = WritableFunctionName<abi>,
36
+ args extends ContractFunctionArgs<abi, "nonpayable" | "payable", functionName> =
37
+ ContractFunctionArgs<abi, "nonpayable" | "payable", functionName>,
38
+ > = WriteContractParameters<abi, functionName, args, Chain, Account>;
39
+
40
+ export type EvmSendTransactionParameters = SendTransactionParameters<Chain, Account>;
41
+
42
+ export interface Erc20Actions {
43
+ balanceOf(token: Address, owner?: Address): Promise<bigint>;
44
+ allowance(token: Address, spender: Address, owner?: Address): Promise<bigint>;
45
+ decimals(token: Address): Promise<number>;
46
+ /** Simulates, then sends `transfer(to, amount)`. `amount` is in the token's base units. */
47
+ transfer(args: { token: Address; to: Address; amount: bigint }): Promise<Hash>;
48
+ /** Simulates, then sends `approve(spender, amount)`. */
49
+ approve(args: { token: Address; spender: Address; amount: bigint }): Promise<Hash>;
50
+ /**
51
+ * Approves `amount` only when the allowance is below it, and waits for that
52
+ * approval to be mined so a purchase call right after it sees the allowance.
53
+ * A non-zero allowance is reset to 0 first, since USDT refuses to move one
54
+ * non-zero allowance to another. Returns the final approval hash, or null
55
+ * when the allowance already covered it. Throws if an approval reverts.
56
+ */
57
+ ensureAllowance(args: { token: Address; spender: Address; amount: bigint }): Promise<Hash | null>;
58
+ }
59
+
60
+ export interface EvmClient extends ChainClient<"evm"> {
61
+ readonly address: Address;
62
+ readonly chainId: number;
63
+ readonly chain: Chain;
64
+ /** The wallet side: anything viem's wallet actions can do. */
65
+ readonly walletClient: EvmWalletClient;
66
+ /** Reads, simulation and receipts. */
67
+ readonly publicClient: PublicClient;
68
+ /** personal_sign; returns the 0x signature. */
69
+ signMessage(message: string): Promise<Hex>;
70
+ sendTransaction(parameters: EvmSendTransactionParameters): Promise<Hash>;
71
+ writeContract<
72
+ const abi extends Abi | readonly unknown[],
73
+ functionName extends WritableFunctionName<abi>,
74
+ args extends ContractFunctionArgs<abi, "nonpayable" | "payable", functionName>,
75
+ >(
76
+ parameters: EvmWriteContractParameters<abi, functionName, args>,
77
+ ): Promise<Hash>;
78
+ waitForTransactionReceipt(hash: Hash): Promise<TransactionReceipt>;
79
+ readonly erc20: Erc20Actions;
80
+ }
81
+
82
+ export type EvmClientConfig = (
83
+ | {
84
+ /** A viem wallet client, e.g. wagmi's `getWalletClient(config)`. */
85
+ walletClient: EvmWalletClient;
86
+ }
87
+ | {
88
+ /** An EIP-1193 provider: injected, MetaMask Connect, or the native WebView bridge. */
89
+ provider: EIP1193Provider;
90
+ account: Address;
91
+ chain: Chain;
92
+ }
93
+ ) & {
94
+ /** Reads go here. Defaults to an http client on `rpcUrl`, else the chain's default RPC. */
95
+ publicClient?: PublicClient;
96
+ rpcUrl?: string;
97
+ };
98
+
99
+ /**
100
+ * transfer and approve with no outputs. USDT and other pre-standard tokens
101
+ * return nothing, and simulating them against erc20Abi's `returns (bool)`
102
+ * fails to decode the empty result, so the helpers simulate against this.
103
+ */
104
+ const erc20WriteAbi = [
105
+ {
106
+ type: "function",
107
+ name: "transfer",
108
+ stateMutability: "nonpayable",
109
+ inputs: [
110
+ { name: "to", type: "address" },
111
+ { name: "amount", type: "uint256" },
112
+ ],
113
+ outputs: [],
114
+ },
115
+ {
116
+ type: "function",
117
+ name: "approve",
118
+ stateMutability: "nonpayable",
119
+ inputs: [
120
+ { name: "spender", type: "address" },
121
+ { name: "amount", type: "uint256" },
122
+ ],
123
+ outputs: [],
124
+ },
125
+ ] as const;
126
+
127
+ const capabilities: readonly ClientCapability[] = [
128
+ "signMessage",
129
+ "sendTransaction",
130
+ "writeContract",
131
+ ];
132
+
133
+ /** Bind a viem WalletClient and PublicClient into the mpo EVM client. */
134
+ export function evmClient(config: EvmClientConfig): EvmClient {
135
+ const walletClient: EvmWalletClient =
136
+ "walletClient" in config
137
+ ? config.walletClient
138
+ : createWalletClient({
139
+ account: config.account,
140
+ chain: config.chain,
141
+ transport: custom(config.provider),
142
+ });
143
+ const chain = walletClient.chain;
144
+ if (!chain) throw new Error("evmClient: the wallet client has no chain");
145
+ const publicClient =
146
+ config.publicClient ??
147
+ (createPublicClient({ chain, transport: http(config.rpcUrl) }) as PublicClient);
148
+ const account = walletClient.account;
149
+
150
+ const writeContract = (parameters: EvmWriteContractParameters) =>
151
+ walletClient.writeContract({ account, chain, ...parameters } as EvmWriteContractParameters);
152
+
153
+ const simulateAndWrite = async (parameters: {
154
+ address: Address;
155
+ functionName: "transfer" | "approve";
156
+ args: readonly [Address, bigint];
157
+ }): Promise<Hash> => {
158
+ const { request } = await publicClient.simulateContract({
159
+ account,
160
+ address: parameters.address,
161
+ abi: erc20WriteAbi,
162
+ functionName: parameters.functionName,
163
+ args: parameters.args,
164
+ });
165
+ return walletClient.writeContract({ ...request, account, chain } as EvmWriteContractParameters);
166
+ };
167
+
168
+ const approveAndWait = async (token: Address, spender: Address, amount: bigint) => {
169
+ const hash = await erc20.approve({ token, spender, amount });
170
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
171
+ if (receipt.status !== "success") throw new Error(`approve ${hash} reverted`);
172
+ return hash;
173
+ };
174
+
175
+ const erc20: Erc20Actions = {
176
+ balanceOf: (token, owner = account.address) =>
177
+ publicClient.readContract({
178
+ address: token,
179
+ abi: erc20Abi,
180
+ functionName: "balanceOf",
181
+ args: [owner],
182
+ }),
183
+ allowance: (token, spender, owner = account.address) =>
184
+ publicClient.readContract({
185
+ address: token,
186
+ abi: erc20Abi,
187
+ functionName: "allowance",
188
+ args: [owner, spender],
189
+ }),
190
+ decimals: (token) =>
191
+ publicClient.readContract({ address: token, abi: erc20Abi, functionName: "decimals" }),
192
+ transfer: ({ token, to, amount }) =>
193
+ simulateAndWrite({ address: token, functionName: "transfer", args: [to, amount] }),
194
+ approve: ({ token, spender, amount }) =>
195
+ simulateAndWrite({ address: token, functionName: "approve", args: [spender, amount] }),
196
+ async ensureAllowance({ token, spender, amount }) {
197
+ const current = await erc20.allowance(token, spender);
198
+ if (current >= amount) return null;
199
+ if (current > 0n) await approveAndWait(token, spender, 0n);
200
+ return approveAndWait(token, spender, amount);
201
+ },
202
+ };
203
+
204
+ return {
205
+ family: "evm",
206
+ address: account.address,
207
+ chainId: chain.id,
208
+ chain,
209
+ capabilities,
210
+ walletClient,
211
+ publicClient,
212
+ signMessage: (message) => walletClient.signMessage({ account, message }),
213
+ sendTransaction: (parameters) =>
214
+ walletClient.sendTransaction({
215
+ account,
216
+ chain,
217
+ ...parameters,
218
+ } as EvmSendTransactionParameters),
219
+ writeContract: writeContract as EvmClient["writeContract"],
220
+ waitForTransactionReceipt: (hash) => publicClient.waitForTransactionReceipt({ hash }),
221
+ erc20,
222
+ };
223
+ }
@@ -0,0 +1,169 @@
1
+ // @vitest-environment happy-dom
2
+ import { act, renderHook } from "@testing-library/react";
3
+ import { describe, expect, it } from "vitest";
4
+ import { gpgSignatureCovers } from "@multiplatform.one/gpg/signer";
5
+ import {
6
+ assertGpgSignature,
7
+ createGpgSigner,
8
+ gpgSignCommand,
9
+ useGpgSigner,
10
+ type GpgSignRequest,
11
+ } from "./gpg";
12
+
13
+ // Real `gpg --detach-sign --armor` output from a throwaway key (GnuPG 2.2.40):
14
+ // ed25519 over "sign me" with SHA-256 and SHA-512, ed25519 --textmode over
15
+ // "line one\nline two", RSA-2048 over "sign me".
16
+ const signature = [
17
+ "-----BEGIN PGP SIGNATURE-----",
18
+ "",
19
+ "iHUEABYIAB0WIQSTkGTQEc3oIZuZ2HdhXGslcfiVLQUCarhXCwAKCRBhXGslcfiV",
20
+ "LQ0LAQCXGCKwc0BQsbKZLC3dGO8G+JcugVvc8pXoLwVEhzHg5gEA9ymdo09WgZpg",
21
+ "ucbH3UOfZUAeoo8/udpgkA8x6FJQPQQ=",
22
+ "=ORhi",
23
+ "-----END PGP SIGNATURE-----",
24
+ ].join("\n");
25
+ const signatureSha512 = [
26
+ "-----BEGIN PGP SIGNATURE-----",
27
+ "",
28
+ "iHUEABYKAB0WIQSTkGTQEc3oIZuZ2HdhXGslcfiVLQUCarhXCwAKCRBhXGslcfiV",
29
+ "LRKTAQD9KN/ePxTrwxYDVP1Vtv+xWw/ADZTMOBIfM5mG662+UwEAjqKNIAR77Qtd",
30
+ "Yz5lxQdmvudeeATH/0mGrq7h+JHSxwA=",
31
+ "=lq5g",
32
+ "-----END PGP SIGNATURE-----",
33
+ ].join("\n");
34
+ const textSignature = [
35
+ "-----BEGIN PGP SIGNATURE-----",
36
+ "",
37
+ "iHUEARYIAB0WIQSTkGTQEc3oIZuZ2HdhXGslcfiVLQUCarhXCwAKCRBhXGslcfiV",
38
+ "LV9cAPwML2fE5cLHDhKjgnHpGjyBJqluiVRkkKwdA8UT64knWgEA9yLAavBGXwOR",
39
+ "VJ6lQNJ4dEUzc4PcrhSY/XoXchB2/wI=",
40
+ "=3t6i",
41
+ "-----END PGP SIGNATURE-----",
42
+ ].join("\n");
43
+ const rsaSignature = [
44
+ "-----BEGIN PGP SIGNATURE-----",
45
+ "",
46
+ "iQFIBAABCgAyFiEE5BSx1a7VdcvuJBKxk/hBDWJyGKcFAmq4VwsUHHJzYUBleGFt",
47
+ "cGxlLmludmFsaWQACgkQk/hBDWJyGKfxuAf/RpMSEstfkVr+LSVbqdqvUwb+eFvS",
48
+ "g257dJ/p75cyySijNHMJiKz/Eg++CxGslryotHAse8cDhhaVNdvhsyWdXgeZAlMw",
49
+ "Yb+PN/Hyr185HXMzVGEm5mbyHOZoh1e68K+BZRRW7g8mu32GxuMPlCfSEJ8Ca+cH",
50
+ "JRRm3gdIXejJzYL8+ECHB1ZA/5rrjMRoluCpzIaO/JuOrUka488bEpZa0SM5R/E0",
51
+ "oxgNj/5h9WV99mIBTKP6uPhsduwLOmETKSzJ53wMqND7DUyVhehMcFh0jR39QQWj",
52
+ "/pFp7YB8/krLA03SRbLuuwSJ0tX9Pjb8pXxTUUnnht9+WuxQSIMYFCvtEg==",
53
+ "=TLuY",
54
+ "-----END PGP SIGNATURE-----",
55
+ ].join("\n");
56
+ const publicKey = [
57
+ "-----BEGIN PGP PUBLIC KEY BLOCK-----",
58
+ "",
59
+ "mDMEarhXCxYJKwYBBAHaRw8BAQdAMFGusqeWs1dEHGDmMnoDwOBl5noKtQUIGORr",
60
+ "ONGF5GC0JW1wbyBmaXh0dXJlIDxmaXh0dXJlQGV4YW1wbGUuaW52YWxpZD6IkAQT",
61
+ "FggAOBYhBJOQZNARzeghm5nYd2FcayVx+JUtBQJquFcLAhsDBQsJCAcCBhUKCQgL",
62
+ "AgQWAgMBAh4BAheAAAoJEGFcayVx+JUt4OoA/1D+/ZAGt3HeS8d7oLydIaRK2s8h",
63
+ "Ew8OhTBk7hzPJKHAAQD7T5AOlLH3r+MzFkqawLdlWy1FnUiVrwyqIrLDvmniCA==",
64
+ "=yro2",
65
+ "-----END PGP PUBLIC KEY BLOCK-----",
66
+ ].join("\n");
67
+ const blob = `${signature}\n${publicKey}`;
68
+
69
+ const pendingOf = (signer: ReturnType<typeof createGpgSigner>) => signer.pending as GpgSignRequest;
70
+
71
+ describe("GPG signer", () => {
72
+ it("parks a request with the terminal command and resolves with the pasted blob", async () => {
73
+ const signer = createGpgSigner();
74
+ expect(signer.family).toBe("gpg");
75
+ expect(signer.address).toBeNull();
76
+ const signed = signer.signMessage("sign me");
77
+ expect(signer.pending).toEqual({ message: "sign me", command: gpgSignCommand("sign me") });
78
+ signer.submit(`\n ${blob}\n`, pendingOf(signer));
79
+ await expect(signed).resolves.toBe(blob);
80
+ expect(signer.pending).toBeNull();
81
+ });
82
+
83
+ it("keeps the request pending when the paste is missing a block", async () => {
84
+ const signer = createGpgSigner();
85
+ const signed = signer.signMessage("sign me");
86
+ expect(() => signer.submit(signature, pendingOf(signer))).toThrow(/PUBLIC KEY/);
87
+ expect(signer.pending?.message).toBe("sign me");
88
+ signer.submit(blob, pendingOf(signer));
89
+ await expect(signed).resolves.toBe(blob);
90
+ });
91
+
92
+ it("refuses a paste for a superseded request, even one for the same message", async () => {
93
+ const signer = createGpgSigner();
94
+ const first = signer.signMessage("sign me");
95
+ const stale = pendingOf(signer);
96
+ const second = signer.signMessage("sign me");
97
+ await expect(first).rejects.toThrow(/superseded/);
98
+ expect(() => signer.submit(blob, stale)).toThrow(/superseded/);
99
+ expect(signer.pending).not.toBe(stale);
100
+ signer.submit(blob, pendingOf(signer));
101
+ await expect(second).resolves.toBe(blob);
102
+ });
103
+
104
+ it("refuses a signature over a different message and keeps the request", async () => {
105
+ const signer = createGpgSigner();
106
+ const signed = signer.signMessage("sign me, nonce 2");
107
+ const request = pendingOf(signer);
108
+ expect(() => signer.submit(blob, request)).toThrow(/different message/);
109
+ expect(signer.pending).toBe(request);
110
+ signer.cancel();
111
+ await expect(signed).rejects.toThrow(/cancelled/);
112
+ });
113
+
114
+ it("rejects on cancel and when a newer request replaces it", async () => {
115
+ const signer = createGpgSigner();
116
+ const first = signer.signMessage("one");
117
+ const second = signer.signMessage("two");
118
+ await expect(first).rejects.toThrow(/superseded/);
119
+ expect(signer.pending?.message).toBe("two");
120
+ const request = pendingOf(signer);
121
+ signer.cancel();
122
+ await expect(second).rejects.toThrow(/cancelled/);
123
+ expect(() => signer.submit(blob, request)).toThrow(/No GPG signature was requested/);
124
+ });
125
+
126
+ it("escapes single quotes so a message cannot break out of the command", () => {
127
+ expect(gpgSignCommand("it's")).toBe(
128
+ `{ printf %s 'it'\\''s' | gpg --detach-sign --armor; gpg --armor --export; }`,
129
+ );
130
+ });
131
+
132
+ it("tells which message a real gpg signature covers", () => {
133
+ expect(gpgSignatureCovers(blob, "sign me")).toBe(true);
134
+ expect(gpgSignatureCovers(blob, "sign me!")).toBe(false);
135
+ expect(gpgSignatureCovers(signatureSha512, "sign me")).toBe(true);
136
+ expect(gpgSignatureCovers(rsaSignature, "sign me")).toBe(true);
137
+ expect(gpgSignatureCovers(rsaSignature, "sign you")).toBe(false);
138
+ // --textmode hashes CRLF line endings, so both spellings of the message match.
139
+ expect(gpgSignatureCovers(textSignature, "line one\nline two")).toBe(true);
140
+ expect(gpgSignatureCovers(textSignature, "line one\r\nline two")).toBe(true);
141
+ expect(gpgSignatureCovers(textSignature, "line one\nline 2")).toBe(false);
142
+ expect(() => gpgSignatureCovers(publicKey, "sign me")).toThrow(/No PGP SIGNATURE/);
143
+ });
144
+
145
+ it("trims a complete paste and rejects an incomplete one", () => {
146
+ expect(assertGpgSignature(` ${blob} `)).toBe(blob);
147
+ expect(() => assertGpgSignature("nope")).toThrow(/FULL output/);
148
+ });
149
+
150
+ it("re-renders a subscribed component as requests come and go", async () => {
151
+ const signer = createGpgSigner();
152
+ const { result } = renderHook(() => useGpgSigner(signer).pending);
153
+ expect(result.current).toBeNull();
154
+ let signed!: Promise<string>;
155
+ act(() => {
156
+ signed = signer.signMessage("sign me");
157
+ });
158
+ expect(result.current?.message).toBe("sign me");
159
+ act(() => signer.submit(blob, pendingOf(signer)));
160
+ expect(result.current).toBeNull();
161
+ await expect(signed).resolves.toBe(blob);
162
+ });
163
+
164
+ it("shares one app-wide signer when none is passed", () => {
165
+ const a = renderHook(() => useGpgSigner());
166
+ const b = renderHook(() => useGpgSigner());
167
+ expect(a.result.current).toBe(b.result.current);
168
+ });
169
+ });
@@ -0,0 +1,8 @@
1
+ export {
2
+ assertGpgSignature,
3
+ createGpgSigner,
4
+ gpgSignCommand,
5
+ useGpgSigner,
6
+ type GpgSigner,
7
+ type GpgSignRequest,
8
+ } from "@multiplatform.one/gpg/signer";