@multiplatform.one/web3 8.2.2 → 8.4.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 (211) hide show
  1. package/README.md +33 -2
  2. package/dist/cjs/clients/tron.cjs +176 -0
  3. package/dist/cjs/clients/tron.native.js +318 -0
  4. package/dist/cjs/clients/tron.native.js.map +1 -0
  5. package/dist/cjs/clients/useTronClient.cjs +50 -0
  6. package/dist/cjs/clients/useTronClient.native.js +63 -0
  7. package/dist/cjs/clients/useTronClient.native.js.map +1 -0
  8. package/dist/cjs/connectkit/adapters/TronAdapter.cjs +139 -0
  9. package/dist/cjs/connectkit/adapters/TronAdapter.native.js +217 -0
  10. package/dist/cjs/connectkit/adapters/TronAdapter.native.js.map +1 -0
  11. package/dist/cjs/connectkit/connectors/createWalletMessage.cjs +3 -3
  12. package/dist/cjs/connectkit/connectors/createWalletMessage.native.js +3 -3
  13. package/dist/cjs/connectkit/connectors/createWalletMessage.native.js.map +1 -1
  14. package/dist/cjs/connectkit/connectors/ensureWalletConnectors.cjs +2 -1
  15. package/dist/cjs/connectkit/connectors/ensureWalletConnectors.native.js +18 -35
  16. package/dist/cjs/connectkit/connectors/ensureWalletConnectors.native.js.map +1 -1
  17. package/dist/cjs/connectkit/connectors/syntheticChains.cjs +10 -4
  18. package/dist/cjs/connectkit/connectors/syntheticChains.native.js +10 -4
  19. package/dist/cjs/connectkit/connectors/syntheticChains.native.js.map +1 -1
  20. package/dist/cjs/connectkit/defaultConfig.cjs +2 -1
  21. package/dist/cjs/connectkit/defaultConfig.native.js +2 -1
  22. package/dist/cjs/connectkit/defaultConfig.native.js.map +1 -1
  23. package/dist/cjs/connectkit/siwe/SIWEContext.native.js.map +1 -1
  24. package/dist/cjs/connectkit/siwe/SIWEProvider.cjs +19 -16
  25. package/dist/cjs/connectkit/siwe/SIWEProvider.native.js +26 -16
  26. package/dist/cjs/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  27. package/dist/cjs/connectkit/wallets/walletConfigs.cjs +12 -0
  28. package/dist/cjs/connectkit/wallets/walletConfigs.native.js +12 -0
  29. package/dist/cjs/connectkit/wallets/walletConfigs.native.js.map +1 -1
  30. package/dist/cjs/families/host.native.js.map +1 -1
  31. package/dist/cjs/families/tron.cjs +92 -0
  32. package/dist/cjs/families/tron.native.js +120 -0
  33. package/dist/cjs/families/tron.native.js.map +1 -0
  34. package/dist/cjs/keycloak/KeycloakWalletLogin.cjs +34 -3
  35. package/dist/cjs/keycloak/useWalletLogin.cjs +3 -2
  36. package/dist/cjs/providers/WalletProvider.cjs +1 -1
  37. package/dist/cjs/tron.cjs +46 -0
  38. package/dist/cjs/tron.native.js +49 -0
  39. package/dist/cjs/tron.native.js.map +1 -0
  40. package/dist/cjs/wagmi/host.cjs +9 -4
  41. package/dist/cjs/wagmi/host.native.js +6 -3
  42. package/dist/cjs/wagmi/host.native.js.map +1 -1
  43. package/dist/esm/clients/tron.mjs +133 -0
  44. package/dist/esm/clients/tron.mjs.map +1 -0
  45. package/dist/esm/clients/tron.native.js +272 -0
  46. package/dist/esm/clients/tron.native.js.map +1 -0
  47. package/dist/esm/clients/useTronClient.mjs +25 -0
  48. package/dist/esm/clients/useTronClient.mjs.map +1 -0
  49. package/dist/esm/clients/useTronClient.native.js +35 -0
  50. package/dist/esm/clients/useTronClient.native.js.map +1 -0
  51. package/dist/esm/connectkit/adapters/TronAdapter.mjs +111 -0
  52. package/dist/esm/connectkit/adapters/TronAdapter.mjs.map +1 -0
  53. package/dist/esm/connectkit/adapters/TronAdapter.native.js +186 -0
  54. package/dist/esm/connectkit/adapters/TronAdapter.native.js.map +1 -0
  55. package/dist/esm/connectkit/connectors/createWalletMessage.mjs +3 -3
  56. package/dist/esm/connectkit/connectors/createWalletMessage.mjs.map +1 -1
  57. package/dist/esm/connectkit/connectors/createWalletMessage.native.js +3 -3
  58. package/dist/esm/connectkit/connectors/createWalletMessage.native.js.map +1 -1
  59. package/dist/esm/connectkit/connectors/ensureWalletConnectors.mjs +2 -1
  60. package/dist/esm/connectkit/connectors/ensureWalletConnectors.mjs.map +1 -1
  61. package/dist/esm/connectkit/connectors/ensureWalletConnectors.native.js +18 -35
  62. package/dist/esm/connectkit/connectors/ensureWalletConnectors.native.js.map +1 -1
  63. package/dist/esm/connectkit/connectors/syntheticChains.mjs +8 -4
  64. package/dist/esm/connectkit/connectors/syntheticChains.mjs.map +1 -1
  65. package/dist/esm/connectkit/connectors/syntheticChains.native.js +8 -4
  66. package/dist/esm/connectkit/connectors/syntheticChains.native.js.map +1 -1
  67. package/dist/esm/connectkit/defaultConfig.mjs +2 -1
  68. package/dist/esm/connectkit/defaultConfig.mjs.map +1 -1
  69. package/dist/esm/connectkit/defaultConfig.native.js +2 -1
  70. package/dist/esm/connectkit/defaultConfig.native.js.map +1 -1
  71. package/dist/esm/connectkit/siwe/SIWEContext.mjs.map +1 -1
  72. package/dist/esm/connectkit/siwe/SIWEContext.native.js.map +1 -1
  73. package/dist/esm/connectkit/siwe/SIWEProvider.mjs +19 -16
  74. package/dist/esm/connectkit/siwe/SIWEProvider.mjs.map +1 -1
  75. package/dist/esm/connectkit/siwe/SIWEProvider.native.js +26 -16
  76. package/dist/esm/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  77. package/dist/esm/connectkit/wallets/walletConfigs.mjs +12 -0
  78. package/dist/esm/connectkit/wallets/walletConfigs.mjs.map +1 -1
  79. package/dist/esm/connectkit/wallets/walletConfigs.native.js +12 -0
  80. package/dist/esm/connectkit/wallets/walletConfigs.native.js.map +1 -1
  81. package/dist/esm/families/host.mjs.map +1 -1
  82. package/dist/esm/families/host.native.js.map +1 -1
  83. package/dist/esm/families/tron.mjs +65 -0
  84. package/dist/esm/families/tron.mjs.map +1 -0
  85. package/dist/esm/families/tron.native.js +90 -0
  86. package/dist/esm/families/tron.native.js.map +1 -0
  87. package/dist/esm/keycloak/KeycloakWalletLogin.mjs +33 -3
  88. package/dist/esm/keycloak/KeycloakWalletLogin.mjs.map +1 -1
  89. package/dist/esm/keycloak/useWalletLogin.mjs +3 -2
  90. package/dist/esm/keycloak/useWalletLogin.mjs.map +1 -1
  91. package/dist/esm/providers/WalletProvider.mjs +1 -1
  92. package/dist/esm/providers/WalletProvider.mjs.map +1 -1
  93. package/dist/esm/tron.mjs +6 -0
  94. package/dist/esm/tron.mjs.map +1 -0
  95. package/dist/esm/tron.native.js +6 -0
  96. package/dist/esm/tron.native.js.map +1 -0
  97. package/dist/esm/wagmi/host.mjs +9 -4
  98. package/dist/esm/wagmi/host.mjs.map +1 -1
  99. package/dist/esm/wagmi/host.native.js +6 -3
  100. package/dist/esm/wagmi/host.native.js.map +1 -1
  101. package/dist/jsx/clients/tron.mjs +133 -0
  102. package/dist/jsx/clients/tron.mjs.map +1 -0
  103. package/dist/jsx/clients/tron.native.js +318 -0
  104. package/dist/jsx/clients/tron.native.js.map +1 -0
  105. package/dist/jsx/clients/useTronClient.mjs +25 -0
  106. package/dist/jsx/clients/useTronClient.mjs.map +1 -0
  107. package/dist/jsx/clients/useTronClient.native.js +63 -0
  108. package/dist/jsx/clients/useTronClient.native.js.map +1 -0
  109. package/dist/jsx/connectkit/adapters/TronAdapter.mjs +111 -0
  110. package/dist/jsx/connectkit/adapters/TronAdapter.mjs.map +1 -0
  111. package/dist/jsx/connectkit/adapters/TronAdapter.native.js +217 -0
  112. package/dist/jsx/connectkit/adapters/TronAdapter.native.js.map +1 -0
  113. package/dist/jsx/connectkit/connectors/createWalletMessage.mjs +3 -3
  114. package/dist/jsx/connectkit/connectors/createWalletMessage.mjs.map +1 -1
  115. package/dist/jsx/connectkit/connectors/createWalletMessage.native.js +3 -3
  116. package/dist/jsx/connectkit/connectors/createWalletMessage.native.js.map +1 -1
  117. package/dist/jsx/connectkit/connectors/ensureWalletConnectors.mjs +2 -1
  118. package/dist/jsx/connectkit/connectors/ensureWalletConnectors.mjs.map +1 -1
  119. package/dist/jsx/connectkit/connectors/ensureWalletConnectors.native.js +18 -35
  120. package/dist/jsx/connectkit/connectors/ensureWalletConnectors.native.js.map +1 -1
  121. package/dist/jsx/connectkit/connectors/syntheticChains.mjs +8 -4
  122. package/dist/jsx/connectkit/connectors/syntheticChains.mjs.map +1 -1
  123. package/dist/jsx/connectkit/connectors/syntheticChains.native.js +10 -4
  124. package/dist/jsx/connectkit/connectors/syntheticChains.native.js.map +1 -1
  125. package/dist/jsx/connectkit/defaultConfig.mjs +2 -1
  126. package/dist/jsx/connectkit/defaultConfig.mjs.map +1 -1
  127. package/dist/jsx/connectkit/defaultConfig.native.js +2 -1
  128. package/dist/jsx/connectkit/defaultConfig.native.js.map +1 -1
  129. package/dist/jsx/connectkit/siwe/SIWEContext.mjs.map +1 -1
  130. package/dist/jsx/connectkit/siwe/SIWEContext.native.js.map +1 -1
  131. package/dist/jsx/connectkit/siwe/SIWEProvider.mjs +19 -16
  132. package/dist/jsx/connectkit/siwe/SIWEProvider.mjs.map +1 -1
  133. package/dist/jsx/connectkit/siwe/SIWEProvider.native.js +26 -16
  134. package/dist/jsx/connectkit/siwe/SIWEProvider.native.js.map +1 -1
  135. package/dist/jsx/connectkit/wallets/walletConfigs.mjs +12 -0
  136. package/dist/jsx/connectkit/wallets/walletConfigs.mjs.map +1 -1
  137. package/dist/jsx/connectkit/wallets/walletConfigs.native.js +12 -0
  138. package/dist/jsx/connectkit/wallets/walletConfigs.native.js.map +1 -1
  139. package/dist/jsx/families/host.mjs.map +1 -1
  140. package/dist/jsx/families/host.native.js.map +1 -1
  141. package/dist/jsx/families/tron.mjs +65 -0
  142. package/dist/jsx/families/tron.mjs.map +1 -0
  143. package/dist/jsx/families/tron.native.js +120 -0
  144. package/dist/jsx/families/tron.native.js.map +1 -0
  145. package/dist/jsx/keycloak/KeycloakWalletLogin.mjs +33 -3
  146. package/dist/jsx/keycloak/KeycloakWalletLogin.mjs.map +1 -1
  147. package/dist/jsx/keycloak/useWalletLogin.mjs +3 -2
  148. package/dist/jsx/keycloak/useWalletLogin.mjs.map +1 -1
  149. package/dist/jsx/providers/WalletProvider.mjs +1 -1
  150. package/dist/jsx/providers/WalletProvider.mjs.map +1 -1
  151. package/dist/jsx/tron.mjs +6 -0
  152. package/dist/jsx/tron.mjs.map +1 -0
  153. package/dist/jsx/tron.native.js +49 -0
  154. package/dist/jsx/tron.native.js.map +1 -0
  155. package/dist/jsx/wagmi/host.mjs +9 -4
  156. package/dist/jsx/wagmi/host.mjs.map +1 -1
  157. package/dist/jsx/wagmi/host.native.js +6 -3
  158. package/dist/jsx/wagmi/host.native.js.map +1 -1
  159. package/dist/keycloak/login.iife.js +399 -399
  160. package/package.json +13 -7
  161. package/src/clients/tron.spec.ts +118 -0
  162. package/src/clients/tron.ts +186 -0
  163. package/src/clients/useTronClient.ts +26 -0
  164. package/src/connectkit/adapters/TronAdapter.spec.ts +155 -0
  165. package/src/connectkit/adapters/TronAdapter.ts +168 -0
  166. package/src/connectkit/adapters/discover.ts +1 -1
  167. package/src/connectkit/connectors/createWalletMessage.ts +3 -3
  168. package/src/connectkit/connectors/ensureWalletConnectors.ts +2 -1
  169. package/src/connectkit/connectors/syntheticChains.ts +8 -2
  170. package/src/connectkit/defaultConfig.ts +5 -2
  171. package/src/connectkit/siwe/SIWEContext.tsx +2 -0
  172. package/src/connectkit/siwe/SIWEProvider.tsx +23 -10
  173. package/src/connectkit/wallets/walletConfigs.tsx +8 -0
  174. package/src/families/host.ts +9 -2
  175. package/src/families/tron.spec.ts +118 -0
  176. package/src/families/tron.ts +63 -0
  177. package/src/keycloak/KeycloakWalletLogin.spec.tsx +110 -0
  178. package/src/keycloak/KeycloakWalletLogin.stories.tsx +93 -0
  179. package/src/keycloak/KeycloakWalletLogin.tsx +39 -2
  180. package/src/keycloak/useWalletLogin.ts +5 -1
  181. package/src/providers/WalletProvider.tsx +1 -1
  182. package/src/tron.ts +26 -0
  183. package/src/wagmi/host.tsx +6 -2
  184. package/types/clients/tron.d.ts +65 -0
  185. package/types/clients/tron.d.ts.map +1 -0
  186. package/types/clients/useTronClient.d.ts +8 -0
  187. package/types/clients/useTronClient.d.ts.map +1 -0
  188. package/types/connectkit/adapters/TronAdapter.d.ts +35 -0
  189. package/types/connectkit/adapters/TronAdapter.d.ts.map +1 -0
  190. package/types/connectkit/adapters/discover.d.ts +1 -1
  191. package/types/connectkit/adapters/discover.d.ts.map +1 -1
  192. package/types/connectkit/connectors/ensureWalletConnectors.d.ts.map +1 -1
  193. package/types/connectkit/connectors/syntheticChains.d.ts +4 -0
  194. package/types/connectkit/connectors/syntheticChains.d.ts.map +1 -1
  195. package/types/connectkit/defaultConfig.d.ts.map +1 -1
  196. package/types/connectkit/siwe/SIWEContext.d.ts +2 -0
  197. package/types/connectkit/siwe/SIWEContext.d.ts.map +1 -1
  198. package/types/connectkit/siwe/SIWEProvider.d.ts +0 -6
  199. package/types/connectkit/siwe/SIWEProvider.d.ts.map +1 -1
  200. package/types/connectkit/wallets/walletConfigs.d.ts.map +1 -1
  201. package/types/families/host.d.ts +9 -2
  202. package/types/families/host.d.ts.map +1 -1
  203. package/types/families/tron.d.ts +15 -0
  204. package/types/families/tron.d.ts.map +1 -0
  205. package/types/keycloak/KeycloakWalletLogin.d.ts +6 -1
  206. package/types/keycloak/KeycloakWalletLogin.d.ts.map +1 -1
  207. package/types/keycloak/useWalletLogin.d.ts +2 -0
  208. package/types/keycloak/useWalletLogin.d.ts.map +1 -1
  209. package/types/tron.d.ts +5 -0
  210. package/types/tron.d.ts.map +1 -0
  211. package/types/wagmi/host.d.ts.map +1 -1
