@asseteragmbh/wallet-connector 0.1.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.
- package/README.md +103 -0
- package/dist/chunk-L7EBYABA.js +129 -0
- package/dist/chunk-L7EBYABA.js.map +1 -0
- package/dist/chunk-N6D53D3G.js +63 -0
- package/dist/chunk-N6D53D3G.js.map +1 -0
- package/dist/chunk-QPNIGEP4.js +259 -0
- package/dist/chunk-QPNIGEP4.js.map +1 -0
- package/dist/index.cjs +332 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.cjs +76 -0
- package/dist/protocol.cjs.map +1 -0
- package/dist/protocol.d.cts +118 -0
- package/dist/protocol.d.ts +118 -0
- package/dist/protocol.js +3 -0
- package/dist/protocol.js.map +1 -0
- package/dist/provider-BEIsX3q_.d.cts +46 -0
- package/dist/provider-BEIsX3q_.d.ts +46 -0
- package/dist/rainbowkit.cjs +446 -0
- package/dist/rainbowkit.cjs.map +1 -0
- package/dist/rainbowkit.d.cts +30 -0
- package/dist/rainbowkit.d.ts +30 -0
- package/dist/rainbowkit.js +22 -0
- package/dist/rainbowkit.js.map +1 -0
- package/dist/wagmi.cjs +434 -0
- package/dist/wagmi.cjs.map +1 -0
- package/dist/wagmi.d.cts +23 -0
- package/dist/wagmi.d.ts +23 -0
- package/dist/wagmi.js +5 -0
- package/dist/wagmi.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pop-up protocol between a partner page (the opener) and the Assetera Wallet (the pop-up) — ADR-0054 D3/D4.
|
|
3
|
+
*
|
|
4
|
+
* This file is the CONTRACT. The connector in this package speaks the opener side; AsseteraWalletFront's
|
|
5
|
+
* `/connect` page speaks the pop-up side and imports these types from `@asseteragmbh/wallet-connector/protocol`.
|
|
6
|
+
* Change it only in a backwards-compatible way, or bump `PROTOCOL_VERSION` and support both on the wallet side:
|
|
7
|
+
* partner sites upgrade on their own schedule.
|
|
8
|
+
*
|
|
9
|
+
* ## The handshake
|
|
10
|
+
*
|
|
11
|
+
* 1. The partner opens `${walletUrl}${CONNECT_PATH}?origin=<partner origin>&v=<version>` from a user click.
|
|
12
|
+
* 2. The pop-up checks the claimed origin against its allowlist (D4). If listed, it posts `ready` to
|
|
13
|
+
* `window.opener` with `targetOrigin` = that origin. The browser delivers it ONLY if the opener really is
|
|
14
|
+
* that origin, so a page cannot claim someone else's origin and still hear the answer.
|
|
15
|
+
* 3. The opener waits for `ready` from the wallet origin, then sends `request`s with `targetOrigin` = the wallet
|
|
16
|
+
* origin. The pop-up accepts a message only when `event.origin` is the allowed origin from step 2 AND
|
|
17
|
+
* `event.source === window.opener`, and answers with `targetOrigin` = that origin. Nothing else is accepted.
|
|
18
|
+
*
|
|
19
|
+
* ## Lifetime
|
|
20
|
+
*
|
|
21
|
+
* The pop-up stays open while the partner uses the wallet (ADR-0054, "the wallet tab must stay open"). When it is
|
|
22
|
+
* closed, the opener sees `disconnect` (or notices `popup.closed`) and must reconnect from a user click.
|
|
23
|
+
*/
|
|
24
|
+
declare const PROTOCOL_VERSION: 1;
|
|
25
|
+
/** The pop-up route on the wallet origin. */
|
|
26
|
+
declare const CONNECT_PATH = "/connect";
|
|
27
|
+
/** Every message carries this prefix in `type`, so both sides can ignore unrelated `postMessage` traffic. */
|
|
28
|
+
declare const MESSAGE_PREFIX: "assetera-wallet:";
|
|
29
|
+
/**
|
|
30
|
+
* The EIP-1193 methods the pop-up answers (ADR-0054 D3). Anything else is refused with 4200. Read-only chain
|
|
31
|
+
* calls (`eth_call`, `eth_getBalance`, …) do not go through the pop-up; wagmi sends them to its own transports.
|
|
32
|
+
*/
|
|
33
|
+
declare const SUPPORTED_METHODS: readonly ["eth_requestAccounts", "eth_accounts", "eth_chainId", "wallet_switchEthereumChain", "personal_sign", "eth_signTypedData_v4", "eth_sendTransaction"];
|
|
34
|
+
type SupportedMethod = (typeof SUPPORTED_METHODS)[number];
|
|
35
|
+
declare function isSupportedMethod(method: string): method is SupportedMethod;
|
|
36
|
+
/** EIP-1193 / EIP-1474 error codes the pop-up uses. */
|
|
37
|
+
declare const RpcErrorCode: {
|
|
38
|
+
/** The client rejected the request in the pop-up. */
|
|
39
|
+
readonly UserRejected: 4001;
|
|
40
|
+
/** Not connected yet (no `eth_requestAccounts` approved in this pop-up). */
|
|
41
|
+
readonly Unauthorized: 4100;
|
|
42
|
+
/** The method is not in SUPPORTED_METHODS. */
|
|
43
|
+
readonly UnsupportedMethod: 4200;
|
|
44
|
+
/** The pop-up closed, or the wallet session ended. */
|
|
45
|
+
readonly Disconnected: 4900;
|
|
46
|
+
/** `wallet_switchEthereumChain` to a chain the wallet does not offer. */
|
|
47
|
+
readonly UnrecognizedChain: 4902;
|
|
48
|
+
/** Malformed params. */
|
|
49
|
+
readonly InvalidParams: -32602;
|
|
50
|
+
/** Anything unexpected inside the wallet. */
|
|
51
|
+
readonly Internal: -32603;
|
|
52
|
+
};
|
|
53
|
+
type RpcErrorCode = (typeof RpcErrorCode)[keyof typeof RpcErrorCode];
|
|
54
|
+
interface RpcError {
|
|
55
|
+
code: number;
|
|
56
|
+
message: string;
|
|
57
|
+
data?: unknown;
|
|
58
|
+
}
|
|
59
|
+
/** The pop-up is loaded and accepts requests from this opener. */
|
|
60
|
+
interface ReadyMessage {
|
|
61
|
+
type: `${typeof MESSAGE_PREFIX}ready`;
|
|
62
|
+
v: typeof PROTOCOL_VERSION;
|
|
63
|
+
/** Shown to the partner for diagnostics only; the partner must not rely on it for anything. */
|
|
64
|
+
walletVersion?: string;
|
|
65
|
+
}
|
|
66
|
+
/** The answer to one `request`, matched by `id`. Exactly one of `result` / `error`. */
|
|
67
|
+
type ResponseMessage = {
|
|
68
|
+
type: `${typeof MESSAGE_PREFIX}response`;
|
|
69
|
+
v: typeof PROTOCOL_VERSION;
|
|
70
|
+
id: string;
|
|
71
|
+
result: unknown;
|
|
72
|
+
} | {
|
|
73
|
+
type: `${typeof MESSAGE_PREFIX}response`;
|
|
74
|
+
v: typeof PROTOCOL_VERSION;
|
|
75
|
+
id: string;
|
|
76
|
+
error: RpcError;
|
|
77
|
+
};
|
|
78
|
+
/** EIP-1193 provider events, forwarded to the partner. */
|
|
79
|
+
type EventMessage = {
|
|
80
|
+
type: `${typeof MESSAGE_PREFIX}event`;
|
|
81
|
+
v: typeof PROTOCOL_VERSION;
|
|
82
|
+
event: "accountsChanged";
|
|
83
|
+
data: `0x${string}`[];
|
|
84
|
+
} | {
|
|
85
|
+
type: `${typeof MESSAGE_PREFIX}event`;
|
|
86
|
+
v: typeof PROTOCOL_VERSION;
|
|
87
|
+
event: "chainChanged";
|
|
88
|
+
data: `0x${string}`;
|
|
89
|
+
} | {
|
|
90
|
+
type: `${typeof MESSAGE_PREFIX}event`;
|
|
91
|
+
v: typeof PROTOCOL_VERSION;
|
|
92
|
+
event: "disconnect";
|
|
93
|
+
data: RpcError;
|
|
94
|
+
};
|
|
95
|
+
type WalletToPartnerMessage = ReadyMessage | ResponseMessage | EventMessage;
|
|
96
|
+
interface RequestMessage {
|
|
97
|
+
type: `${typeof MESSAGE_PREFIX}request`;
|
|
98
|
+
v: typeof PROTOCOL_VERSION;
|
|
99
|
+
/** Unique per request within one connection; the response carries it back. */
|
|
100
|
+
id: string;
|
|
101
|
+
method: string;
|
|
102
|
+
params?: unknown[] | Record<string, unknown>;
|
|
103
|
+
}
|
|
104
|
+
/** The partner disconnects (for example the user clicked "Disconnect" in the partner page). */
|
|
105
|
+
interface DisconnectMessage {
|
|
106
|
+
type: `${typeof MESSAGE_PREFIX}disconnect`;
|
|
107
|
+
v: typeof PROTOCOL_VERSION;
|
|
108
|
+
}
|
|
109
|
+
type PartnerToWalletMessage = RequestMessage | DisconnectMessage;
|
|
110
|
+
declare function isReadyMessage(value: unknown): value is ReadyMessage;
|
|
111
|
+
declare function isResponseMessage(value: unknown): value is ResponseMessage;
|
|
112
|
+
declare function isEventMessage(value: unknown): value is EventMessage;
|
|
113
|
+
declare function isRequestMessage(value: unknown): value is RequestMessage;
|
|
114
|
+
declare function isDisconnectMessage(value: unknown): value is DisconnectMessage;
|
|
115
|
+
/** The URL the partner opens. `partnerOrigin` is `window.location.origin` of the partner page. */
|
|
116
|
+
declare function connectUrl(walletUrl: string, partnerOrigin: string): string;
|
|
117
|
+
|
|
118
|
+
export { CONNECT_PATH, type DisconnectMessage, type EventMessage, MESSAGE_PREFIX, PROTOCOL_VERSION, type PartnerToWalletMessage, type ReadyMessage, type RequestMessage, type ResponseMessage, type RpcError, RpcErrorCode, SUPPORTED_METHODS, type SupportedMethod, type WalletToPartnerMessage, connectUrl, isDisconnectMessage, isEventMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSupportedMethod };
|
package/dist/protocol.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { CONNECT_PATH, MESSAGE_PREFIX, PROTOCOL_VERSION, RpcErrorCode, SUPPORTED_METHODS, connectUrl, isDisconnectMessage, isEventMessage, isReadyMessage, isRequestMessage, isResponseMessage, isSupportedMethod } from './chunk-N6D53D3G.js';
|
|
2
|
+
//# sourceMappingURL=protocol.js.map
|
|
3
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"protocol.js"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Arguments accepted by `request`, mirroring EIP-1193. */
|
|
2
|
+
interface RequestArguments {
|
|
3
|
+
method: string;
|
|
4
|
+
params?: unknown[] | Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
/** EIP-1193 provider events emitted by the pop-up. */
|
|
7
|
+
type ProviderEvent = "accountsChanged" | "chainChanged" | "connect" | "disconnect";
|
|
8
|
+
/**
|
|
9
|
+
* Listener shape for EIP-1193 provider events. `never[]` accepts a listener with any concrete parameter list
|
|
10
|
+
* (for example wagmi's `(accounts: string[]) => void`), while internal emission stays type-safe via a cast.
|
|
11
|
+
*/
|
|
12
|
+
type ProviderListener = (...args: never[]) => void;
|
|
13
|
+
/** The EIP-1193 surface returned by {@link createAsseteraWalletProvider}. */
|
|
14
|
+
interface AsseteraWalletProvider {
|
|
15
|
+
request(args: RequestArguments): Promise<unknown>;
|
|
16
|
+
on(event: ProviderEvent, listener: ProviderListener): void;
|
|
17
|
+
removeListener(event: ProviderEvent, listener: ProviderListener): void;
|
|
18
|
+
disconnect(): void;
|
|
19
|
+
}
|
|
20
|
+
/** Options for {@link createAsseteraWalletProvider}. */
|
|
21
|
+
interface AsseteraWalletProviderOptions {
|
|
22
|
+
/** Base URL of the wallet origin, e.g. `https://wallet.playground.assetera.com`. */
|
|
23
|
+
walletUrl: string;
|
|
24
|
+
/** Chain id used before the wallet reports one, and as the local `eth_chainId` fallback. */
|
|
25
|
+
defaultChainId: number;
|
|
26
|
+
/** `window.open` feature string. Defaults to `"popup,width=420,height=720"`. */
|
|
27
|
+
popupFeatures?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* EIP-1193 error carrying a JSON-RPC `code` (and optional `data`). This is what every rejected `request`
|
|
31
|
+
* throws, so wagmi maps the wallet's `4001` / `4100` / `4200` / `4900` correctly.
|
|
32
|
+
*/
|
|
33
|
+
declare class ProviderRpcError extends Error {
|
|
34
|
+
readonly code: number;
|
|
35
|
+
readonly data?: unknown;
|
|
36
|
+
constructor(code: number, message: string, data?: unknown);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Create the EIP-1193 provider that talks to the Assetera Wallet pop-up.
|
|
40
|
+
*
|
|
41
|
+
* Call `request` from a user gesture: `eth_requestAccounts` opens the pop-up synchronously (before any
|
|
42
|
+
* `await`) so the browser treats it as part of the click and does not block it.
|
|
43
|
+
*/
|
|
44
|
+
declare function createAsseteraWalletProvider(options: AsseteraWalletProviderOptions): AsseteraWalletProvider;
|
|
45
|
+
|
|
46
|
+
export { type AsseteraWalletProvider as A, type ProviderEvent as P, type RequestArguments as R, type AsseteraWalletProviderOptions as a, type ProviderListener as b, ProviderRpcError as c, createAsseteraWalletProvider as d };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Arguments accepted by `request`, mirroring EIP-1193. */
|
|
2
|
+
interface RequestArguments {
|
|
3
|
+
method: string;
|
|
4
|
+
params?: unknown[] | Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
/** EIP-1193 provider events emitted by the pop-up. */
|
|
7
|
+
type ProviderEvent = "accountsChanged" | "chainChanged" | "connect" | "disconnect";
|
|
8
|
+
/**
|
|
9
|
+
* Listener shape for EIP-1193 provider events. `never[]` accepts a listener with any concrete parameter list
|
|
10
|
+
* (for example wagmi's `(accounts: string[]) => void`), while internal emission stays type-safe via a cast.
|
|
11
|
+
*/
|
|
12
|
+
type ProviderListener = (...args: never[]) => void;
|
|
13
|
+
/** The EIP-1193 surface returned by {@link createAsseteraWalletProvider}. */
|
|
14
|
+
interface AsseteraWalletProvider {
|
|
15
|
+
request(args: RequestArguments): Promise<unknown>;
|
|
16
|
+
on(event: ProviderEvent, listener: ProviderListener): void;
|
|
17
|
+
removeListener(event: ProviderEvent, listener: ProviderListener): void;
|
|
18
|
+
disconnect(): void;
|
|
19
|
+
}
|
|
20
|
+
/** Options for {@link createAsseteraWalletProvider}. */
|
|
21
|
+
interface AsseteraWalletProviderOptions {
|
|
22
|
+
/** Base URL of the wallet origin, e.g. `https://wallet.playground.assetera.com`. */
|
|
23
|
+
walletUrl: string;
|
|
24
|
+
/** Chain id used before the wallet reports one, and as the local `eth_chainId` fallback. */
|
|
25
|
+
defaultChainId: number;
|
|
26
|
+
/** `window.open` feature string. Defaults to `"popup,width=420,height=720"`. */
|
|
27
|
+
popupFeatures?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* EIP-1193 error carrying a JSON-RPC `code` (and optional `data`). This is what every rejected `request`
|
|
31
|
+
* throws, so wagmi maps the wallet's `4001` / `4100` / `4200` / `4900` correctly.
|
|
32
|
+
*/
|
|
33
|
+
declare class ProviderRpcError extends Error {
|
|
34
|
+
readonly code: number;
|
|
35
|
+
readonly data?: unknown;
|
|
36
|
+
constructor(code: number, message: string, data?: unknown);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Create the EIP-1193 provider that talks to the Assetera Wallet pop-up.
|
|
40
|
+
*
|
|
41
|
+
* Call `request` from a user gesture: `eth_requestAccounts` opens the pop-up synchronously (before any
|
|
42
|
+
* `await`) so the browser treats it as part of the click and does not block it.
|
|
43
|
+
*/
|
|
44
|
+
declare function createAsseteraWalletProvider(options: AsseteraWalletProviderOptions): AsseteraWalletProvider;
|
|
45
|
+
|
|
46
|
+
export { type AsseteraWalletProvider as A, type ProviderEvent as P, type RequestArguments as R, type AsseteraWalletProviderOptions as a, type ProviderListener as b, ProviderRpcError as c, createAsseteraWalletProvider as d };
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@wagmi/core');
|
|
4
|
+
var viem = require('viem');
|
|
5
|
+
|
|
6
|
+
// src/rainbowkit.ts
|
|
7
|
+
|
|
8
|
+
// src/icon.ts
|
|
9
|
+
var ICON_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128" fill="none"><rect width="128" height="128" rx="28" fill="#1a1a2e"/><path fill="#ffffff" fill-rule="evenodd" d="M64 24 100 104H80.5L73.6 86H54.4L47.5 104H28L64 24Zm-4.5 44.5h9L64 54.4 59.5 68.5Z"/></svg>';
|
|
10
|
+
var ASSETERA_WALLET_ICON = `data:image/svg+xml,${encodeURIComponent(ICON_SVG)}`;
|
|
11
|
+
|
|
12
|
+
// src/protocol.ts
|
|
13
|
+
var PROTOCOL_VERSION = 1;
|
|
14
|
+
var CONNECT_PATH = "/connect";
|
|
15
|
+
var MESSAGE_PREFIX = "assetera-wallet:";
|
|
16
|
+
var SUPPORTED_METHODS = [
|
|
17
|
+
"eth_requestAccounts",
|
|
18
|
+
"eth_accounts",
|
|
19
|
+
"eth_chainId",
|
|
20
|
+
"wallet_switchEthereumChain",
|
|
21
|
+
"personal_sign",
|
|
22
|
+
"eth_signTypedData_v4",
|
|
23
|
+
"eth_sendTransaction"
|
|
24
|
+
];
|
|
25
|
+
function isSupportedMethod(method) {
|
|
26
|
+
return SUPPORTED_METHODS.includes(method);
|
|
27
|
+
}
|
|
28
|
+
var RpcErrorCode = {
|
|
29
|
+
/** Not connected yet (no `eth_requestAccounts` approved in this pop-up). */
|
|
30
|
+
Unauthorized: 4100,
|
|
31
|
+
/** The method is not in SUPPORTED_METHODS. */
|
|
32
|
+
UnsupportedMethod: 4200,
|
|
33
|
+
/** The pop-up closed, or the wallet session ended. */
|
|
34
|
+
Disconnected: 4900};
|
|
35
|
+
function isRecord(value) {
|
|
36
|
+
return typeof value === "object" && value !== null;
|
|
37
|
+
}
|
|
38
|
+
function hasType(value, suffix) {
|
|
39
|
+
return isRecord(value) && value.type === `${MESSAGE_PREFIX}${suffix}` && value.v === PROTOCOL_VERSION;
|
|
40
|
+
}
|
|
41
|
+
function isReadyMessage(value) {
|
|
42
|
+
return hasType(value, "ready");
|
|
43
|
+
}
|
|
44
|
+
function isResponseMessage(value) {
|
|
45
|
+
return hasType(value, "response") && typeof value.id === "string" && ("result" in value || isRecord(value.error) && typeof value.error.code === "number");
|
|
46
|
+
}
|
|
47
|
+
function isEventMessage(value) {
|
|
48
|
+
return hasType(value, "event") && (value.event === "accountsChanged" || value.event === "chainChanged" || value.event === "disconnect");
|
|
49
|
+
}
|
|
50
|
+
function connectUrl(walletUrl, partnerOrigin) {
|
|
51
|
+
const url = new URL(CONNECT_PATH, walletUrl);
|
|
52
|
+
url.searchParams.set("origin", partnerOrigin);
|
|
53
|
+
url.searchParams.set("v", String(PROTOCOL_VERSION));
|
|
54
|
+
return url.toString();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/provider.ts
|
|
58
|
+
var ProviderRpcError = class extends Error {
|
|
59
|
+
code;
|
|
60
|
+
data;
|
|
61
|
+
constructor(code, message, data) {
|
|
62
|
+
super(message);
|
|
63
|
+
this.name = "ProviderRpcError";
|
|
64
|
+
this.code = code;
|
|
65
|
+
this.data = data;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var DEFAULT_POPUP_FEATURES = "popup,width=420,height=720";
|
|
69
|
+
var POPUP_NAME = "assetera-wallet";
|
|
70
|
+
var CLOSE_POLL_MS = 500;
|
|
71
|
+
var SIGNING_METHODS = /* @__PURE__ */ new Set([
|
|
72
|
+
"personal_sign",
|
|
73
|
+
"eth_signTypedData_v4",
|
|
74
|
+
"eth_sendTransaction"
|
|
75
|
+
]);
|
|
76
|
+
function createDeferred() {
|
|
77
|
+
let resolve;
|
|
78
|
+
let reject;
|
|
79
|
+
const promise = new Promise((res, rej) => {
|
|
80
|
+
resolve = res;
|
|
81
|
+
reject = rej;
|
|
82
|
+
});
|
|
83
|
+
void promise.catch(() => {
|
|
84
|
+
});
|
|
85
|
+
return { promise, resolve, reject };
|
|
86
|
+
}
|
|
87
|
+
function toHexChainId(chainId) {
|
|
88
|
+
return `0x${chainId.toString(16)}`;
|
|
89
|
+
}
|
|
90
|
+
function createAsseteraWalletProvider(options) {
|
|
91
|
+
const { defaultChainId } = options;
|
|
92
|
+
const walletOrigin = new URL(options.walletUrl).origin;
|
|
93
|
+
const popupFeatures = options.popupFeatures ?? DEFAULT_POPUP_FEATURES;
|
|
94
|
+
let popup = null;
|
|
95
|
+
let ready = createDeferred();
|
|
96
|
+
let accounts = [];
|
|
97
|
+
let chainIdHex = null;
|
|
98
|
+
let walletDisconnected = false;
|
|
99
|
+
const pending = /* @__PURE__ */ new Map();
|
|
100
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
101
|
+
let closeTimer = null;
|
|
102
|
+
function currentChainId() {
|
|
103
|
+
return chainIdHex ?? toHexChainId(defaultChainId);
|
|
104
|
+
}
|
|
105
|
+
function blockedError() {
|
|
106
|
+
return new ProviderRpcError(
|
|
107
|
+
RpcErrorCode.Disconnected,
|
|
108
|
+
"The Assetera Wallet pop-up was blocked by the browser. The pop-up must be opened from a user click (for example a button press) and then the request retried."
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
function disconnectedError(message = "The Assetera Wallet pop-up was closed.") {
|
|
112
|
+
return new ProviderRpcError(RpcErrorCode.Disconnected, message);
|
|
113
|
+
}
|
|
114
|
+
function emit(event, ...args) {
|
|
115
|
+
const set = listeners.get(event);
|
|
116
|
+
if (!set) return;
|
|
117
|
+
for (const listener of set) {
|
|
118
|
+
try {
|
|
119
|
+
listener(...args);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error(`[assetera-wallet] listener for "${event}" threw`, error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function addListener(event, listener) {
|
|
126
|
+
let set = listeners.get(event);
|
|
127
|
+
if (!set) {
|
|
128
|
+
set = /* @__PURE__ */ new Set();
|
|
129
|
+
listeners.set(event, set);
|
|
130
|
+
}
|
|
131
|
+
set.add(listener);
|
|
132
|
+
}
|
|
133
|
+
function removeEventListener(event, listener) {
|
|
134
|
+
listeners.get(event)?.delete(listener);
|
|
135
|
+
}
|
|
136
|
+
function stopClosePolling() {
|
|
137
|
+
if (closeTimer !== null) {
|
|
138
|
+
clearInterval(closeTimer);
|
|
139
|
+
closeTimer = null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function startClosePolling() {
|
|
143
|
+
if (closeTimer !== null) return;
|
|
144
|
+
closeTimer = setInterval(() => {
|
|
145
|
+
if (popup?.closed) handlePopupClosed();
|
|
146
|
+
}, CLOSE_POLL_MS);
|
|
147
|
+
}
|
|
148
|
+
function rejectAllPending(error) {
|
|
149
|
+
for (const request2 of pending.values()) request2.reject(error);
|
|
150
|
+
pending.clear();
|
|
151
|
+
}
|
|
152
|
+
function handlePopupClosed() {
|
|
153
|
+
const hadPending = pending.size > 0;
|
|
154
|
+
stopClosePolling();
|
|
155
|
+
const closedPopup = popup;
|
|
156
|
+
popup = null;
|
|
157
|
+
const closedReady = ready;
|
|
158
|
+
ready = createDeferred();
|
|
159
|
+
const error = disconnectedError();
|
|
160
|
+
if (closedPopup) closedReady.reject(error);
|
|
161
|
+
rejectAllPending(error);
|
|
162
|
+
const shouldEmit = hadPending || walletDisconnected;
|
|
163
|
+
walletDisconnected = false;
|
|
164
|
+
if (shouldEmit) emit("disconnect", error);
|
|
165
|
+
}
|
|
166
|
+
function openPopup() {
|
|
167
|
+
if (popup && !popup.closed) {
|
|
168
|
+
popup.focus();
|
|
169
|
+
return popup;
|
|
170
|
+
}
|
|
171
|
+
if (typeof window === "undefined") return null;
|
|
172
|
+
const opened = window.open(
|
|
173
|
+
connectUrl(options.walletUrl, window.location.origin),
|
|
174
|
+
POPUP_NAME,
|
|
175
|
+
popupFeatures
|
|
176
|
+
);
|
|
177
|
+
if (!opened) return null;
|
|
178
|
+
popup = opened;
|
|
179
|
+
ready = createDeferred();
|
|
180
|
+
walletDisconnected = false;
|
|
181
|
+
startClosePolling();
|
|
182
|
+
return opened;
|
|
183
|
+
}
|
|
184
|
+
function sendRequest(method, params) {
|
|
185
|
+
const active = popup;
|
|
186
|
+
if (!active || active.closed) return Promise.reject(disconnectedError());
|
|
187
|
+
const id = crypto.randomUUID();
|
|
188
|
+
const message = {
|
|
189
|
+
type: `${MESSAGE_PREFIX}request`,
|
|
190
|
+
v: PROTOCOL_VERSION,
|
|
191
|
+
id,
|
|
192
|
+
method,
|
|
193
|
+
...params === void 0 ? {} : { params }
|
|
194
|
+
};
|
|
195
|
+
return new Promise((resolve, reject) => {
|
|
196
|
+
pending.set(id, { resolve, reject });
|
|
197
|
+
active.postMessage(message, walletOrigin);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
function handleResponse(message) {
|
|
201
|
+
const request2 = pending.get(message.id);
|
|
202
|
+
if (!request2) return;
|
|
203
|
+
pending.delete(message.id);
|
|
204
|
+
if ("error" in message) {
|
|
205
|
+
request2.reject(new ProviderRpcError(message.error.code, message.error.message, message.error.data));
|
|
206
|
+
} else {
|
|
207
|
+
request2.resolve(message.result);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function handleEventMessage(message) {
|
|
211
|
+
if (message.event === "accountsChanged") {
|
|
212
|
+
accounts = [...message.data];
|
|
213
|
+
emit("accountsChanged", [...accounts]);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (message.event === "chainChanged") {
|
|
217
|
+
chainIdHex = message.data;
|
|
218
|
+
emit("chainChanged", chainIdHex);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
walletDisconnected = true;
|
|
222
|
+
emit("disconnect", new ProviderRpcError(message.data.code, message.data.message, message.data.data));
|
|
223
|
+
}
|
|
224
|
+
function onWindowMessage(event) {
|
|
225
|
+
if (event.origin !== walletOrigin) return;
|
|
226
|
+
if (popup === null || event.source !== popup) return;
|
|
227
|
+
const data = event.data;
|
|
228
|
+
if (isReadyMessage(data)) {
|
|
229
|
+
ready.resolve(void 0);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (isResponseMessage(data)) {
|
|
233
|
+
handleResponse(data);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (isEventMessage(data)) handleEventMessage(data);
|
|
237
|
+
}
|
|
238
|
+
if (typeof window !== "undefined") window.addEventListener("message", onWindowMessage);
|
|
239
|
+
function request({ method, params }) {
|
|
240
|
+
if (typeof window === "undefined") {
|
|
241
|
+
return Promise.reject(
|
|
242
|
+
new ProviderRpcError(
|
|
243
|
+
RpcErrorCode.Disconnected,
|
|
244
|
+
"The Assetera Wallet provider can only run in a browser."
|
|
245
|
+
)
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
if (!isSupportedMethod(method)) {
|
|
249
|
+
return Promise.reject(
|
|
250
|
+
new ProviderRpcError(
|
|
251
|
+
RpcErrorCode.UnsupportedMethod,
|
|
252
|
+
`The Assetera Wallet pop-up does not support the method "${method}".`
|
|
253
|
+
)
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
if (method === "eth_accounts") return Promise.resolve([...accounts]);
|
|
257
|
+
if (method === "eth_chainId") return Promise.resolve(currentChainId());
|
|
258
|
+
if (method === "eth_requestAccounts") {
|
|
259
|
+
const active2 = openPopup();
|
|
260
|
+
if (!active2) return Promise.reject(blockedError());
|
|
261
|
+
return ready.promise.then(() => sendRequest("eth_requestAccounts", params)).then((result) => {
|
|
262
|
+
accounts = Array.isArray(result) ? result : [];
|
|
263
|
+
emit("accountsChanged", [...accounts]);
|
|
264
|
+
emit("connect", { chainId: currentChainId() });
|
|
265
|
+
return [...accounts];
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
if (accounts.length === 0) {
|
|
269
|
+
return Promise.reject(
|
|
270
|
+
new ProviderRpcError(
|
|
271
|
+
RpcErrorCode.Unauthorized,
|
|
272
|
+
"Connect to the Assetera Wallet first (eth_requestAccounts)."
|
|
273
|
+
)
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
const active = openPopup();
|
|
277
|
+
if (!active) return Promise.reject(blockedError());
|
|
278
|
+
if (SIGNING_METHODS.has(method)) active.focus();
|
|
279
|
+
return ready.promise.then(() => sendRequest(method, params));
|
|
280
|
+
}
|
|
281
|
+
function disconnect() {
|
|
282
|
+
const active = popup;
|
|
283
|
+
if (active && !active.closed) {
|
|
284
|
+
const message = {
|
|
285
|
+
type: `${MESSAGE_PREFIX}disconnect`,
|
|
286
|
+
v: PROTOCOL_VERSION
|
|
287
|
+
};
|
|
288
|
+
active.postMessage(message, walletOrigin);
|
|
289
|
+
active.close();
|
|
290
|
+
}
|
|
291
|
+
stopClosePolling();
|
|
292
|
+
popup = null;
|
|
293
|
+
const closedReady = ready;
|
|
294
|
+
ready = createDeferred();
|
|
295
|
+
closedReady.reject(disconnectedError("Disconnected from the Assetera Wallet."));
|
|
296
|
+
rejectAllPending(disconnectedError("Disconnected from the Assetera Wallet."));
|
|
297
|
+
accounts = [];
|
|
298
|
+
chainIdHex = null;
|
|
299
|
+
walletDisconnected = false;
|
|
300
|
+
emit("disconnect", disconnectedError("Disconnected from the Assetera Wallet."));
|
|
301
|
+
}
|
|
302
|
+
function on(event, listener) {
|
|
303
|
+
addListener(event, listener);
|
|
304
|
+
}
|
|
305
|
+
function removeListener(event, listener) {
|
|
306
|
+
removeEventListener(event, listener);
|
|
307
|
+
}
|
|
308
|
+
return { request, on, removeListener, disconnect };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/wagmi.ts
|
|
312
|
+
var ASSETERA_WALLET_ID = "assetera-wallet";
|
|
313
|
+
var ASSETERA_WALLET_NAME = "Assetera Wallet";
|
|
314
|
+
var ASSETERA_WALLET_TYPE = "asseteraWallet";
|
|
315
|
+
function asseteraWallet(parameters) {
|
|
316
|
+
let provider;
|
|
317
|
+
let accountsChanged;
|
|
318
|
+
let chainChanged;
|
|
319
|
+
let disconnectHandler;
|
|
320
|
+
function removeProviderListeners(activeProvider) {
|
|
321
|
+
if (accountsChanged) {
|
|
322
|
+
activeProvider.removeListener("accountsChanged", accountsChanged);
|
|
323
|
+
accountsChanged = void 0;
|
|
324
|
+
}
|
|
325
|
+
if (chainChanged) {
|
|
326
|
+
activeProvider.removeListener("chainChanged", chainChanged);
|
|
327
|
+
chainChanged = void 0;
|
|
328
|
+
}
|
|
329
|
+
if (disconnectHandler) {
|
|
330
|
+
activeProvider.removeListener("disconnect", disconnectHandler);
|
|
331
|
+
disconnectHandler = void 0;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return core.createConnector((config) => ({
|
|
335
|
+
id: ASSETERA_WALLET_ID,
|
|
336
|
+
name: ASSETERA_WALLET_NAME,
|
|
337
|
+
type: ASSETERA_WALLET_TYPE,
|
|
338
|
+
icon: ASSETERA_WALLET_ICON,
|
|
339
|
+
async connect({ chainId, withCapabilities } = {}) {
|
|
340
|
+
const activeProvider = await this.getProvider();
|
|
341
|
+
const requested = await activeProvider.request({
|
|
342
|
+
method: "eth_requestAccounts"
|
|
343
|
+
});
|
|
344
|
+
const addresses = requested.map((account) => viem.getAddress(account));
|
|
345
|
+
if (!accountsChanged) {
|
|
346
|
+
accountsChanged = this.onAccountsChanged.bind(this);
|
|
347
|
+
activeProvider.on("accountsChanged", accountsChanged);
|
|
348
|
+
}
|
|
349
|
+
if (!chainChanged) {
|
|
350
|
+
chainChanged = this.onChainChanged.bind(this);
|
|
351
|
+
activeProvider.on("chainChanged", chainChanged);
|
|
352
|
+
}
|
|
353
|
+
if (!disconnectHandler) {
|
|
354
|
+
disconnectHandler = this.onDisconnect.bind(this);
|
|
355
|
+
activeProvider.on("disconnect", disconnectHandler);
|
|
356
|
+
}
|
|
357
|
+
let currentChainId = await this.getChainId();
|
|
358
|
+
if (chainId && currentChainId !== chainId) {
|
|
359
|
+
const chain = await this.switchChain({ chainId }).catch((error) => {
|
|
360
|
+
if (error?.code === viem.UserRejectedRequestError.code) throw error;
|
|
361
|
+
return { id: currentChainId };
|
|
362
|
+
});
|
|
363
|
+
currentChainId = chain?.id ?? currentChainId;
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
accounts: withCapabilities ? addresses.map((address) => ({ address, capabilities: {} })) : addresses,
|
|
367
|
+
chainId: currentChainId
|
|
368
|
+
};
|
|
369
|
+
},
|
|
370
|
+
async disconnect() {
|
|
371
|
+
if (!provider) return;
|
|
372
|
+
removeProviderListeners(provider);
|
|
373
|
+
provider.disconnect();
|
|
374
|
+
},
|
|
375
|
+
async getAccounts() {
|
|
376
|
+
const activeProvider = await this.getProvider();
|
|
377
|
+
const requested = await activeProvider.request({ method: "eth_accounts" });
|
|
378
|
+
return requested.map((account) => viem.getAddress(account));
|
|
379
|
+
},
|
|
380
|
+
async getChainId() {
|
|
381
|
+
const activeProvider = await this.getProvider();
|
|
382
|
+
return Number(await activeProvider.request({ method: "eth_chainId" }));
|
|
383
|
+
},
|
|
384
|
+
async getProvider() {
|
|
385
|
+
if (!provider) {
|
|
386
|
+
provider = createAsseteraWalletProvider({
|
|
387
|
+
walletUrl: parameters.walletUrl,
|
|
388
|
+
defaultChainId: config.chains[0].id
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
return provider;
|
|
392
|
+
},
|
|
393
|
+
/**
|
|
394
|
+
* Always `false`: opening the pop-up requires a user click, so there is nothing to reconnect to on page
|
|
395
|
+
* load. Returning `true` would make wagmi attempt an automatic reconnect that the browser blocks; the
|
|
396
|
+
* partner app must drive `connect()` from a click instead.
|
|
397
|
+
*/
|
|
398
|
+
async isAuthorized() {
|
|
399
|
+
return false;
|
|
400
|
+
},
|
|
401
|
+
async switchChain({ chainId }) {
|
|
402
|
+
const chain = config.chains.find((candidate) => candidate.id === chainId);
|
|
403
|
+
if (!chain) throw new core.ChainNotConfiguredError();
|
|
404
|
+
const activeProvider = await this.getProvider();
|
|
405
|
+
await activeProvider.request({
|
|
406
|
+
method: "wallet_switchEthereumChain",
|
|
407
|
+
params: [{ chainId: viem.numberToHex(chainId) }]
|
|
408
|
+
});
|
|
409
|
+
this.onChainChanged(viem.numberToHex(chainId));
|
|
410
|
+
return chain;
|
|
411
|
+
},
|
|
412
|
+
onAccountsChanged(accounts) {
|
|
413
|
+
if (accounts.length === 0) this.onDisconnect();
|
|
414
|
+
else
|
|
415
|
+
config.emitter.emit("change", {
|
|
416
|
+
accounts: accounts.map((account) => viem.getAddress(account))
|
|
417
|
+
});
|
|
418
|
+
},
|
|
419
|
+
onChainChanged(chain) {
|
|
420
|
+
config.emitter.emit("change", { chainId: Number(chain) });
|
|
421
|
+
},
|
|
422
|
+
onDisconnect() {
|
|
423
|
+
config.emitter.emit("disconnect");
|
|
424
|
+
if (provider) removeProviderListeners(provider);
|
|
425
|
+
}
|
|
426
|
+
}));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// src/rainbowkit.ts
|
|
430
|
+
function asseteraRainbowWallet(options) {
|
|
431
|
+
return () => ({
|
|
432
|
+
id: ASSETERA_WALLET_ID,
|
|
433
|
+
name: ASSETERA_WALLET_NAME,
|
|
434
|
+
iconUrl: ASSETERA_WALLET_ICON,
|
|
435
|
+
iconBackground: "#1a1a2e",
|
|
436
|
+
installed: true,
|
|
437
|
+
createConnector: (walletDetails) => core.createConnector((config) => ({
|
|
438
|
+
...asseteraWallet({ walletUrl: options.walletUrl })(config),
|
|
439
|
+
...walletDetails
|
|
440
|
+
}))
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
exports.asseteraRainbowWallet = asseteraRainbowWallet;
|
|
445
|
+
//# sourceMappingURL=rainbowkit.cjs.map
|
|
446
|
+
//# sourceMappingURL=rainbowkit.cjs.map
|