UNPKG

@mysten/slush-wallet

Version:
310 lines (309 loc) 12.2 kB
var __typeError = (msg) => { throw TypeError(msg); }; var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method); var _id, _events, _accounts, _origin, _walletName, _icon, _name, _signTransactionBlock, _signTransaction, _signAndExecuteTransaction, _signPersonalMessage, _on, _SlushWallet_instances, setAccounts_fn, _connect, getPreviouslyAuthorizedAccounts_fn, _disconnect, getNewPopupChannel_fn; import { fromBase64, toBase64 } from "@mysten/sui/utils"; import { getWallets, ReadonlyWalletAccount, SUI_CHAINS } from "@mysten/wallet-standard"; import mitt from "mitt"; import { boolean, object, parse, string } from "valibot"; import { DappPostMessageChannel, decodeJwtSession } from "@mysten/window-wallet-core"; const DEFAULT_SLUSH_ORIGIN = "https://my.slush.app"; const SLUSH_SESSION_KEY = "slush:session"; const SLUSH_WALLET_NAME = "Slush"; const SUI_WALLET_EXTENSION_ID = "com.mystenlabs.suiwallet"; const METADATA_API_URL = "https://api.slush.app/api/wallet/metadata"; const FALLBACK_METADATA = { id: "com.mystenlabs.suiwallet.web", walletName: "Slush", description: "Trade and earn on Sui.", icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIHZpZXdCb3g9IjAgMCA1MCA1MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjUwIiBoZWlnaHQ9IjUwIiBmaWxsPSIjNENBMkZGIi8+CjxwYXRoIGQ9Ik0xMi4zNDczIDM0LjcyNTRDMTMuNTU1MyAzOS4yMzM2IDE4LjA2NzMgNDMuMzE0OCAyNy40MDI1IDQwLjgxMzRDMzYuMzA5NyAzOC40MjY3IDQxLjg5MjEgMzEuMDk5MyA0MC40NDQ2IDI1LjY5NzJDMzkuOTQ0NyAyMy44MzE3IDM4LjQzOTEgMjIuNTY4OSAzNi4xMTc4IDIyLjc3NDRMMTUuMzYxNSAyNC41MDM4QzE0LjA1NDQgMjQuNjA0MSAxMy40NTUgMjQuMzg5OCAxMy4xMDkyIDIzLjU2NjFDMTIuNzczOCAyMi43ODEyIDEyLjk2NDkgMjEuOTM4NSAxNC41NDM3IDIxLjE0MDZMMzAuMzM5NiAxMy4wMzQyQzMxLjU1MDMgMTIuNDE4MiAzMi4zNTY3IDEyLjE2MDUgMzMuMDkzNiAxMi40MjEzQzMzLjU1NTUgMTIuNTg5MSAzMy44NTk2IDEzLjI1NzQgMzMuNTgwMyAxNC4wODJMMzIuNTU2MSAxNy4xMDU2QzMxLjI5OTIgMjAuODE2NCAzMy45ODk5IDIxLjY3ODQgMzUuNTA2OCAyMS4yNzE5QzM3LjgwMTcgMjAuNjU3IDM4LjM0MTYgMTguNDcxMiAzNy42MDIzIDE1LjcxMTlDMzUuNzI3OCA4LjcxNjI5IDI4LjMwNTkgNy42MjI1NCAyMS41NzY4IDkuNDI1NTlDMTQuNzMxMSAxMS4yNTk5IDguNzk2ODEgMTYuODA3MiAxMC42MDg4IDIzLjU2OTZDMTEuMDM1OCAyNS4xNjMgMTIuNTAyNSAyNi40MzYyIDE0LjIwMTQgMjYuMzk3NUwxNi43OTUgMjYuMzkxMkMxNy4zMjg0IDI2LjM3ODggMTcuMTM2MyAyNi40MjI3IDE4LjE2NTMgMjYuMzM3NEMxOS4xOTQ0IDI2LjI1MjIgMjEuOTQyNSAyNS45MTQgMjEuOTQyNSAyNS45MTRMMzUuNDI3NSAyNC4zODhMMzUuNzc1IDI0LjMzNzVDMzYuNTYzNyAyNC4yMDMgMzcuMTU5NyAyNC40MDc5IDM3LjY2MzYgMjUuMjc2QzM4LjQxNzcgMjYuNTc1IDM3LjI2NzIgMjcuNTU0NiAzNS44ODk5IDI4LjcyNzJDMzUuODUzIDI4Ljc1ODYgMzUuODE2IDI4Ljc5MDEgMzUuNzc4OSAyOC44MjE4TDIzLjkyNSAzOS4wMzc3QzIxLjg5MzMgNDAuNzkwMSAyMC40NjYgNDAuMTMxMSAxOS45NjYyIDM4LjI2NTZMMTguMTk1OCAzMS42NTg3QzE3Ljc1ODUgMzAuMDI2NCAxNi4xNjQ2IDI4Ljc0NTYgMTQuMjk3NiAyOS4yNDU5QzExLjk2MzggMjkuODcxMiAxMS43NzQ2IDMyLjU4NzggMTIuMzQ3MyAzNC43MjU0WiIgZmlsbD0iIzA2MEQxNCIvPgo8L3N2Zz4K", enabled: true }; const WalletMetadataSchema = object({ id: string("Wallet ID is required"), walletName: string("Wallet name is required"), icon: string("Icon must be a valid wallet icon format"), enabled: boolean("Enabled is required") }); function setSessionToStorage(session) { localStorage.setItem(SLUSH_SESSION_KEY, session); } function getSessionFromStorage() { const session = localStorage.getItem(SLUSH_SESSION_KEY); if (!session) { throw new Error("No session found"); } return session; } const walletAccountFeatures = [ "sui:signTransaction", "sui:signAndExecuteTransaction", "sui:signPersonalMessage", "sui:signTransactionBlock", "sui:signAndExecuteTransactionBlock" ]; function getAccountsFromSession(session) { const { payload } = decodeJwtSession(session); return payload.accounts.map((account) => { return new ReadonlyWalletAccount({ address: account.address, chains: SUI_CHAINS, features: walletAccountFeatures, publicKey: fromBase64(account.publicKey) }); }); } class SlushWallet { constructor({ name, origin, metadata }) { __privateAdd(this, _SlushWallet_instances); __privateAdd(this, _id); __privateAdd(this, _events); __privateAdd(this, _accounts); __privateAdd(this, _origin); __privateAdd(this, _walletName); __privateAdd(this, _icon); __privateAdd(this, _name); __privateAdd(this, _signTransactionBlock, async ({ transactionBlock, account, chain }) => { const data = await transactionBlock.toJSON(); const popup = __privateMethod(this, _SlushWallet_instances, getNewPopupChannel_fn).call(this); const response = await popup.send({ type: "sign-transaction", transaction: data, address: account.address, chain, session: getSessionFromStorage() }); return { transactionBlockBytes: response.bytes, signature: response.signature }; }); __privateAdd(this, _signTransaction, async ({ transaction, account, chain }) => { const popup = __privateMethod(this, _SlushWallet_instances, getNewPopupChannel_fn).call(this); const tx = await transaction.toJSON(); const response = await popup.send({ type: "sign-transaction", transaction: tx, address: account.address, chain, session: getSessionFromStorage() }); return { bytes: response.bytes, signature: response.signature }; }); __privateAdd(this, _signAndExecuteTransaction, async ({ transaction, account, chain }) => { const popup = __privateMethod(this, _SlushWallet_instances, getNewPopupChannel_fn).call(this); const data = await transaction.toJSON(); const response = await popup.send({ type: "sign-and-execute-transaction", transaction: data, address: account.address, chain, session: getSessionFromStorage() }); return { bytes: response.bytes, signature: response.signature, digest: response.digest, effects: response.effects }; }); __privateAdd(this, _signPersonalMessage, async ({ message, account, chain }) => { const popup = __privateMethod(this, _SlushWallet_instances, getNewPopupChannel_fn).call(this); const response = await popup.send({ type: "sign-personal-message", message: toBase64(message), address: account.address, chain: chain ?? account.chains[0], session: getSessionFromStorage() }); return { bytes: response.bytes, signature: response.signature }; }); __privateAdd(this, _on, (event, listener) => { __privateGet(this, _events).on(event, listener); return () => __privateGet(this, _events).off(event, listener); }); __privateAdd(this, _connect, async (input) => { if (input?.silent) { return { accounts: this.accounts }; } const popup = __privateMethod(this, _SlushWallet_instances, getNewPopupChannel_fn).call(this); const response = await popup.send({ type: "connect" }); setSessionToStorage(response.session); __privateMethod(this, _SlushWallet_instances, setAccounts_fn).call(this, getAccountsFromSession(response.session)); return { accounts: this.accounts }; }); __privateAdd(this, _disconnect, async () => { localStorage.removeItem(SLUSH_SESSION_KEY); __privateMethod(this, _SlushWallet_instances, setAccounts_fn).call(this, []); }); __privateSet(this, _id, metadata.id); __privateSet(this, _accounts, __privateMethod(this, _SlushWallet_instances, getPreviouslyAuthorizedAccounts_fn).call(this)); __privateSet(this, _events, mitt()); __privateSet(this, _origin, origin || DEFAULT_SLUSH_ORIGIN); __privateSet(this, _name, name); __privateSet(this, _walletName, metadata.walletName); __privateSet(this, _icon, metadata.icon); } get name() { return __privateGet(this, _walletName); } get id() { return __privateGet(this, _id); } get icon() { return __privateGet(this, _icon); } get version() { return "1.0.0"; } get chains() { return SUI_CHAINS; } get accounts() { return __privateGet(this, _accounts); } get features() { return { "standard:connect": { version: "1.0.0", connect: __privateGet(this, _connect) }, "standard:disconnect": { version: "1.0.0", disconnect: __privateGet(this, _disconnect) }, "standard:events": { version: "1.0.0", on: __privateGet(this, _on) }, "sui:signTransactionBlock": { version: "1.0.0", signTransactionBlock: __privateGet(this, _signTransactionBlock) }, "sui:signTransaction": { version: "2.0.0", signTransaction: __privateGet(this, _signTransaction) }, "sui:signPersonalMessage": { version: "1.1.0", signPersonalMessage: __privateGet(this, _signPersonalMessage) }, "sui:signAndExecuteTransaction": { version: "2.0.0", signAndExecuteTransaction: __privateGet(this, _signAndExecuteTransaction) } }; } updateMetadata(metadata) { __privateSet(this, _id, metadata.id); __privateSet(this, _walletName, metadata.walletName); __privateSet(this, _icon, metadata.icon); } } _id = new WeakMap(); _events = new WeakMap(); _accounts = new WeakMap(); _origin = new WeakMap(); _walletName = new WeakMap(); _icon = new WeakMap(); _name = new WeakMap(); _signTransactionBlock = new WeakMap(); _signTransaction = new WeakMap(); _signAndExecuteTransaction = new WeakMap(); _signPersonalMessage = new WeakMap(); _on = new WeakMap(); _SlushWallet_instances = new WeakSet(); setAccounts_fn = function(accounts) { __privateSet(this, _accounts, accounts); __privateGet(this, _events).emit("change", { accounts: this.accounts }); }; _connect = new WeakMap(); getPreviouslyAuthorizedAccounts_fn = function() { try { return getAccountsFromSession(getSessionFromStorage()); } catch (error) { return []; } }; _disconnect = new WeakMap(); getNewPopupChannel_fn = function() { return new DappPostMessageChannel({ appName: __privateGet(this, _name), hostOrigin: __privateGet(this, _origin) }); }; async function fetchMetadata(metadataApiUrl) { const response = await fetch(metadataApiUrl); if (!response.ok) { throw new Error("Failed to fetch wallet metadata"); } const data = await response.json(); return parse(WalletMetadataSchema, data); } function registerSlushWallet(name, { origin, metadataApiUrl = METADATA_API_URL } = {}) { const wallets = getWallets(); let unregister = null; wallets.on("register", (wallet) => { if (wallet.id === SUI_WALLET_EXTENSION_ID) { unregister?.(); } }); const extension = wallets.get().find((wallet) => wallet.id === SUI_WALLET_EXTENSION_ID); if (extension) { return; } const slushWalletInstance = new SlushWallet({ name, origin, metadata: FALLBACK_METADATA }); unregister = wallets.register(slushWalletInstance); fetchMetadata(metadataApiUrl).then((metadata) => { if (!metadata.enabled) { console.log("Slush wallet is not currently enabled."); unregister?.(); return; } slushWalletInstance.updateMetadata(metadata); }).catch((error) => { console.error("Error fetching metadata", error); }); return { wallet: slushWalletInstance, unregister }; } export { SLUSH_WALLET_NAME, SlushWallet, registerSlushWallet }; //# sourceMappingURL=index.js.map