@@ -0,0 +1,168 @@
1
+ import type { TronNetwork } from "../../clients/tron";
2
+ import type { WalletEntry } from "./discover";
3
+ import type { SignInMessageOptions, WalletAdapter, WalletAddress } from "./types";
4
+
5
+ interface TronWebLike {
6
+ ready?: boolean;
7
+ defaultAddress?: { base58?: string | false };
8
+ fullNode?: { host?: string };
9
+ trx: { signMessageV2(message: string): Promise<string> };
10
+ }
11
+
12
+ interface TronRequester {
13
+ request(args: { method: string; params?: unknown }): Promise<unknown>;
14
+ }
15
+
16
+ interface Tip1193Provider extends TronRequester {
17
+ tronWeb?: TronWebLike | false;
18
+ on?(event: "accountsChanged", listener: (accounts: string[]) => void): void;
19
+ removeListener?(event: "accountsChanged", listener: (accounts: string[]) => void): void;
20
+ }
21
+
22
+ interface TronLinkLike extends TronRequester {
23
+ ready?: boolean;
24
+ tronWeb?: TronWebLike | false;
25
+ }
26
+
27
+ interface TronWindow {
28
+ tron?: Tip1193Provider;
29
+ tronLink?: TronLinkLike;
30
+ tronWeb?: TronWebLike | false;
31
+ addEventListener?: Window["addEventListener"];
32
+ removeEventListener?: Window["removeEventListener"];
33
+ }
34
+
35
+ const page = (): TronWindow | undefined =>
36
+ typeof window === "undefined" ? undefined : (window as unknown as TronWindow);
37
+
38
+ const tronWebOf = (w: TronWindow): TronWebLike | undefined =>
39
+ w.tron?.tronWeb || w.tronLink?.tronWeb || w.tronWeb || undefined;
40
+
41
+ const accountOf = (w: TronWindow): string | null => tronWebOf(w)?.defaultAddress?.base58 || null;
42
+
43
+ /** The network TronLink's full node is on, from its host. Mainnet for an unknown node. */
44
+ export function tronNetworkOf(host: string | undefined): TronNetwork {
45
+ if (host?.includes("nile")) return "nile";
46
+ if (host?.includes("shasta")) return "shasta";
47
+ return "mainnet";
48
+ }
49
+
50
+ /** TronLink is on this page: the TIP-1193 `window.tron`, or the older `window.tronLink`. */
51
+ export function hasTronWallet(): boolean {
52
+ const w = page();
53
+ return Boolean(w?.tron || w?.tronLink);
54
+ }
55
+
56
+ /**
57
+ * TronLink over its injected provider: `tron_requestAccounts` (or TIP-1193's
58
+ * `eth_requestAccounts`) to connect, `tronWeb.defaultAddress.base58` for the
59
+ * account, `tronWeb.trx.signMessageV2` to sign. No tronweb package.
60
+ */
61
+ export class TronAdapter implements WalletAdapter {
62
+ readonly chain = "tron";
63
+ address: WalletAddress | null = null;
64
+ isConnected = false;
65
+
66
+ get network(): TronNetwork {
67
+ const w = page();
68
+ return tronNetworkOf(w ? tronWebOf(w)?.fullNode?.host : undefined);
69
+ }
70
+
71
+ get networkId(): string {
72
+ return `tron:${this.network}`;
73
+ }
74
+
75
+ async connect(): Promise<void> {
76
+ const w = page();
77
+ if (!w?.tron && !w?.tronLink) {
78
+ throw new Error("No Tron wallet found. Install TronLink.");
79
+ }
80
+ if (w.tron) {
81
+ await w.tron.request({ method: "eth_requestAccounts" });
82
+ } else if (w.tronLink) {
83
+ const answer = (await w.tronLink.request({ method: "tron_requestAccounts" })) as
84
+ | { code?: number; message?: string }
85
+ | ""
86
+ | undefined;
87
+ if (!answer) throw new Error("TronLink is locked. Unlock it and try again.");
88
+ if (answer.code !== undefined && answer.code !== 200) {
89
+ throw new Error(answer.message || "TronLink refused the connection");
90
+ }
91
+ }
92
+ const address = accountOf(w);
93
+ if (!address) throw new Error("TronLink returned no account");
94
+ this.address = address;
95
+ this.isConnected = true;
96
+ }
97
+
98
+ /**
99
+ * Takes the account TronLink already shares with this page, without a
100
+ * prompt. False when it shares none; throws while TronLink has not
101
+ * injected itself yet.
102
+ */
103
+ async restore(): Promise<boolean> {
104
+ const w = page();
105
+ if (!w?.tron && !w?.tronLink && !w?.tronWeb) throw new Error("No Tron wallet found yet.");
106
+ const address = accountOf(w);
107
+ this.address = address;
108
+ this.isConnected = address !== null;
109
+ return address !== null;
110
+ }
111
+
112
+ /** TronLink's account switches and disconnects; the account is read back from tronWeb on each. */
113
+ subscribe(listener: () => void): () => void {
114
+ const w = page();
115
+ if (!w) return () => {};
116
+ const update = () => {
117
+ const address = accountOf(w);
118
+ this.address = address;
119
+ this.isConnected = address !== null;
120
+ listener();
121
+ };
122
+ const provider = w.tron;
123
+ if (provider?.on) {
124
+ const onAccounts = () => update();
125
+ provider.on("accountsChanged", onAccounts);
126
+ return () => provider.removeListener?.("accountsChanged", onAccounts);
127
+ }
128
+ if (typeof w.addEventListener !== "function") return () => {};
129
+ const onMessage = (event: MessageEvent) => {
130
+ const action = (event.data as { message?: { action?: string } } | null)?.message?.action;
131
+ if (
132
+ action === "accountsChanged" ||
133
+ action === "setAccount" ||
134
+ action === "disconnect" ||
135
+ action === "disconnectWeb"
136
+ ) {
137
+ update();
138
+ }
139
+ };
140
+ w.addEventListener("message", onMessage as EventListener);
141
+ return () => w.removeEventListener?.("message", onMessage as EventListener);
142
+ }
143
+
144
+ async disconnect(): Promise<void> {
145
+ this.address = null;
146
+ this.isConnected = false;
147
+ }
148
+
149
+ async buildMessage(_opts: SignInMessageOptions): Promise<string> {
150
+ throw new Error("Tron sign-in is not supported yet");
151
+ }
152
+
153
+ /** TronLink's `signMessageV2`: the 0x hex signature over the TIP-191 prefixed message. */
154
+ async signMessage(message: string): Promise<string> {
155
+ const w = page();
156
+ const tronWeb = w ? tronWebOf(w) : undefined;
157
+ if (!this.address || !tronWeb) throw new Error("connect a Tron wallet first");
158
+ return tronWeb.trx.signMessageV2(message);
159
+ }
160
+ }
161
+
162
+ /** TronLink when it is on the page, as the one Tron wallet entry. */
163
+ export function discoverTronWallets(): WalletEntry[] {
164
+ if (!hasTronWallet()) return [];
165
+ return [
166
+ { id: "wallet:tron:tronlink", name: "TronLink", ecosystem: "tron", adapter: new TronAdapter() },
167
+ ];
168
+ }
@@ -4,7 +4,7 @@ import { SolanaAdapter, isStandardSolanaWallet, standardSolanaProvider } from ".
4
4
  import { SuiAdapter, discoverSuiWallets } from "./SuiAdapter";
