@mysten/slush-wallet
Version:
Wallet adapter for Slush web wallet
310 lines (309 loc) • 12.2 kB
JavaScript
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