@hot-labs/kit 1.0.33
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/.eslintrc.cjs +11 -0
- package/.github/workflows/deploy-example.yml +55 -0
- package/.github/workflows/release.yml +74 -0
- package/.prettierrc +4 -0
- package/.prototools +2 -0
- package/.vscode/settings.json +3 -0
- package/CHANGELOG.md +1 -0
- package/README.md +67 -0
- package/build/GoogleConnector.d.ts +20 -0
- package/build/GoogleConnector.js +76 -0
- package/build/GoogleConnector.js.map +1 -0
- package/build/HotConnector.d.ts +91 -0
- package/build/HotConnector.js +285 -0
- package/build/HotConnector.js.map +1 -0
- package/build/OmniConnector.d.ts +95 -0
- package/build/OmniConnector.js +123 -0
- package/build/OmniConnector.js.map +1 -0
- package/build/OmniWallet.d.ts +57 -0
- package/build/OmniWallet.js +56 -0
- package/build/OmniWallet.js.map +1 -0
- package/build/cosmos/connector.d.ts +53 -0
- package/build/cosmos/connector.js +207 -0
- package/build/cosmos/connector.js.map +1 -0
- package/build/cosmos/wallet.d.ts +28 -0
- package/build/cosmos/wallet.js +59 -0
- package/build/cosmos/wallet.js.map +1 -0
- package/build/events.d.ts +42 -0
- package/build/events.js +64 -0
- package/build/events.js.map +1 -0
- package/build/evm/abi.d.ts +17 -0
- package/build/evm/abi.js +38 -0
- package/build/evm/abi.js.map +1 -0
- package/build/evm/connector.d.ts +35 -0
- package/build/evm/connector.js +124 -0
- package/build/evm/connector.js.map +1 -0
- package/build/evm/wallet.d.ts +47 -0
- package/build/evm/wallet.js +136 -0
- package/build/evm/wallet.js.map +1 -0
- package/build/exchange.d.ts +63 -0
- package/build/exchange.js +384 -0
- package/build/exchange.js.map +1 -0
- package/build/hot-wallet/evm.d.ts +1 -0
- package/build/hot-wallet/evm.js +33 -0
- package/build/hot-wallet/evm.js.map +1 -0
- package/build/hot-wallet/hot.d.ts +3 -0
- package/build/hot-wallet/hot.js +40 -0
- package/build/hot-wallet/hot.js.map +1 -0
- package/build/hot-wallet/index.d.ts +4 -0
- package/build/hot-wallet/index.js +5 -0
- package/build/hot-wallet/index.js.map +1 -0
- package/build/hot-wallet/solana/account.d.ts +11 -0
- package/build/hot-wallet/solana/account.js +42 -0
- package/build/hot-wallet/solana/account.js.map +1 -0
- package/build/hot-wallet/solana/index.d.ts +1 -0
- package/build/hot-wallet/solana/index.js +85 -0
- package/build/hot-wallet/solana/index.js.map +1 -0
- package/build/hot-wallet/solana/register.d.ts +2 -0
- package/build/hot-wallet/solana/register.js +41 -0
- package/build/hot-wallet/solana/register.js.map +1 -0
- package/build/hot-wallet/solana/solana-wallet.d.ts +34 -0
- package/build/hot-wallet/solana/solana-wallet.js +223 -0
- package/build/hot-wallet/solana/solana-wallet.js.map +1 -0
- package/build/hot-wallet/solana/utils.d.ts +32 -0
- package/build/hot-wallet/solana/utils.js +36 -0
- package/build/hot-wallet/solana/utils.js.map +1 -0
- package/build/hot-wallet/stellar.d.ts +38 -0
- package/build/hot-wallet/stellar.js +32 -0
- package/build/hot-wallet/stellar.js.map +1 -0
- package/build/hot-wallet/ton.d.ts +1 -0
- package/build/hot-wallet/ton.js +49 -0
- package/build/hot-wallet/ton.js.map +1 -0
- package/build/hot-wallet/wallet.d.ts +1 -0
- package/build/hot-wallet/wallet.js +40 -0
- package/build/hot-wallet/wallet.js.map +1 -0
- package/build/index.d.ts +24 -0
- package/build/index.js +25 -0
- package/build/index.js.map +1 -0
- package/build/near/connector.d.ts +28 -0
- package/build/near/connector.js +56 -0
- package/build/near/connector.js.map +1 -0
- package/build/near/wallet.d.ts +62 -0
- package/build/near/wallet.js +233 -0
- package/build/near/wallet.js.map +1 -0
- package/build/omni/Intents.d.ts +93 -0
- package/build/omni/Intents.js +395 -0
- package/build/omni/Intents.js.map +1 -0
- package/build/omni/bridge.d.ts +3 -0
- package/build/omni/bridge.js +34 -0
- package/build/omni/bridge.js.map +1 -0
- package/build/omni/config.d.ts +99 -0
- package/build/omni/config.js +126 -0
- package/build/omni/config.js.map +1 -0
- package/build/omni/defaultTokens.d.ts +17 -0
- package/build/omni/defaultTokens.js +1079 -0
- package/build/omni/defaultTokens.js.map +1 -0
- package/build/omni/index.d.ts +8 -0
- package/build/omni/index.js +9 -0
- package/build/omni/index.js.map +1 -0
- package/build/omni/nearRpc.d.ts +24 -0
- package/build/omni/nearRpc.js +167 -0
- package/build/omni/nearRpc.js.map +1 -0
- package/build/omni/recipient.d.ts +10 -0
- package/build/omni/recipient.js +40 -0
- package/build/omni/recipient.js.map +1 -0
- package/build/omni/token.d.ts +36 -0
- package/build/omni/token.js +136 -0
- package/build/omni/token.js.map +1 -0
- package/build/omni/tokens.d.ts +14 -0
- package/build/omni/tokens.js +57 -0
- package/build/omni/tokens.js.map +1 -0
- package/build/omni/types.d.ts +41 -0
- package/build/omni/types.js +2 -0
- package/build/omni/types.js.map +1 -0
- package/build/omni/utils.d.ts +24 -0
- package/build/omni/utils.js +150 -0
- package/build/omni/utils.js.map +1 -0
- package/build/settings.d.ts +5 -0
- package/build/settings.js +6 -0
- package/build/settings.js.map +1 -0
- package/build/solana/connector.d.ts +31 -0
- package/build/solana/connector.js +138 -0
- package/build/solana/connector.js.map +1 -0
- package/build/solana/protocol.d.ts +25 -0
- package/build/solana/protocol.js +56 -0
- package/build/solana/protocol.js.map +1 -0
- package/build/solana/wallet.d.ts +47 -0
- package/build/solana/wallet.js +188 -0
- package/build/solana/wallet.js.map +1 -0
- package/build/solana/wallets.d.ts +102 -0
- package/build/solana/wallets.js +150 -0
- package/build/solana/wallets.js.map +1 -0
- package/build/stellar/connector.d.ts +25 -0
- package/build/stellar/connector.js +56 -0
- package/build/stellar/connector.js.map +1 -0
- package/build/stellar/wallet.d.ts +70 -0
- package/build/stellar/wallet.js +225 -0
- package/build/stellar/wallet.js.map +1 -0
- package/build/storage.d.ts +10 -0
- package/build/storage.js +12 -0
- package/build/storage.js.map +1 -0
- package/build/ton/connector.d.ts +25 -0
- package/build/ton/connector.js +119 -0
- package/build/ton/connector.js.map +1 -0
- package/build/ton/utils.d.ts +45 -0
- package/build/ton/utils.js +64 -0
- package/build/ton/utils.js.map +1 -0
- package/build/ton/wallet.d.ts +70 -0
- package/build/ton/wallet.js +154 -0
- package/build/ton/wallet.js.map +1 -0
- package/build/ui/Popup.d.ts +10 -0
- package/build/ui/Popup.js +38 -0
- package/build/ui/Popup.js.map +1 -0
- package/build/ui/connect/AuthPopup.d.ts +2 -0
- package/build/ui/connect/AuthPopup.js +48 -0
- package/build/ui/connect/AuthPopup.js.map +1 -0
- package/build/ui/connect/ConnectWallet.d.ts +9 -0
- package/build/ui/connect/ConnectWallet.js +22 -0
- package/build/ui/connect/ConnectWallet.js.map +1 -0
- package/build/ui/connect/LogoutPopup.d.ts +10 -0
- package/build/ui/connect/LogoutPopup.js +8 -0
- package/build/ui/connect/LogoutPopup.js.map +1 -0
- package/build/ui/connect/WCPopup.d.ts +13 -0
- package/build/ui/connect/WCPopup.js +81 -0
- package/build/ui/connect/WCPopup.js.map +1 -0
- package/build/ui/connect/WCRequest.d.ts +9 -0
- package/build/ui/connect/WCRequest.js +13 -0
- package/build/ui/connect/WCRequest.js.map +1 -0
- package/build/ui/connect/WalletPicker.d.ts +11 -0
- package/build/ui/connect/WalletPicker.js +48 -0
- package/build/ui/connect/WalletPicker.js.map +1 -0
- package/build/ui/icons/arrow-right.d.ts +1 -0
- package/build/ui/icons/arrow-right.js +5 -0
- package/build/ui/icons/arrow-right.js.map +1 -0
- package/build/ui/icons/exchange.d.ts +6 -0
- package/build/ui/icons/exchange.js +6 -0
- package/build/ui/icons/exchange.js.map +1 -0
- package/build/ui/icons/logout.d.ts +1 -0
- package/build/ui/icons/logout.js +3 -0
- package/build/ui/icons/logout.js.map +1 -0
- package/build/ui/icons/pending.d.ts +1 -0
- package/build/ui/icons/pending.js +5 -0
- package/build/ui/icons/pending.js.map +1 -0
- package/build/ui/icons/qr.d.ts +1 -0
- package/build/ui/icons/qr.js +5 -0
- package/build/ui/icons/qr.js.map +1 -0
- package/build/ui/icons/search.d.ts +1 -0
- package/build/ui/icons/search.js +5 -0
- package/build/ui/icons/search.js.map +1 -0
- package/build/ui/icons/switch.d.ts +1 -0
- package/build/ui/icons/switch.js +5 -0
- package/build/ui/icons/switch.js.map +1 -0
- package/build/ui/icons/wallet.d.ts +1 -0
- package/build/ui/icons/wallet.js +5 -0
- package/build/ui/icons/wallet.js.map +1 -0
- package/build/ui/payment/Bridge.d.ts +27 -0
- package/build/ui/payment/Bridge.js +340 -0
- package/build/ui/payment/Bridge.js.map +1 -0
- package/build/ui/payment/DepositQR.d.ts +9 -0
- package/build/ui/payment/DepositQR.js +56 -0
- package/build/ui/payment/DepositQR.js.map +1 -0
- package/build/ui/payment/Payment.d.ts +16 -0
- package/build/ui/payment/Payment.js +50 -0
- package/build/ui/payment/Payment.js.map +1 -0
- package/build/ui/payment/Profile.d.ts +7 -0
- package/build/ui/payment/Profile.js +88 -0
- package/build/ui/payment/Profile.js.map +1 -0
- package/build/ui/payment/SelectRecipient.d.ts +14 -0
- package/build/ui/payment/SelectRecipient.js +68 -0
- package/build/ui/payment/SelectRecipient.js.map +1 -0
- package/build/ui/payment/SelectSender.d.ts +13 -0
- package/build/ui/payment/SelectSender.js +23 -0
- package/build/ui/payment/SelectSender.js.map +1 -0
- package/build/ui/payment/SelectToken.d.ts +13 -0
- package/build/ui/payment/SelectToken.js +92 -0
- package/build/ui/payment/SelectToken.js.map +1 -0
- package/build/ui/payment/TokenCard.d.ts +23 -0
- package/build/ui/payment/TokenCard.js +50 -0
- package/build/ui/payment/TokenCard.js.map +1 -0
- package/build/ui/router.d.ts +37 -0
- package/build/ui/router.js +56 -0
- package/build/ui/router.js.map +1 -0
- package/build/ui/styles.d.ts +11 -0
- package/build/ui/styles.js +273 -0
- package/build/ui/styles.js.map +1 -0
- package/package.json +60 -0
- package/skill.md +989 -0
- package/src/GoogleConnector.ts +102 -0
- package/src/HotConnector.ts +344 -0
- package/src/OmniConnector.ts +161 -0
- package/src/OmniWallet.ts +94 -0
- package/src/cosmos/connector.ts +242 -0
- package/src/cosmos/wallet.ts +77 -0
- package/src/events.ts +66 -0
- package/src/evm/abi.ts +39 -0
- package/src/evm/connector.ts +139 -0
- package/src/evm/wallet.ts +156 -0
- package/src/exchange.ts +426 -0
- package/src/hot-wallet/evm.ts +38 -0
- package/src/hot-wallet/hot.ts +39 -0
- package/src/hot-wallet/index.ts +4 -0
- package/src/hot-wallet/solana/account.ts +52 -0
- package/src/hot-wallet/solana/index.ts +98 -0
- package/src/hot-wallet/solana/register.ts +48 -0
- package/src/hot-wallet/solana/solana-wallet.ts +280 -0
- package/src/hot-wallet/solana/utils.ts +56 -0
- package/src/hot-wallet/stellar.ts +39 -0
- package/src/hot-wallet/ton.ts +56 -0
- package/src/hot-wallet/wallet.ts +44 -0
- package/src/index.ts +30 -0
- package/src/near/connector.ts +71 -0
- package/src/near/wallet.ts +255 -0
- package/src/omni/Intents.ts +454 -0
- package/src/omni/bridge.ts +38 -0
- package/src/omni/config.ts +130 -0
- package/src/omni/defaultTokens.ts +1078 -0
- package/src/omni/index.ts +8 -0
- package/src/omni/nearRpc.ts +187 -0
- package/src/omni/recipient.ts +41 -0
- package/src/omni/token.ts +125 -0
- package/src/omni/tokens.ts +68 -0
- package/src/omni/types.ts +46 -0
- package/src/omni/utils.ts +163 -0
- package/src/settings.ts +5 -0
- package/src/solana/connector.ts +151 -0
- package/src/solana/protocol.ts +66 -0
- package/src/solana/wallet.ts +230 -0
- package/src/solana/wallets.ts +243 -0
- package/src/stellar/connector.ts +69 -0
- package/src/stellar/wallet.ts +267 -0
- package/src/storage.ts +19 -0
- package/src/ton/connector.ts +138 -0
- package/src/ton/utils.ts +73 -0
- package/src/ton/wallet.ts +178 -0
- package/src/ui/Popup.tsx +62 -0
- package/src/ui/connect/AuthPopup.tsx +78 -0
- package/src/ui/connect/ConnectWallet.tsx +63 -0
- package/src/ui/connect/LogoutPopup.tsx +20 -0
- package/src/ui/connect/WCPopup.tsx +122 -0
- package/src/ui/connect/WCRequest.tsx +28 -0
- package/src/ui/connect/WalletPicker.tsx +92 -0
- package/src/ui/icons/arrow-right.tsx +8 -0
- package/src/ui/icons/exchange.tsx +17 -0
- package/src/ui/icons/logout.tsx +18 -0
- package/src/ui/icons/pending.tsx +18 -0
- package/src/ui/icons/qr.tsx +12 -0
- package/src/ui/icons/search.tsx +18 -0
- package/src/ui/icons/switch.tsx +10 -0
- package/src/ui/icons/wallet.tsx +18 -0
- package/src/ui/payment/Bridge.tsx +582 -0
- package/src/ui/payment/DepositQR.tsx +88 -0
- package/src/ui/payment/Payment.tsx +78 -0
- package/src/ui/payment/Profile.tsx +140 -0
- package/src/ui/payment/SelectRecipient.tsx +111 -0
- package/src/ui/payment/SelectSender.tsx +60 -0
- package/src/ui/payment/SelectToken.tsx +134 -0
- package/src/ui/payment/TokenCard.tsx +83 -0
- package/src/ui/router.tsx +92 -0
- package/src/ui/styles.ts +284 -0
- package/tsconfig.json +22 -0
- package/vite.config.ts +17 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { Wallet } from "@wallet-standard/base";
|
|
2
|
+
import { Transaction, PublicKey, VersionedTransaction, Connection } from "@solana/web3.js";
|
|
3
|
+
import { base58 } from "@scure/base";
|
|
4
|
+
import { runInAction } from "mobx";
|
|
5
|
+
|
|
6
|
+
import { ConnectorType, OmniConnector, OmniConnectorOptions, WC_ICON } from "../OmniConnector";
|
|
7
|
+
import { HotConnector } from "../HotConnector";
|
|
8
|
+
import { OmniWallet } from "../OmniWallet";
|
|
9
|
+
import { isInjected } from "../hot-wallet/hot";
|
|
10
|
+
import { WalletType } from "../omni/config";
|
|
11
|
+
|
|
12
|
+
import SolanaProtocolWallet from "./protocol";
|
|
13
|
+
import { getWallets } from "./wallets";
|
|
14
|
+
import SolanaWallet from "./wallet";
|
|
15
|
+
|
|
16
|
+
const wallets = getWallets();
|
|
17
|
+
|
|
18
|
+
class SolanaConnector extends OmniConnector<SolanaWallet, { wallet: Wallet }> {
|
|
19
|
+
type = ConnectorType.WALLET;
|
|
20
|
+
walletTypes = [WalletType.SOLANA, WalletType.OMNI];
|
|
21
|
+
|
|
22
|
+
icon = "https://storage.herewallet.app/upload/8700f33153ad813e133e5bf9b791b5ecbeea66edca6b8d17aeccb8048eb29ef7.png";
|
|
23
|
+
name = "Solana Wallet";
|
|
24
|
+
id = "solana";
|
|
25
|
+
|
|
26
|
+
constructor(wibe3: HotConnector, readonly args?: OmniConnectorOptions) {
|
|
27
|
+
super(wibe3, args);
|
|
28
|
+
|
|
29
|
+
wallets.get().forEach((t) => {
|
|
30
|
+
if (this.options.find((w) => w.name === t.name)) return;
|
|
31
|
+
this.options.push({ type: "extension", wallet: t, name: t.name, icon: t.icon, id: t.name, download: t.url });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
this.getConnectedWallet().then(async ({ id }) => {
|
|
35
|
+
try {
|
|
36
|
+
const wallet = this.options.find((w) => w.id === id);
|
|
37
|
+
if (!wallet) return;
|
|
38
|
+
const protocolWallet = await SolanaProtocolWallet.connect(wallet.wallet, { silent: true });
|
|
39
|
+
this.setWallet(new SolanaWallet(this, protocolWallet));
|
|
40
|
+
} catch {
|
|
41
|
+
this.removeStorage();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
wallets.on("register", async (wallet: Wallet & { url?: string }) => {
|
|
46
|
+
if (this.options.find((w) => w.id === wallet.name)) return;
|
|
47
|
+
runInAction(() => {
|
|
48
|
+
this.options.push({
|
|
49
|
+
wallet: wallet,
|
|
50
|
+
name: wallet.name,
|
|
51
|
+
icon: wallet.icon,
|
|
52
|
+
id: wallet.name,
|
|
53
|
+
download: wallet.url,
|
|
54
|
+
type: "extension",
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const connected = await this.getConnectedWallet();
|
|
60
|
+
if (connected !== wallet.name) return;
|
|
61
|
+
const protocolWallet = await SolanaProtocolWallet.connect(wallet, { silent: true });
|
|
62
|
+
this.setWallet(new SolanaWallet(this, protocolWallet));
|
|
63
|
+
} catch {
|
|
64
|
+
this.removeStorage();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
wallets.on("unregister", (wallet) => {
|
|
69
|
+
this.options = this.options.filter((w) => w.id !== wallet.name);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
this.initWalletConnect().then(async (wc) => {
|
|
73
|
+
this.options.unshift({ type: "external", download: "https://www.walletconnect.com/get", wallet: {} as Wallet, name: "WalletConnect", id: "walletconnect", icon: WC_ICON });
|
|
74
|
+
const selected = await this.getConnectedWallet();
|
|
75
|
+
if (selected.type !== "walletconnect") return;
|
|
76
|
+
this.setupWalletConnect();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async setupWalletConnect(): Promise<SolanaWallet> {
|
|
81
|
+
const wc = await this.wc;
|
|
82
|
+
if (!wc) throw new Error("WalletConnect not found");
|
|
83
|
+
|
|
84
|
+
const account = wc.session?.namespaces.solana?.accounts[0]?.split(":")[2];
|
|
85
|
+
if (!account) throw new Error("Account not found");
|
|
86
|
+
|
|
87
|
+
this.setStorage({ type: "walletconnect" });
|
|
88
|
+
return this.setWallet(
|
|
89
|
+
new SolanaWallet(this, {
|
|
90
|
+
address: account,
|
|
91
|
+
sendTransaction: async (tx: Transaction | VersionedTransaction, connection: Connection, options?: any) => {
|
|
92
|
+
const transaction = Buffer.from(tx.serialize()).toString("base64");
|
|
93
|
+
const { signature } = await this.requestWalletConnect<{ signature: string }>({
|
|
94
|
+
request: { params: { transaction, options }, method: "solana_signTransaction" },
|
|
95
|
+
});
|
|
96
|
+
tx.addSignature(new PublicKey(account), Buffer.from(base58.decode(signature)));
|
|
97
|
+
return await connection.sendRawTransaction(tx.serialize(), options);
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
signMessage: async (msg: string) => {
|
|
101
|
+
const message = base58.encode(Buffer.from(msg, "utf8"));
|
|
102
|
+
const { signature } = await this.requestWalletConnect<{ signature: string }>({
|
|
103
|
+
request: { method: "solana_signMessage", params: { message, pubkey: account } },
|
|
104
|
+
});
|
|
105
|
+
return base58.decode(signature);
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
disconnect: () => this.disconnectWalletConnect(),
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async createWallet(address: string): Promise<OmniWallet> {
|
|
114
|
+
return new SolanaWallet(this, { address });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async getConnectedWallet() {
|
|
118
|
+
if (isInjected()) return { type: "wallet", id: "HOT Wallet" };
|
|
119
|
+
return this.getStorage();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async connect(id: string) {
|
|
123
|
+
if (id === "walletconnect") {
|
|
124
|
+
return await this.connectWalletConnect({
|
|
125
|
+
onConnect: () => this.setupWalletConnect(),
|
|
126
|
+
namespaces: {
|
|
127
|
+
solana: {
|
|
128
|
+
methods: ["solana_signTransaction", "solana_signMessage"],
|
|
129
|
+
chains: ["solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", "solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ"],
|
|
130
|
+
events: [],
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
this.disconnectWalletConnect();
|
|
137
|
+
const wallet = this.options.find((t) => t.id === id);
|
|
138
|
+
if (!wallet) throw new Error("Wallet not found");
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
this.setStorage({ type: "wallet", id });
|
|
142
|
+
const protocolWallet = await SolanaProtocolWallet.connect(wallet.wallet, { silent: false });
|
|
143
|
+
return this.setWallet(new SolanaWallet(this, protocolWallet));
|
|
144
|
+
} catch (e) {
|
|
145
|
+
this.removeStorage();
|
|
146
|
+
throw e;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export default SolanaConnector;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Connection, Transaction, VersionedTransaction } from "@solana/web3.js";
|
|
2
|
+
import { SolanaSignAndSendTransactionMethod, SolanaSignMessageMethod, SolanaSignTransactionMethod } from "@solana/wallet-standard-features";
|
|
3
|
+
import type { Wallet } from "@wallet-standard/base";
|
|
4
|
+
import { base58 } from "@scure/base";
|
|
5
|
+
|
|
6
|
+
export interface ISolanaProtocolWallet {
|
|
7
|
+
address: string;
|
|
8
|
+
sendTransaction?: (transaction: Transaction | VersionedTransaction, connection: Connection, options?: any) => Promise<string>;
|
|
9
|
+
signMessage?: (message: string) => Promise<Uint8Array>;
|
|
10
|
+
disconnect?: (data?: { silent?: boolean }) => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class SolanaProtocolWallet implements ISolanaProtocolWallet {
|
|
14
|
+
constructor(readonly wallet: Wallet, readonly address: string) {}
|
|
15
|
+
|
|
16
|
+
static async connect(wallet: Wallet, { silent = false }: { silent?: boolean } = {}): Promise<ISolanaProtocolWallet> {
|
|
17
|
+
const a = new SolanaProtocolWallet(wallet, "");
|
|
18
|
+
const account = await a.getAccount({ silent });
|
|
19
|
+
return new SolanaProtocolWallet(wallet, account.address);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async getAccount({ silent = false }: { silent?: boolean } = {}) {
|
|
23
|
+
let accounts = this.wallet.accounts || [];
|
|
24
|
+
|
|
25
|
+
if (!accounts.length) {
|
|
26
|
+
const connect = (this.wallet.features as any)["standard:connect"]?.connect;
|
|
27
|
+
if (!connect) throw new Error("Wallet does not support standard:connect");
|
|
28
|
+
const { accounts: connectedAccounts } = await connect({ silent });
|
|
29
|
+
accounts = connectedAccounts || [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!accounts.length) throw new Error("No account found");
|
|
33
|
+
return accounts[0];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async disconnect() {
|
|
37
|
+
const disconnect = (this.wallet.features as any)["standard:disconnect"]?.disconnect as (() => Promise<void>) | undefined;
|
|
38
|
+
if (disconnect) await disconnect();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async sendTransaction(transaction: Transaction | VersionedTransaction, connection: Connection, options?: any): Promise<string> {
|
|
42
|
+
const account = await this.getAccount();
|
|
43
|
+
const features = this.wallet.features as any;
|
|
44
|
+
const signTx = features["solana:signTransaction"]?.signTransaction as SolanaSignTransactionMethod;
|
|
45
|
+
const [signed] = await signTx({ account, chain: account.chains[0], transaction: transaction.serialize() });
|
|
46
|
+
const signedTx = signed.signedTransaction as Transaction | VersionedTransaction | Uint8Array;
|
|
47
|
+
const raw = signedTx instanceof Uint8Array ? signedTx : (signedTx as any).serialize();
|
|
48
|
+
const sig = await connection.sendRawTransaction(raw as Uint8Array, options as any);
|
|
49
|
+
return sig;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async signMessage(message: string) {
|
|
53
|
+
const account = await this.getAccount();
|
|
54
|
+
const features = this.wallet.features as any;
|
|
55
|
+
const signMessageFeature = features["solana:signMessage"]?.signMessage as SolanaSignMessageMethod;
|
|
56
|
+
|
|
57
|
+
if (!signMessageFeature) throw new Error("Wallet does not support solana:signMessage");
|
|
58
|
+
const [result] = await signMessageFeature({ account, message: new TextEncoder().encode(message) });
|
|
59
|
+
|
|
60
|
+
if (result.signature) return result.signature;
|
|
61
|
+
if (Array.isArray(result) && result[0]?.signature) return result[0].signature as Uint8Array;
|
|
62
|
+
throw new Error("Unexpected signMessage result");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export default SolanaProtocolWallet;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { Connection, TransactionInstruction, VersionedTransaction } from "@solana/web3.js";
|
|
2
|
+
import { ComputeBudgetProgram, PublicKey, SystemProgram, TransactionMessage } from "@solana/web3.js";
|
|
3
|
+
import { base64, base58, hex } from "@scure/base";
|
|
4
|
+
import {
|
|
5
|
+
TOKEN_PROGRAM_ID,
|
|
6
|
+
TOKEN_2022_PROGRAM_ID,
|
|
7
|
+
getMinimumBalanceForRentExemptAccount,
|
|
8
|
+
createAssociatedTokenAccountInstruction,
|
|
9
|
+
createTransferInstruction,
|
|
10
|
+
getAccount,
|
|
11
|
+
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
12
|
+
getAssociatedTokenAddressSync,
|
|
13
|
+
createTransferCheckedInstruction,
|
|
14
|
+
} from "@solana/spl-token";
|
|
15
|
+
|
|
16
|
+
import { Network, WalletType } from "../omni/config";
|
|
17
|
+
import { OmniConnector } from "../OmniConnector";
|
|
18
|
+
import { OmniWallet } from "../OmniWallet";
|
|
19
|
+
|
|
20
|
+
import { Token } from "../omni/token";
|
|
21
|
+
import { formatter } from "../omni/utils";
|
|
22
|
+
import { ReviewFee } from "../omni/bridge";
|
|
23
|
+
|
|
24
|
+
import { ISolanaProtocolWallet } from "./protocol";
|
|
25
|
+
|
|
26
|
+
const connection = new Connection("https://api0.herewallet.app/api/v1/evm/rpc/1001");
|
|
27
|
+
|
|
28
|
+
class SolanaWallet extends OmniWallet {
|
|
29
|
+
readonly type = WalletType.SOLANA;
|
|
30
|
+
|
|
31
|
+
constructor(readonly connector: OmniConnector, readonly wallet: ISolanaProtocolWallet) {
|
|
32
|
+
super(connector);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get address() {
|
|
36
|
+
return this.wallet.address;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get publicKey() {
|
|
40
|
+
return this.wallet.address;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get omniAddress() {
|
|
44
|
+
return hex.encode(base58.decode(this.address)).toLowerCase();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async fetchBalance(_: number, address: string) {
|
|
48
|
+
if (address === "native") {
|
|
49
|
+
const balance = await connection.getBalance(new PublicKey(this.address));
|
|
50
|
+
return BigInt(balance);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const ATA = getAssociatedTokenAddressSync(new PublicKey(address), new PublicKey(this.address));
|
|
54
|
+
const meta = await connection.getTokenAccountBalance(ATA);
|
|
55
|
+
return BigInt(meta.value.amount);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async disconnect() {
|
|
59
|
+
await this.wallet.disconnect?.();
|
|
60
|
+
super.disconnect();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async signIntentsWithAuth(domain: string, intents?: Record<string, any>[]) {
|
|
64
|
+
const seed = hex.encode(window.crypto.getRandomValues(new Uint8Array(32)));
|
|
65
|
+
const msgBuffer = new TextEncoder().encode(`${domain}_${seed}`);
|
|
66
|
+
const nonce = await window.crypto.subtle.digest("SHA-256", new Uint8Array(msgBuffer));
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
signed: await this.signIntents(intents || [], { nonce: new Uint8Array(nonce) }),
|
|
70
|
+
publicKey: `ed25519:${this.address}`,
|
|
71
|
+
chainId: WalletType.SOLANA,
|
|
72
|
+
address: this.address,
|
|
73
|
+
seed,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async buildTranferInstructions(token: Token, amount: bigint, receiver: string, fee: ReviewFee) {
|
|
78
|
+
const destination = new PublicKey(receiver);
|
|
79
|
+
const owner = new PublicKey(this.address);
|
|
80
|
+
|
|
81
|
+
const reserve = await connection.getMinimumBalanceForRentExemption(0);
|
|
82
|
+
let additionalFee = 0n;
|
|
83
|
+
|
|
84
|
+
if (token.address === "native") {
|
|
85
|
+
return {
|
|
86
|
+
reserve,
|
|
87
|
+
additionalFee,
|
|
88
|
+
instructions: [
|
|
89
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: Number(fee.priorityFee) }),
|
|
90
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: Number(fee.gasLimit) }),
|
|
91
|
+
SystemProgram.transfer({ fromPubkey: owner, toPubkey: destination, lamports: amount }),
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const mint = new PublicKey(token.address);
|
|
97
|
+
const mintAccount = await connection.getAccountInfo(mint);
|
|
98
|
+
const tokenProgramId = mintAccount?.owner.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID;
|
|
99
|
+
|
|
100
|
+
const tokenFrom = getAssociatedTokenAddressSync(mint, owner, false, tokenProgramId);
|
|
101
|
+
const tokenTo = getAssociatedTokenAddressSync(mint, destination, false, tokenProgramId);
|
|
102
|
+
|
|
103
|
+
const instructions: TransactionInstruction[] = [ComputeBudgetProgram.setComputeUnitPrice({ microLamports: Number(fee.baseFee) }), ComputeBudgetProgram.setComputeUnitLimit({ units: Number(fee.gasLimit) })];
|
|
104
|
+
|
|
105
|
+
const isRegistered = await getAccount(connection, tokenTo, "confirmed", tokenProgramId).catch(() => null);
|
|
106
|
+
if (isRegistered == null) {
|
|
107
|
+
const inst = createAssociatedTokenAccountInstruction(new PublicKey(this.address), tokenTo, destination, mint, tokenProgramId, ASSOCIATED_TOKEN_PROGRAM_ID);
|
|
108
|
+
instructions.push(inst);
|
|
109
|
+
additionalFee += BigInt(await getMinimumBalanceForRentExemptAccount(connection));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (tokenProgramId === TOKEN_2022_PROGRAM_ID) {
|
|
113
|
+
instructions.push(createTransferCheckedInstruction(tokenFrom, mint, tokenTo, owner, amount, token.decimals, [], tokenProgramId));
|
|
114
|
+
} else {
|
|
115
|
+
instructions.push(createTransferInstruction(tokenFrom, tokenTo, owner, amount, [], tokenProgramId));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return { instructions, additionalFee, reserve };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async transferFee(token: Token, receiver: string): Promise<ReviewFee> {
|
|
122
|
+
const { blockhash } = await connection.getLatestBlockhash();
|
|
123
|
+
const fee = new ReviewFee({ chain: Network.Solana, gasLimit: 1_400_000n, baseFee: 100n });
|
|
124
|
+
const { instructions, additionalFee, reserve } = await this.buildTranferInstructions(token, 1n, receiver, fee);
|
|
125
|
+
|
|
126
|
+
const msgForEstimate = new TransactionMessage({ payerKey: new PublicKey(this.address), recentBlockhash: blockhash, instructions }).compileToV0Message();
|
|
127
|
+
const tx = new VersionedTransaction(msgForEstimate);
|
|
128
|
+
|
|
129
|
+
const priorityFeeData = await this.getPriorityFeeEstimate({
|
|
130
|
+
options: { includeAllPriorityFeeLevels: true },
|
|
131
|
+
transaction: base58.encode(tx.serialize()),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (priorityFeeData?.priorityFeeLevels == null) throw "Failed to fetch gas";
|
|
135
|
+
const simulate = await connection.simulateTransaction(tx).catch(() => null);
|
|
136
|
+
const unitsConsumed = formatter.bigIntMax(BigInt(simulate?.value.unitsConsumed || 10_000n), 10_000n);
|
|
137
|
+
|
|
138
|
+
const msgFee = await connection.getFeeForMessage(msgForEstimate);
|
|
139
|
+
const medium = BigInt(priorityFeeData.priorityFeeLevels.medium);
|
|
140
|
+
const high = BigInt(priorityFeeData.priorityFeeLevels.high);
|
|
141
|
+
const veryHigh = BigInt(priorityFeeData.priorityFeeLevels.veryHigh);
|
|
142
|
+
const baseFee = BigInt(msgFee.value || 0);
|
|
143
|
+
|
|
144
|
+
return new ReviewFee({
|
|
145
|
+
chain: Network.Solana,
|
|
146
|
+
reserve: BigInt(reserve) + additionalFee,
|
|
147
|
+
gasLimit: unitsConsumed,
|
|
148
|
+
baseFee,
|
|
149
|
+
priorityFee: medium,
|
|
150
|
+
options: [
|
|
151
|
+
{ priorityFee: medium, baseFee },
|
|
152
|
+
{ priorityFee: high, baseFee },
|
|
153
|
+
{ priorityFee: veryHigh, baseFee },
|
|
154
|
+
],
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async getPriorityFeeEstimate(params: any): Promise<any> {
|
|
159
|
+
const response = await fetch("https://api0.herewallet.app/api/v1/evm/helius/staked", {
|
|
160
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: "helius-sdk", method: "getPriorityFeeEstimate", params: [params] }),
|
|
161
|
+
headers: { "Content-Type": "application/json" },
|
|
162
|
+
method: "POST",
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
if (!response.ok) throw "Server error";
|
|
166
|
+
const { result, error } = await response.json();
|
|
167
|
+
if (error) throw error.message;
|
|
168
|
+
if (result.error) throw result.error.message;
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async transfer(args: { token: Token; receiver: string; amount: bigint; comment?: string; gasFee: ReviewFee }): Promise<string> {
|
|
173
|
+
const { instructions } = await this.buildTranferInstructions(args.token, args.amount, args.receiver, args.gasFee);
|
|
174
|
+
return await this.sendTransaction(instructions);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async sendTransaction(instructions: TransactionInstruction[]): Promise<string> {
|
|
178
|
+
if (!this.wallet.sendTransaction) throw "not impl";
|
|
179
|
+
const { blockhash } = await connection.getLatestBlockhash();
|
|
180
|
+
const message = new TransactionMessage({ payerKey: new PublicKey(this.address), recentBlockhash: blockhash, instructions });
|
|
181
|
+
const transaction = new VersionedTransaction(message.compileToV0Message());
|
|
182
|
+
return await this.wallet.sendTransaction(transaction, connection, { preflightCommitment: "confirmed" });
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async fetchBalances(chain: number, whitelist: string[]): Promise<Record<string, bigint>> {
|
|
186
|
+
const native = await this.fetchBalance(chain, "native");
|
|
187
|
+
try {
|
|
188
|
+
const res = await fetch(`https://api0.herewallet.app/api/v1/user/balances/${chain}/${this.address}`, { body: JSON.stringify({ whitelist }), method: "POST" });
|
|
189
|
+
const { balances } = await res.json();
|
|
190
|
+
return { ...balances, native };
|
|
191
|
+
} catch {
|
|
192
|
+
const tokenAccounts = await connection.getParsedTokenAccountsByOwner(new PublicKey(this.address), { programId: TOKEN_PROGRAM_ID });
|
|
193
|
+
const balances = Object.fromEntries(
|
|
194
|
+
tokenAccounts.value.map((account) => {
|
|
195
|
+
const { mint, tokenAmount } = account.account.data.parsed.info;
|
|
196
|
+
return [mint, tokenAmount.amount];
|
|
197
|
+
})
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
return { ...balances, native };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async signMessage(message: string) {
|
|
205
|
+
if (!this.wallet.signMessage) throw "not impl";
|
|
206
|
+
return this.wallet.signMessage(message);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async signIntents(intents: Record<string, any>[], options?: { deadline?: number; nonce?: Uint8Array }): Promise<Record<string, any>> {
|
|
210
|
+
const nonce = new Uint8Array(options?.nonce || window.crypto.getRandomValues(new Uint8Array(32)));
|
|
211
|
+
|
|
212
|
+
const message = JSON.stringify({
|
|
213
|
+
deadline: options?.deadline ? new Date(options.deadline).toISOString() : "2100-01-01T00:00:00.000Z",
|
|
214
|
+
nonce: base64.encode(nonce),
|
|
215
|
+
verifying_contract: "intents.near",
|
|
216
|
+
signer_id: this.omniAddress,
|
|
217
|
+
intents: intents,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const signature = await this.signMessage(message);
|
|
221
|
+
return {
|
|
222
|
+
signature: `ed25519:${base58.encode(signature)}`,
|
|
223
|
+
public_key: `ed25519:${this.publicKey}`,
|
|
224
|
+
standard: "raw_ed25519",
|
|
225
|
+
payload: message,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export default SolanaWallet;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import type { DEPRECATED_WalletsCallback, DEPRECATED_WalletsWindow, Wallet, WalletEventsWindow, WindowAppReadyEvent, WindowAppReadyEventAPI } from "@wallet-standard/base";
|
|
2
|
+
|
|
3
|
+
let wallets: Wallets | undefined = undefined;
|
|
4
|
+
const registeredWalletsSet = new Set<Wallet>();
|
|
5
|
+
function addRegisteredWallet(wallet: Wallet) {
|
|
6
|
+
cachedWalletsArray = undefined;
|
|
7
|
+
registeredWalletsSet.add(wallet);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function removeRegisteredWallet(wallet: Wallet) {
|
|
11
|
+
cachedWalletsArray = undefined;
|
|
12
|
+
registeredWalletsSet.delete(wallet);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const listeners: { [E in WalletsEventNames]?: WalletsEventsListeners[E][] } = {};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get an API for {@link Wallets.get | getting}, {@link Wallets.on | listening for}, and
|
|
19
|
+
* {@link Wallets.register | registering} {@link "@wallet-standard/base".Wallet | Wallets}.
|
|
20
|
+
*
|
|
21
|
+
* When called for the first time --
|
|
22
|
+
*
|
|
23
|
+
* This dispatches a {@link "@wallet-standard/base".WindowAppReadyEvent} to notify each Wallet that the app is ready
|
|
24
|
+
* to register it.
|
|
25
|
+
*
|
|
26
|
+
* This also adds a listener for {@link "@wallet-standard/base".WindowRegisterWalletEvent} to listen for a notification
|
|
27
|
+
* from each Wallet that the Wallet is ready to be registered by the app.
|
|
28
|
+
*
|
|
29
|
+
* This combination of event dispatch and listener guarantees that each Wallet will be registered synchronously as soon
|
|
30
|
+
* as the app is ready whether the app loads before or after each Wallet.
|
|
31
|
+
*
|
|
32
|
+
* @return API for getting, listening for, and registering Wallets.
|
|
33
|
+
*
|
|
34
|
+
* @group App
|
|
35
|
+
*/
|
|
36
|
+
export function getWallets(): Wallets {
|
|
37
|
+
if (wallets) return wallets;
|
|
38
|
+
wallets = Object.freeze({ register, get, on });
|
|
39
|
+
if (typeof window === "undefined") return wallets;
|
|
40
|
+
|
|
41
|
+
const api = Object.freeze({ register });
|
|
42
|
+
try {
|
|
43
|
+
(window as WalletEventsWindow).addEventListener("wallet-standard:register-wallet", ({ detail: callback }) => callback(api));
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("wallet-standard:register-wallet event listener could not be added\n", error);
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
(window as WalletEventsWindow).dispatchEvent(new AppReadyEvent(api));
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error("wallet-standard:app-ready event could not be dispatched\n", error);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return wallets;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* API for {@link Wallets.get | getting}, {@link Wallets.on | listening for}, and
|
|
58
|
+
* {@link Wallets.register | registering} {@link "@wallet-standard/base".Wallet | Wallets}.
|
|
59
|
+
*
|
|
60
|
+
* @group App
|
|
61
|
+
*/
|
|
62
|
+
export interface Wallets {
|
|
63
|
+
/**
|
|
64
|
+
* Get all Wallets that have been registered.
|
|
65
|
+
*
|
|
66
|
+
* @return Registered Wallets.
|
|
67
|
+
*/
|
|
68
|
+
get(): readonly (Wallet & { url?: string })[];
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Add an event listener and subscribe to events for Wallets that are
|
|
72
|
+
* {@link WalletsEventsListeners.register | registered} and
|
|
73
|
+
* {@link WalletsEventsListeners.unregister | unregistered}.
|
|
74
|
+
*
|
|
75
|
+
* @param event Event type to listen for. {@link WalletsEventsListeners.register | `register`} and
|
|
76
|
+
* {@link WalletsEventsListeners.unregister | `unregister`} are the only event types.
|
|
77
|
+
* @param listener Function that will be called when an event of the type is emitted.
|
|
78
|
+
*
|
|
79
|
+
* @return
|
|
80
|
+
* `off` function which may be called to remove the event listener and unsubscribe from events.
|
|
81
|
+
*
|
|
82
|
+
* As with all event listeners, be careful to avoid memory leaks.
|
|
83
|
+
*/
|
|
84
|
+
on<E extends WalletsEventNames>(event: E, listener: WalletsEventsListeners[E]): () => void;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Register Wallets. This can be used to programmatically wrap non-standard wallets as Standard Wallets.
|
|
88
|
+
*
|
|
89
|
+
* Apps generally do not need to, and should not, call this.
|
|
90
|
+
*
|
|
91
|
+
* @param wallets Wallets to register.
|
|
92
|
+
*
|
|
93
|
+
* @return
|
|
94
|
+
* `unregister` function which may be called to programmatically unregister the registered Wallets.
|
|
95
|
+
*
|
|
96
|
+
* Apps generally do not need to, and should not, call this.
|
|
97
|
+
*/
|
|
98
|
+
register(...wallets: Wallet[]): () => void;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Types of event listeners of the {@link Wallets} API.
|
|
103
|
+
*
|
|
104
|
+
* @group App
|
|
105
|
+
*/
|
|
106
|
+
export interface WalletsEventsListeners {
|
|
107
|
+
/**
|
|
108
|
+
* Emitted when Wallets are registered.
|
|
109
|
+
*
|
|
110
|
+
* @param wallets Wallets that were registered.
|
|
111
|
+
*/
|
|
112
|
+
register(...wallets: Wallet[]): void;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Emitted when Wallets are unregistered.
|
|
116
|
+
*
|
|
117
|
+
* @param wallets Wallets that were unregistered.
|
|
118
|
+
*/
|
|
119
|
+
unregister(...wallets: Wallet[]): void;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Names of {@link WalletsEventsListeners} that can be listened for.
|
|
124
|
+
*
|
|
125
|
+
* @group App
|
|
126
|
+
*/
|
|
127
|
+
export type WalletsEventNames = keyof WalletsEventsListeners;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @deprecated Use {@link WalletsEventsListeners} instead.
|
|
131
|
+
*
|
|
132
|
+
* @group Deprecated
|
|
133
|
+
*/
|
|
134
|
+
export type WalletsEvents = WalletsEventsListeners;
|
|
135
|
+
|
|
136
|
+
function register(...wallets: Wallet[]): () => void {
|
|
137
|
+
// Filter out wallets that have already been registered.
|
|
138
|
+
// This prevents the same wallet from being registered twice, but it also prevents wallets from being
|
|
139
|
+
// unregistered by reusing a reference to the wallet to obtain the unregister function for it.
|
|
140
|
+
wallets = wallets.filter((wallet) => !registeredWalletsSet.has(wallet));
|
|
141
|
+
// If there are no new wallets to register, just return a no-op unregister function.
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
143
|
+
if (!wallets.length) return () => {};
|
|
144
|
+
|
|
145
|
+
wallets.forEach((wallet) => addRegisteredWallet(wallet));
|
|
146
|
+
listeners["register"]?.forEach((listener) => guard(() => listener(...wallets)));
|
|
147
|
+
// Return a function that unregisters the registered wallets.
|
|
148
|
+
return function unregister(): void {
|
|
149
|
+
wallets.forEach((wallet) => removeRegisteredWallet(wallet));
|
|
150
|
+
listeners["unregister"]?.forEach((listener) => guard(() => listener(...wallets)));
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let cachedWalletsArray: readonly Wallet[] | undefined;
|
|
155
|
+
function get(): readonly Wallet[] {
|
|
156
|
+
if (!cachedWalletsArray) {
|
|
157
|
+
cachedWalletsArray = [...registeredWalletsSet];
|
|
158
|
+
}
|
|
159
|
+
return cachedWalletsArray;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function on<E extends WalletsEventNames>(event: E, listener: WalletsEventsListeners[E]): () => void {
|
|
163
|
+
listeners[event]?.push(listener) || (listeners[event] = [listener]);
|
|
164
|
+
// Return a function that removes the event listener.
|
|
165
|
+
return function off(): void {
|
|
166
|
+
listeners[event] = listeners[event]?.filter((existingListener) => listener !== existingListener);
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function guard(callback: () => void) {
|
|
171
|
+
try {
|
|
172
|
+
callback();
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error(error);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
class AppReadyEvent extends Event implements WindowAppReadyEvent {
|
|
179
|
+
readonly #detail: WindowAppReadyEventAPI;
|
|
180
|
+
|
|
181
|
+
get detail() {
|
|
182
|
+
return this.#detail;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
get type() {
|
|
186
|
+
return "wallet-standard:app-ready" as const;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
constructor(api: WindowAppReadyEventAPI) {
|
|
190
|
+
super("wallet-standard:app-ready", {
|
|
191
|
+
bubbles: false,
|
|
192
|
+
cancelable: false,
|
|
193
|
+
composed: false,
|
|
194
|
+
});
|
|
195
|
+
this.#detail = api;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** @deprecated */
|
|
199
|
+
preventDefault(): never {
|
|
200
|
+
throw new Error("preventDefault cannot be called");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** @deprecated */
|
|
204
|
+
stopImmediatePropagation(): never {
|
|
205
|
+
throw new Error("stopImmediatePropagation cannot be called");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** @deprecated */
|
|
209
|
+
stopPropagation(): never {
|
|
210
|
+
throw new Error("stopPropagation cannot be called");
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* @deprecated Use {@link getWallets} instead.
|
|
216
|
+
*
|
|
217
|
+
* @group Deprecated
|
|
218
|
+
*/
|
|
219
|
+
export function DEPRECATED_getWallets(): Wallets {
|
|
220
|
+
if (wallets) return wallets;
|
|
221
|
+
wallets = getWallets();
|
|
222
|
+
if (typeof window === "undefined") return wallets;
|
|
223
|
+
|
|
224
|
+
const callbacks = (window as DEPRECATED_WalletsWindow).navigator.wallets || [];
|
|
225
|
+
if (!Array.isArray(callbacks)) {
|
|
226
|
+
console.error("window.navigator.wallets is not an array");
|
|
227
|
+
return wallets;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const { register } = wallets;
|
|
231
|
+
const push = (...callbacks: DEPRECATED_WalletsCallback[]): void => callbacks.forEach((callback) => guard(() => callback({ register })));
|
|
232
|
+
try {
|
|
233
|
+
Object.defineProperty((window as DEPRECATED_WalletsWindow).navigator, "wallets", {
|
|
234
|
+
value: Object.freeze({ push }),
|
|
235
|
+
});
|
|
236
|
+
} catch (error) {
|
|
237
|
+
console.error("window.navigator.wallets could not be set");
|
|
238
|
+
return wallets;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
push(...callbacks);
|
|
242
|
+
return wallets;
|
|
243
|
+
}
|