5
5
  import { BitcoinAdapter } from "./BitcoinAdapter";
6
6
 
7
- export type WalletEcosystem = "solana" | "sui" | "bitcoin";
7
+ export type WalletEcosystem = "solana" | "sui" | "bitcoin" | "tron";
8
8
 
9
9
  export interface WalletEntry {
10
10
  /** Stable id, e.g. "wallet:solana:phantom" — matches a walletConfigs key. */
@@ -3,9 +3,9 @@ import { ecosystemBySyntheticChainId } from "./syntheticChains";
3
3
 
4
4
  /** Derive the signer family from the (possibly synthetic) chainId of the active connector. */
5
5
  export function familyFromChainId(chainId?: number): SignerFamily {
6
- if (chainId != null && ecosystemBySyntheticChainId[chainId]) {
7
- return ecosystemBySyntheticChainId[chainId];
8
- }
6
+ const ecosystem = chainId == null ? undefined : ecosystemBySyntheticChainId[chainId];
7
+ if (ecosystem === "tron") throw new Error("Tron sign-in is not supported yet");
8
+ if (ecosystem) return ecosystem;
9
9
  return "evm";
10
10
  }
11
11
 
@@ -2,6 +2,7 @@ import type { Config, Connector, CreateConnectorFn } from "wagmi";
2
2
 
3
3
  import { getConnectorEcosystem } from "@multiplatform.one/connectkit";
4
4
  import { discoverWallets } from "../adapters/discover";
5
+ import { discoverTronWallets } from "../adapters/TronAdapter";
5
6
  import { ecosystemBySyntheticChainId } from "./syntheticChains";
6
7
  import { walletAdapterConnector } from "./walletAdapterConnector";
7
8
 
@@ -38,7 +39,7 @@ export function ensureWalletConnectors(config: Config): number {
38
39
  ]);
39
40
  const existing = new Set(config.connectors.map((c) => c.id));
40
41
  let added = 0;
41
- for (const entry of discoverWallets()) {
42
+ for (const entry of [...discoverWallets(), ...discoverTronWallets()]) {
42
43
  if (existing.has(entry.id) || !listed.has(entry.ecosystem)) continue;
43
44
  const fn = walletAdapterConnector({
44
45
  id: entry.id,
@@ -8,7 +8,7 @@
8
8
  import type { Chain } from "viem";
9
9
  import type { Ecosystem } from "@multiplatform.one/connectkit";
10
10
 
11
- // 0x534f4c="SOL", 0x535549="SUI", 0x425443="BTC" — reserved, collision-free vs
11
+ // 0x534f4c="SOL", 0x535549="SUI", 0x425443="BTC", 0x545258="TRX" — reserved, collision-free vs
12
12
  // real EVM chainIds.
13
13
  /** @deprecated The wagmi shim for Solana, Sui and Bitcoin wallets, which goes in a later major when the connect modal reads the connection store (MPO-385). Use the `sol()`, `sui()` and `btc()` families and `useConnection()`. */
14
14
  export const SOLANA_CHAIN_ID = 0x534f4c; // 5_459_788
@@ -16,17 +16,21 @@ export const SOLANA_CHAIN_ID = 0x534f4c; // 5_459_788
16
16
  export const SUI_CHAIN_ID = 0x535549; // 5_461_321
17
17
  /** @deprecated The wagmi shim for Solana, Sui and Bitcoin wallets, which goes in a later major when the connect modal reads the connection store (MPO-385). Use the `sol()`, `sui()` and `btc()` families and `useConnection()`. */
18
18
  export const BITCOIN_CHAIN_ID = 0x425443; // 4_347_459
19
+ /** @deprecated The wagmi shim for Solana, Sui, Bitcoin and Tron wallets, which goes in a later major when the connect modal reads the connection store (MPO-385). Use the `tron()` family from `./tron` and `useConnection()`. */
20
+ export const TRON_CHAIN_ID = 0x545258; // 5_526_104
19
21
 
20
22
  export const syntheticChainIdByEcosystem: Record<Exclude<Ecosystem, "evm">, number> = {
21
23
  solana: SOLANA_CHAIN_ID,
22
24
  sui: SUI_CHAIN_ID,
23
25
  bitcoin: BITCOIN_CHAIN_ID,
26
+ tron: TRON_CHAIN_ID,
24
27
  };
25
28
 
26
29
  export const ecosystemBySyntheticChainId: Record<number, Ecosystem> = {
27
30
  [SOLANA_CHAIN_ID]: "solana",
28
31
  [SUI_CHAIN_ID]: "sui",
29
32
  [BITCOIN_CHAIN_ID]: "bitcoin",
33
+ [TRON_CHAIN_ID]: "tron",
30
34
  };
31
35
 
32
36
  /** @deprecated The wagmi shim for Solana, Sui and Bitcoin wallets, which goes in a later major when the connect modal reads the connection store (MPO-385). Use the `sol()`, `sui()` and `btc()` families and `useConnection()`. */
@@ -56,6 +60,8 @@ export const solanaChain = makeChain(SOLANA_CHAIN_ID, "Solana", "SOL", 9);
56
60
  export const suiChain = makeChain(SUI_CHAIN_ID, "Sui", "SUI", 9);
57
61
  /** @deprecated The wagmi shim for Solana, Sui and Bitcoin wallets, which goes in a later major when the connect modal reads the connection store (MPO-385). Use the `sol()`, `sui()` and `btc()` families and `useConnection()`. */
58
62
  export const bitcoinChain = makeChain(BITCOIN_CHAIN_ID, "Bitcoin", "BTC", 8);
63
+ /** @deprecated The wagmi shim for Solana, Sui, Bitcoin and Tron wallets, which goes in a later major when the connect modal reads the connection store (MPO-385). Use the `tron()` family from `./tron` and `useConnection()`. */
64
+ export const tronChain = makeChain(TRON_CHAIN_ID, "Tron", "TRX", 6);
59
65
 
60
66
  /** @deprecated The wagmi shim for Solana, Sui and Bitcoin wallets, which goes in a later major when the connect modal reads the connection store (MPO-385). Use the `sol()`, `sui()` and `btc()` families and `useConnection()`. */
61
- export const syntheticChains: Chain[] = [solanaChain, suiChain, bitcoinChain];
67
+ export const syntheticChains: Chain[] = [solanaChain, suiChain, bitcoinChain, tronChain];
@@ -7,6 +7,7 @@ import { setAppMeta } from "@multiplatform.one/connectkit";
7
7
  import defaultConnectors from "./defaultConnectors";
8
8
  import type { RestoredSessionTimeout } from "./connectors/restoredSession";
9
9
  import { discoverWallets, type WalletEcosystem } from "./adapters/discover";
10
+ import { discoverTronWallets } from "./adapters/TronAdapter";
10
11
  import { getWalletConnectors } from "./connectors/getWalletConnectors";
11
12
  import { ecosystemBySyntheticChainId, syntheticChains } from "./connectors/syntheticChains";
12
13
 
@@ -32,7 +33,7 @@ type DefaultConfigProps = {
32
33
  metaMaskRestoredSessionTimeout?: RestoredSessionTimeout;
33
34
  // wallet: append shim-connectors for any detected non-EVM wallet (Solana/Sui/
34
35
  // Bitcoin) alongside the EVM connectors. No-op when none are installed. A list
35
- // limits it to those ecosystems.
36
+ // limits it to those ecosystems; Tron is listed only when a list names it.
36
37
  enableWallet?: boolean | readonly WalletEcosystem[];
37
38
  } & Partial<CreateConfigParameters>;
38
39
 
@@ -90,7 +91,9 @@ const defaultConfig = ({
90
91
  ? [
91
92
  ...(baseConnectors ?? []),
92
93
  ...getWalletConnectors(
93
- discoverWallets().filter((entry) => ecosystems.includes(entry.ecosystem)),
94
+ [...discoverWallets(), ...discoverTronWallets()].filter((entry) =>
95
+ ecosystems.includes(entry.ecosystem),
96
+ ),
94
97
  ),
95
98
  ]
96
99
  : baseConnectors;
@@ -61,6 +61,8 @@ export type SIWEContextValue = Required<Omit<SIWEConfig, "onSign" | "subscribeNo
61
61
  nonce: ReturnType<typeof useQuery<string | null>>;
62
62
  session: ReturnType<typeof useQuery<SIWESession | null>>;
63
63
  status: StatusState;
64
+ /** What ended the last sign-in, while status is ERROR or REJECTED. */
65
+ error: Error | null;
64
66
  signIn: () => Promise<SIWESession | false>;
65
67
  resetStatus: () => void;
66
68
  };
@@ -26,6 +26,20 @@ const b64 = (s: string) => window.btoa(unescape(encodeURIComponent(s)));
26
26
  * connection store holds: `<SignInProvider {...kc.signInConfig(onSign)}>`,
27
27
  * or Web3Provider's `signIn` prop.
28
28
  */
29
+ // A transport wraps the wallet's own refusal (viem's HttpRequestError around a
30
+ // 4001), so the code can sit anywhere down the cause chain.
31
+ function isUserRejection(error: unknown): boolean {
32
+ for (
33
+ let cause = error as { code?: unknown; cause?: unknown } | undefined, depth = 0;
34
+ cause && depth < 8;
35
+ cause = cause.cause as typeof cause, depth++
36
+ ) {
37
+ if (cause.code === -32000 || cause.code === 4001 || cause.code === "ACTION_REJECTED")
38
+ return true;
39
+ }
40
+ return false;
41
+ }
42
+
29
43
  export const SIWEProvider = ({
30
44
  children,
31
45
  enabled = true,
@@ -39,7 +53,11 @@ export const SIWEProvider = ({
39
53
  ...siweConfig
40
54
  }: Props) => {
41
55
  const [status, setStatus] = useState<StatusState>(StatusState.READY);
42
- const resetStatus = () => setStatus(StatusState.READY);
56
+ const [error, setError] = useState<Error | null>(null);
57
+ const resetStatus = () => {
58
+ setStatus(StatusState.READY);
59
+ setError(null);
60
+ };
43
61
 
44
62
  // Only allow for mounting SIWEProvider once, so we avoid weird global state
45
63
  // collisions.
@@ -111,15 +129,8 @@ export const SIWEProvider = ({
111
129
 
112
130
  const onError = (error: any) => {
113
131
  console.error("signIn error", error, error.message);
114
- switch (error.code) {
115
- case -32000: // user rejected, as some wallets report it
116
- case 4001: // MetaMask: user rejected
117
- case "ACTION_REJECTED": // MetaMask: user rejected
118
- setStatus(StatusState.REJECTED);
119
- break;
120
- default:
121
- setStatus(StatusState.ERROR);
122
- }
132
+ setError(error instanceof Error ? error : new Error(String(error)));
133
+ setStatus(isUserRejection(error) ? StatusState.REJECTED : StatusState.ERROR);
123
134
  };
124
135
 
125
136
  const signIn = async () => {
@@ -135,6 +146,7 @@ export const SIWEProvider = ({
135
146
  if (!chainId) throw new Error("No chainId found");
136
147
 
137
148
  setStatus(StatusState.LOADING);
149
+ setError(null);
138
150
 
139
151
  // Fetch this sign-in's own nonce. A server that consumes its nonce on
140
152
  // verify refuses the one cached at mount the second time, so a cached
@@ -249,6 +261,7 @@ export const SIWEProvider = ({
249
261
  signIn,
250
262
  signOut: signOutAndRefetch,
251
263
  status,
264
+ error,
252
265
  resetStatus,
253
266
  }}
254
267
  >
@@ -89,6 +89,14 @@ export const walletConfigs: {
89
89
  icon: <BrandIcon bg="#000000" fg="#FFFFFF" glyph="OK" />,
90
90
  iconShape: "squircle",
91
91
  },
92
+ "wallet:tron:tronlink": {
93
+ icon: <BrandIcon bg="#EB0029" fg="#FFFFFF" glyph="T" />,
94
+ iconShape: "squircle",
95
+ downloadUrls: {
96
+ website: "https://www.tronlink.org",
97
+ chrome: "https://chromewebstore.google.com/detail/tronlink/ibnejdfjmmkpcnlpebklmnkoeoihofec",
98
+ },
99
+ },
92
100
  aaveAccountProvider: {
93
101
  name: "Aave Account",
94
102
  shortName: "Aave",
@@ -1,9 +1,11 @@
1
1
  import type { Config } from "wagmi";
2
2
  import type { SolanaChain } from "../clients/solanaMessage";
3
+ import type { ChainClient } from "../clients/types";
4
+ import type { WalletAdapter } from "../connectkit/adapters/types";
3
5
  import type { WalletFamily } from "../core/family";
4
6
 
5
- /** The ecosystem a wagmi connector carries: `evm`, or a Solana, Sui or Bitcoin shim's. */
6
- export type HostedEcosystem = "evm" | "solana" | "sui" | "bitcoin";
7
+ /** The ecosystem a wagmi connector carries: `evm`, or a Solana, Sui, Bitcoin or Tron shim's. */
8
+ export type HostedEcosystem = "evm" | "solana" | "sui" | "bitcoin" | "tron";
7
9
 
8
10
  /**
9
11
  * How a Web3Provider hosts a built-in family on its wagmi config while the
@@ -19,6 +21,11 @@ export interface WagmiHosting {
19
21
  readonly solanaChain?: SolanaChain;
20
22
  /** The wagmi config the app gave `eth()`, which the provider then uses. */
21
23
  readonly config?: Config;
24
+ /**
25
+ * The family's client over its shim's adapter, for a family whose client
26
+ * the shared connector lookup does not build, such as Tron's web-only one.
27
+ */
28
+ readonly client?: (adapter: WalletAdapter) => ChainClient | null;
22
29
  }
23
30
 
24
31
  const hosting = new WeakMap<WalletFamily, WagmiHosting>();
@@ -0,0 +1,118 @@
1
+ // @vitest-environment happy-dom
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { createConfig, http } from "wagmi";
4
+ import { mainnet } from "wagmi/chains";
5
+ import type { TronClient } from "../clients/tron";
6
+ import { TronAdapter } from "../connectkit/adapters/TronAdapter";
7
+ import { tronChain } from "../connectkit/connectors/syntheticChains";
8
+ import { walletAdapterConnector } from "../connectkit/connectors/walletAdapterConnector";
9
+ import { createFamilyRegistry } from "../core/family";
10
+ import { hostFamiliesOnWagmi } from "../wagmi/host";
11
+ import { wagmiHosting } from "./host";
12
+ import { walletFamilies } from "./index";
13
+ import { tron, tronDriver } from "./tron";
14
+
15
+ const address = "TKHuVq1oKVruCGLvqVexFs6dawKv6fQgFs";
16
+ const usdt = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t";
17
+ const globals: string[] = [];
18
+ const install = (name: string, value: unknown) => {
19
+ globals.push(name);
20
+ (window as unknown as Record<string, unknown>)[name] = value;
21
+ };
22
+
23
+ afterEach(() => {
24
+ for (const name of globals.splice(0)) Reflect.deleteProperty(window, name);
25
+ vi.unstubAllGlobals();
26
+ });
27
+
28
+ function injectTronLink(host = "https://nile.trongrid.io") {
29
+ const web = {
30
+ defaultAddress: { base58: false as string | false },
31
+ fullNode: { host },
32
+ trx: { signMessageV2: vi.fn(async () => "0xsig") },
33
+ };
34
+ install("tronLink", {
35
+ tronWeb: web,
36
+ request: vi.fn(async () => {
37
+ web.defaultAddress.base58 = address;
38
+ return { code: 200 };
39
+ }),
40
+ });
41
+ install("tronWeb", web);
42
+ return web;
43
+ }
44
+
45
+ function trongrid(word = "2a") {
46
+ const fetch = vi.fn(async (_url: string | URL | Request, _init?: RequestInit) =>
47
+ Response.json({ result: { result: true }, constant_result: [word] }),
48
+ );
49
+ vi.stubGlobal("fetch", fetch);
50
+ return fetch;
51
+ }
52
+
53
+ describe("the tron family", () => {
54
+ it("is its own family, beside the built-in ones and not among them", () => {
55
+ const family = tron();
56
+ expect(family).toMatchObject({ id: "tron", label: "Tron", aliases: ["trx"] });
57
+ expect(createFamilyRegistry([family]).require("trx")).toBe(family);
58
+ expect(wagmiHosting(family)).toMatchObject({ ecosystem: "tron", chainId: "tron" });
59
+ expect(walletFamilies().map((entry) => entry.id)).not.toContain("tron");
60
+ });
61
+
62
+ it("connects TronLink on the light driver and reads TRC-20 on TronLink's network", async () => {
63
+ injectTronLink();
64
+ const fetch = trongrid();
65
+ const driver = tronDriver();
66
+ expect(driver.connectors()).toEqual([{ id: "wallet:tron:tronlink", name: "TronLink" }]);
67
+ await expect(driver.connect("wallet:tron:tronlink")).resolves.toEqual({
68
+ address,
69
+ chainId: "tron",
70
+ });
71
+ const client = (await driver.client?.(driver.getState())) as TronClient;
72
+ expect(client).toMatchObject({ family: "tron", address, network: "nile" });
73
+ await expect(client.trc20Balance(usdt)).resolves.toBe(42n);
74
+ expect(fetch.mock.calls[0][0]).toBe("https://nile.trongrid.io/wallet/triggerconstantcontract");
75
+ });
76
+
77
+ it("hears TronLink when it injects itself after the page loaded", () => {
78
+ const driver = tronDriver();
79
+ expect(driver.connectors()).toEqual([]);
80
+ const changed = vi.fn();
81
+ const unwatch = driver.watchConnectors?.(changed);
82
+ injectTronLink();
83
+ window.dispatchEvent(new Event("tronLink#initialized"));
84
+ expect(changed).toHaveBeenCalledTimes(1);
85
+ expect(driver.connectors()).toHaveLength(1);
86
+ unwatch?.();
87
+ window.dispatchEvent(new Event("tronLink#initialized"));
88
+ expect(changed).toHaveBeenCalledTimes(1);
89
+ });
90
+
91
+ it("hosted on wagmi, connects through the modal's shim and hands back its Tron client", async () => {
92
+ injectTronLink("https://api.trongrid.io");
93
+ trongrid("0");
94
+ const adapter = new TronAdapter();
95
+ const config = createConfig({
96
+ chains: [mainnet, tronChain],
97
+ connectors: [
98
+ walletAdapterConnector({
99
+ id: "wallet:tron:tronlink",
100
+ name: "TronLink",
101
+ ecosystem: "tron",
102
+ adapter,
103
+ }),
104
+ ],
105
+ transports: { [mainnet.id]: http(), [tronChain.id]: http() },
106
+ });
107
+ const [hosted] = hostFamiliesOnWagmi([tron()], config);
108
+ const driver = hosted.driver?.();
109
+ expect(driver?.connectors().map((connector) => connector.id)).toEqual(["wallet:tron:tronlink"]);
110
+ await expect(driver?.connect("wallet:tron:tronlink")).resolves.toEqual({
111
+ address,
112
+ chainId: "tron",
113
+ });
114
+ const client = (await driver?.client?.(driver.getState())) as TronClient;
115
+ expect(client).toMatchObject({ family: "tron", address, network: "mainnet" });
116
+ await expect(client.trc20Balance(usdt)).resolves.toBe(0n);
117
+ });
118
+ });
@@ -0,0 +1,63 @@
1
+ import { tronClient, type TronClientOptions } from "../clients/tron";
2
+ import { discoverTronWallets, TronAdapter } from "../connectkit/adapters/TronAdapter";
3
+ import type { WalletMessageSpec } from "../core/message";
4
+ import { defineWalletFamily, type WalletFamily } from "../core/family";
5
+ import { lightDriver } from "../core/lightDriver";
6
+ import type { ConnectionDriver } from "../core/types";
7
+ import { withHosting } from "./host";
8
+
9
+ export const tronMessage: WalletMessageSpec = {
10
+ header: "wants you to sign in with your Tron account:",
11
+ statement: "Sign in With Tron.",
12
+ chainId: "tron",
13
+ };
14
+
15
+ export type TronFamilyOptions = Omit<TronClientOptions, "network">;
16
+
17
+ const networkOf = (adapter: unknown) =>
18
+ adapter instanceof TronAdapter ? { network: adapter.network } : {};
19
+
20
+ /** TronLink on the light driver. Hears TronLink when it injects itself after the page loaded. */
21
+ export function tronDriver(options: TronFamilyOptions = {}): ConnectionDriver {
22
+ return lightDriver({
23
+ wallets: () => discoverTronWallets().map(({ id, name, adapter }) => ({ id, name, adapter })),
24
+ watchWallets(listener) {
25
+ if (typeof window === "undefined" || typeof window.addEventListener !== "function") {
26
+ return () => {};
27
+ }
28
+ const announced = (event: Event) => {
29
+ const action = (event as MessageEvent<{ message?: { action?: string } } | null>).data
30
+ ?.message?.action;
31
+ if (event.type === "tronLink#initialized" || action === "tabReply") listener();
32
+ };
33
+ window.addEventListener("tronLink#initialized", announced);
34
+ window.addEventListener("message", announced);
35
+ return () => {
36
+ window.removeEventListener("tronLink#initialized", announced);
37
+ window.removeEventListener("message", announced);
38
+ };
39
+ },
40
+ chainId: "tron",
41
+ client: (wallet) => tronClient(wallet.adapter, { ...options, ...networkOf(wallet.adapter) }),
42
+ });
43
+ }
44
+
45
+ /**
46
+ * The Tron family: TronLink, through the connect modal under Web3Provider.
47
+ * Its client reads TRC-20 balances through TronGrid on the network TronLink
48
+ * is on. Web only, from `@multiplatform.one/web3/tron`.
49
+ */
50
+ export function tron(options: TronFamilyOptions = {}): WalletFamily {
51
+ const family = defineWalletFamily({
52
+ id: "tron",
53
+ label: "Tron",
54
+ aliases: ["trx"],
55
+ message: tronMessage,
56
+ driver: () => tronDriver(options),
57
+ });
58
+ return withHosting(family, {
59
+ ecosystem: "tron",
60
+ chainId: "tron",
61
+ client: (adapter) => tronClient(adapter, { ...options, ...networkOf(adapter) }),
62
+ });
63
+ }