@simplepay-ai/widget
Version:
SimplePay Payment Widget
1,493 lines • 129 kB
JavaScript
import { B as Buffer, b as getAugmentedNamespace, s as sha3, g as getDefaultExportFromCjs, d as bytesToHex, e as sha256 } from "./main-oDQ_krE7.js";
import { D, _, c as clsx, d, y } from "./clsx.m-yJycXJN4.js";
class ScopedLocalStorage {
constructor(scope, module) {
this.scope = scope;
this.module = module;
}
storeObject(key, item) {
this.setItem(key, JSON.stringify(item));
}
loadObject(key) {
const item = this.getItem(key);
return item ? JSON.parse(item) : void 0;
}
setItem(key, value) {
localStorage.setItem(this.scopedKey(key), value);
}
getItem(key) {
return localStorage.getItem(this.scopedKey(key));
}
removeItem(key) {
localStorage.removeItem(this.scopedKey(key));
}
clear() {
const prefix = this.scopedKey("");
const keysToRemove = [];
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (typeof key === "string" && key.startsWith(prefix)) {
keysToRemove.push(key);
}
}
keysToRemove.forEach((key) => localStorage.removeItem(key));
}
scopedKey(key) {
return `-${this.scope}${this.module ? `:${this.module}` : ""}:${key}`;
}
static clearAll() {
new ScopedLocalStorage("CBWSDK").clear();
new ScopedLocalStorage("walletlink").clear();
}
}
const standardErrorCodes = {
rpc: {
invalidInput: -32e3,
resourceNotFound: -32001,
resourceUnavailable: -32002,
transactionRejected: -32003,
methodNotSupported: -32004,
limitExceeded: -32005,
parse: -32700,
invalidRequest: -32600,
methodNotFound: -32601,
invalidParams: -32602,
internal: -32603
},
provider: {
userRejectedRequest: 4001,
unauthorized: 4100,
unsupportedMethod: 4200,
disconnected: 4900,
chainDisconnected: 4901,
unsupportedChain: 4902
}
};
const errorValues = {
"-32700": {
standard: "JSON RPC 2.0",
message: "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."
},
"-32600": {
standard: "JSON RPC 2.0",
message: "The JSON sent is not a valid Request object."
},
"-32601": {
standard: "JSON RPC 2.0",
message: "The method does not exist / is not available."
},
"-32602": {
standard: "JSON RPC 2.0",
message: "Invalid method parameter(s)."
},
"-32603": {
standard: "JSON RPC 2.0",
message: "Internal JSON-RPC error."
},
"-32000": {
standard: "EIP-1474",
message: "Invalid input."
},
"-32001": {
standard: "EIP-1474",
message: "Resource not found."
},
"-32002": {
standard: "EIP-1474",
message: "Resource unavailable."
},
"-32003": {
standard: "EIP-1474",
message: "Transaction rejected."
},
"-32004": {
standard: "EIP-1474",
message: "Method not supported."
},
"-32005": {
standard: "EIP-1474",
message: "Request limit exceeded."
},
"4001": {
standard: "EIP-1193",
message: "User rejected the request."
},
"4100": {
standard: "EIP-1193",
message: "The requested account and/or method has not been authorized by the user."
},
"4200": {
standard: "EIP-1193",
message: "The requested method is not supported by this Ethereum provider."
},
"4900": {
standard: "EIP-1193",
message: "The provider is disconnected from all chains."
},
"4901": {
standard: "EIP-1193",
message: "The provider is disconnected from the specified chain."
},
"4902": {
standard: "EIP-3085",
message: "Unrecognized chain ID."
}
};
const FALLBACK_MESSAGE = "Unspecified error message.";
const JSON_RPC_SERVER_ERROR_MESSAGE = "Unspecified server error.";
function getMessageFromCode(code, fallbackMessage = FALLBACK_MESSAGE) {
if (code && Number.isInteger(code)) {
const codeString = code.toString();
if (hasKey(errorValues, codeString)) {
return errorValues[codeString].message;
}
if (isJsonRpcServerError(code)) {
return JSON_RPC_SERVER_ERROR_MESSAGE;
}
}
return fallbackMessage;
}
function isValidCode(code) {
if (!Number.isInteger(code)) {
return false;
}
const codeString = code.toString();
if (errorValues[codeString]) {
return true;
}
if (isJsonRpcServerError(code)) {
return true;
}
return false;
}
function serialize(error, { shouldIncludeStack = false } = {}) {
const serialized = {};
if (error && typeof error === "object" && !Array.isArray(error) && hasKey(error, "code") && isValidCode(error.code)) {
const _error = error;
serialized.code = _error.code;
if (_error.message && typeof _error.message === "string") {
serialized.message = _error.message;
if (hasKey(_error, "data")) {
serialized.data = _error.data;
}
} else {
serialized.message = getMessageFromCode(serialized.code);
serialized.data = { originalError: assignOriginalError(error) };
}
} else {
serialized.code = standardErrorCodes.rpc.internal;
serialized.message = hasStringProperty(error, "message") ? error.message : FALLBACK_MESSAGE;
serialized.data = { originalError: assignOriginalError(error) };
}
if (shouldIncludeStack) {
serialized.stack = hasStringProperty(error, "stack") ? error.stack : void 0;
}
return serialized;
}
function isJsonRpcServerError(code) {
return code >= -32099 && code <= -32e3;
}
function assignOriginalError(error) {
if (error && typeof error === "object" && !Array.isArray(error)) {
return Object.assign({}, error);
}
return error;
}
function hasKey(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
function hasStringProperty(obj, prop) {
return typeof obj === "object" && obj !== null && prop in obj && typeof obj[prop] === "string";
}
const standardErrors = {
rpc: {
parse: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.parse, arg),
invalidRequest: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.invalidRequest, arg),
invalidParams: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.invalidParams, arg),
methodNotFound: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.methodNotFound, arg),
internal: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.internal, arg),
server: (opts) => {
if (!opts || typeof opts !== "object" || Array.isArray(opts)) {
throw new Error("Ethereum RPC Server errors must provide single object argument.");
}
const { code } = opts;
if (!Number.isInteger(code) || code > -32005 || code < -32099) {
throw new Error('"code" must be an integer such that: -32099 <= code <= -32005');
}
return getEthJsonRpcError(code, opts);
},
invalidInput: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.invalidInput, arg),
resourceNotFound: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.resourceNotFound, arg),
resourceUnavailable: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.resourceUnavailable, arg),
transactionRejected: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.transactionRejected, arg),
methodNotSupported: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.methodNotSupported, arg),
limitExceeded: (arg) => getEthJsonRpcError(standardErrorCodes.rpc.limitExceeded, arg)
},
provider: {
userRejectedRequest: (arg) => {
return getEthProviderError(standardErrorCodes.provider.userRejectedRequest, arg);
},
unauthorized: (arg) => {
return getEthProviderError(standardErrorCodes.provider.unauthorized, arg);
},
unsupportedMethod: (arg) => {
return getEthProviderError(standardErrorCodes.provider.unsupportedMethod, arg);
},
disconnected: (arg) => {
return getEthProviderError(standardErrorCodes.provider.disconnected, arg);
},
chainDisconnected: (arg) => {
return getEthProviderError(standardErrorCodes.provider.chainDisconnected, arg);
},
unsupportedChain: (arg) => {
return getEthProviderError(standardErrorCodes.provider.unsupportedChain, arg);
},
custom: (opts) => {
if (!opts || typeof opts !== "object" || Array.isArray(opts)) {
throw new Error("Ethereum Provider custom errors must provide single object argument.");
}
const { code, message, data } = opts;
if (!message || typeof message !== "string") {
throw new Error('"message" must be a nonempty string');
}
return new EthereumProviderError(code, message, data);
}
}
};
function getEthJsonRpcError(code, arg) {
const [message, data] = parseOpts(arg);
return new EthereumRpcError(code, message || getMessageFromCode(code), data);
}
function getEthProviderError(code, arg) {
const [message, data] = parseOpts(arg);
return new EthereumProviderError(code, message || getMessageFromCode(code), data);
}
function parseOpts(arg) {
if (arg) {
if (typeof arg === "string") {
return [arg];
} else if (typeof arg === "object" && !Array.isArray(arg)) {
const { message, data } = arg;
if (message && typeof message !== "string") {
throw new Error("Must specify string message.");
}
return [message || void 0, data];
}
}
return [];
}
class EthereumRpcError extends Error {
constructor(code, message, data) {
if (!Number.isInteger(code)) {
throw new Error('"code" must be an integer.');
}
if (!message || typeof message !== "string") {
throw new Error('"message" must be a nonempty string.');
}
super(message);
this.code = code;
if (data !== void 0) {
this.data = data;
}
}
}
class EthereumProviderError extends EthereumRpcError {
/**
* Create an Ethereum Provider JSON-RPC error.
* `code` must be an integer in the 1000 <= 4999 range.
*/
constructor(code, message, data) {
if (!isValidEthProviderCode(code)) {
throw new Error('"code" must be an integer such that: 1000 <= code <= 4999');
}
super(code, message, data);
}
}
function isValidEthProviderCode(code) {
return Number.isInteger(code) && code >= 1e3 && code <= 4999;
}
function OpaqueType() {
return (value) => value;
}
const HexString = OpaqueType();
const AddressString = OpaqueType();
const BigIntString = OpaqueType();
function IntNumber(num) {
return Math.floor(num);
}
const INT_STRING_REGEX = /^[0-9]*$/;
const HEXADECIMAL_STRING_REGEX = /^[a-f0-9]*$/;
function randomBytesHex(length) {
return uint8ArrayToHex(crypto.getRandomValues(new Uint8Array(length)));
}
function uint8ArrayToHex(value) {
return [...value].map((b) => b.toString(16).padStart(2, "0")).join("");
}
function hexStringToUint8Array(hexString) {
return new Uint8Array(hexString.match(/.{1,2}/g).map((byte) => Number.parseInt(byte, 16)));
}
function hexStringFromBuffer(buf, includePrefix = false) {
const hex = buf.toString("hex");
return HexString(includePrefix ? `0x${hex}` : hex);
}
function encodeToHexString(str) {
return hexStringFromBuffer(ensureBuffer(str), true);
}
function bigIntStringFromBigInt(bi) {
return BigIntString(bi.toString(10));
}
function hexStringFromNumber(num) {
return HexString(`0x${BigInt(num).toString(16)}`);
}
function has0xPrefix(str) {
return str.startsWith("0x") || str.startsWith("0X");
}
function strip0x(hex) {
if (has0xPrefix(hex)) {
return hex.slice(2);
}
return hex;
}
function prepend0x(hex) {
if (has0xPrefix(hex)) {
return `0x${hex.slice(2)}`;
}
return `0x${hex}`;
}
function isHexString$1(hex) {
if (typeof hex !== "string") {
return false;
}
const s = strip0x(hex).toLowerCase();
return HEXADECIMAL_STRING_REGEX.test(s);
}
function ensureHexString(hex, includePrefix = false) {
if (typeof hex === "string") {
const s = strip0x(hex).toLowerCase();
if (HEXADECIMAL_STRING_REGEX.test(s)) {
return HexString(includePrefix ? `0x${s}` : s);
}
}
throw standardErrors.rpc.invalidParams(`"${String(hex)}" is not a hexadecimal string`);
}
function ensureEvenLengthHexString(hex, includePrefix = false) {
let h = ensureHexString(hex, false);
if (h.length % 2 === 1) {
h = HexString(`0${h}`);
}
return includePrefix ? HexString(`0x${h}`) : h;
}
function ensureAddressString(str) {
if (typeof str === "string") {
const s = strip0x(str).toLowerCase();
if (isHexString$1(s) && s.length === 40) {
return AddressString(prepend0x(s));
}
}
throw standardErrors.rpc.invalidParams(`Invalid Ethereum address: ${String(str)}`);
}
function ensureBuffer(str) {
if (Buffer.isBuffer(str)) {
return str;
}
if (typeof str === "string") {
if (isHexString$1(str)) {
const s = ensureEvenLengthHexString(str, false);
return Buffer.from(s, "hex");
}
return Buffer.from(str, "utf8");
}
throw standardErrors.rpc.invalidParams(`Not binary data: ${String(str)}`);
}
function ensureIntNumber(num) {
if (typeof num === "number" && Number.isInteger(num)) {
return IntNumber(num);
}
if (typeof num === "string") {
if (INT_STRING_REGEX.test(num)) {
return IntNumber(Number(num));
}
if (isHexString$1(num)) {
return IntNumber(Number(BigInt(ensureEvenLengthHexString(num, true))));
}
}
throw standardErrors.rpc.invalidParams(`Not an integer: ${String(num)}`);
}
function ensureBigInt(val) {
if (val !== null && (typeof val === "bigint" || isBigNumber(val))) {
return BigInt(val.toString(10));
}
if (typeof val === "number") {
return BigInt(ensureIntNumber(val));
}
if (typeof val === "string") {
if (INT_STRING_REGEX.test(val)) {
return BigInt(val);
}
if (isHexString$1(val)) {
return BigInt(ensureEvenLengthHexString(val, true));
}
}
throw standardErrors.rpc.invalidParams(`Not an integer: ${String(val)}`);
}
function ensureParsedJSONObject(val) {
if (typeof val === "string") {
return JSON.parse(val);
}
if (typeof val === "object") {
return val;
}
throw standardErrors.rpc.invalidParams(`Not a JSON string or an object: ${String(val)}`);
}
function isBigNumber(val) {
if (val == null || typeof val.constructor !== "function") {
return false;
}
const { constructor } = val;
return typeof constructor.config === "function" && typeof constructor.EUCLID === "number";
}
async function generateKeyPair() {
return crypto.subtle.generateKey({
name: "ECDH",
namedCurve: "P-256"
}, true, ["deriveKey"]);
}
async function deriveSharedSecret(ownPrivateKey, peerPublicKey) {
return crypto.subtle.deriveKey({
name: "ECDH",
public: peerPublicKey
}, ownPrivateKey, {
name: "AES-GCM",
length: 256
}, false, ["encrypt", "decrypt"]);
}
async function encrypt(sharedSecret, plainText) {
const iv = crypto.getRandomValues(new Uint8Array(12));
const cipherText = await crypto.subtle.encrypt({
name: "AES-GCM",
iv
}, sharedSecret, new TextEncoder().encode(plainText));
return { iv, cipherText };
}
async function decrypt(sharedSecret, { iv, cipherText }) {
const plainText = await crypto.subtle.decrypt({
name: "AES-GCM",
iv
}, sharedSecret, cipherText);
return new TextDecoder().decode(plainText);
}
function getFormat(keyType) {
switch (keyType) {
case "public":
return "spki";
case "private":
return "pkcs8";
}
}
async function exportKeyToHexString(type, key) {
const format = getFormat(type);
const exported = await crypto.subtle.exportKey(format, key);
return uint8ArrayToHex(new Uint8Array(exported));
}
async function importKeyFromHexString(type, hexString) {
const format = getFormat(type);
const arrayBuffer = hexStringToUint8Array(hexString).buffer;
return await crypto.subtle.importKey(format, new Uint8Array(arrayBuffer), {
name: "ECDH",
namedCurve: "P-256"
}, true, type === "private" ? ["deriveKey"] : []);
}
async function encryptContent(content, sharedSecret) {
const serialized = JSON.stringify(content, (_2, value) => {
if (!(value instanceof Error))
return value;
const error = value;
return Object.assign(Object.assign({}, error.code ? { code: error.code } : {}), { message: error.message });
});
return encrypt(sharedSecret, serialized);
}
async function decryptContent(encryptedData, sharedSecret) {
return JSON.parse(await decrypt(sharedSecret, encryptedData));
}
const OWN_PRIVATE_KEY = {
storageKey: "ownPrivateKey",
keyType: "private"
};
const OWN_PUBLIC_KEY = {
storageKey: "ownPublicKey",
keyType: "public"
};
const PEER_PUBLIC_KEY = {
storageKey: "peerPublicKey",
keyType: "public"
};
class SCWKeyManager {
constructor() {
this.storage = new ScopedLocalStorage("CBWSDK", "SCWKeyManager");
this.ownPrivateKey = null;
this.ownPublicKey = null;
this.peerPublicKey = null;
this.sharedSecret = null;
}
async getOwnPublicKey() {
await this.loadKeysIfNeeded();
return this.ownPublicKey;
}
// returns null if the shared secret is not yet derived
async getSharedSecret() {
await this.loadKeysIfNeeded();
return this.sharedSecret;
}
async setPeerPublicKey(key) {
this.sharedSecret = null;
this.peerPublicKey = key;
await this.storeKey(PEER_PUBLIC_KEY, key);
await this.loadKeysIfNeeded();
}
async clear() {
this.ownPrivateKey = null;
this.ownPublicKey = null;
this.peerPublicKey = null;
this.sharedSecret = null;
this.storage.removeItem(OWN_PUBLIC_KEY.storageKey);
this.storage.removeItem(OWN_PRIVATE_KEY.storageKey);
this.storage.removeItem(PEER_PUBLIC_KEY.storageKey);
}
async generateKeyPair() {
const newKeyPair = await generateKeyPair();
this.ownPrivateKey = newKeyPair.privateKey;
this.ownPublicKey = newKeyPair.publicKey;
await this.storeKey(OWN_PRIVATE_KEY, newKeyPair.privateKey);
await this.storeKey(OWN_PUBLIC_KEY, newKeyPair.publicKey);
}
async loadKeysIfNeeded() {
if (this.ownPrivateKey === null) {
this.ownPrivateKey = await this.loadKey(OWN_PRIVATE_KEY);
}
if (this.ownPublicKey === null) {
this.ownPublicKey = await this.loadKey(OWN_PUBLIC_KEY);
}
if (this.ownPrivateKey === null || this.ownPublicKey === null) {
await this.generateKeyPair();
}
if (this.peerPublicKey === null) {
this.peerPublicKey = await this.loadKey(PEER_PUBLIC_KEY);
}
if (this.sharedSecret === null) {
if (this.ownPrivateKey === null || this.peerPublicKey === null)
return;
this.sharedSecret = await deriveSharedSecret(this.ownPrivateKey, this.peerPublicKey);
}
}
// storage methods
async loadKey(item) {
const key = this.storage.getItem(item.storageKey);
if (!key)
return null;
return importKeyFromHexString(item.keyType, key);
}
async storeKey(item, key) {
const hexString = await exportKeyToHexString(item.keyType, key);
this.storage.setItem(item.storageKey, hexString);
}
}
const VERSION = "4.3.0";
const NAME = "@coinbase/wallet-sdk";
async function fetchRPCRequest(request, rpcUrl) {
const requestBody = Object.assign(Object.assign({}, request), { jsonrpc: "2.0", id: crypto.randomUUID() });
const res = await window.fetch(rpcUrl, {
method: "POST",
body: JSON.stringify(requestBody),
mode: "cors",
headers: {
"Content-Type": "application/json",
"X-Cbw-Sdk-Version": VERSION,
"X-Cbw-Sdk-Platform": NAME
}
});
const { result, error } = await res.json();
if (error)
throw error;
return result;
}
function getCoinbaseInjectedLegacyProvider() {
const window2 = globalThis;
return window2.coinbaseWalletExtension;
}
function getInjectedEthereum() {
var _a, _b;
try {
const window2 = globalThis;
return (_a = window2.ethereum) !== null && _a !== void 0 ? _a : (_b = window2.top) === null || _b === void 0 ? void 0 : _b.ethereum;
} catch (_c) {
return void 0;
}
}
function getCoinbaseInjectedProvider({ metadata, preference }) {
var _a, _b;
const { appName, appLogoUrl, appChainIds } = metadata;
if (preference.options !== "smartWalletOnly") {
const extension = getCoinbaseInjectedLegacyProvider();
if (extension) {
(_a = extension.setAppInfo) === null || _a === void 0 ? void 0 : _a.call(extension, appName, appLogoUrl, appChainIds, preference);
return extension;
}
}
const ethereum = getInjectedEthereum();
if (ethereum === null || ethereum === void 0 ? void 0 : ethereum.isCoinbaseBrowser) {
(_b = ethereum.setAppInfo) === null || _b === void 0 ? void 0 : _b.call(ethereum, appName, appLogoUrl, appChainIds, preference);
return ethereum;
}
return void 0;
}
function checkErrorForInvalidRequestArgs(args) {
if (!args || typeof args !== "object" || Array.isArray(args)) {
throw standardErrors.rpc.invalidParams({
message: "Expected a single, non-array, object argument.",
data: args
});
}
const { method, params } = args;
if (typeof method !== "string" || method.length === 0) {
throw standardErrors.rpc.invalidParams({
message: "'args.method' must be a non-empty string.",
data: args
});
}
if (params !== void 0 && !Array.isArray(params) && (typeof params !== "object" || params === null)) {
throw standardErrors.rpc.invalidParams({
message: "'args.params' must be an object or array if provided.",
data: args
});
}
switch (method) {
case "eth_sign":
case "eth_signTypedData_v2":
case "eth_subscribe":
case "eth_unsubscribe":
throw standardErrors.provider.unsupportedMethod();
}
}
const ACCOUNTS_KEY = "accounts";
const ACTIVE_CHAIN_STORAGE_KEY = "activeChain";
const AVAILABLE_CHAINS_STORAGE_KEY = "availableChains";
const WALLET_CAPABILITIES_STORAGE_KEY = "walletCapabilities";
class SCWSigner {
constructor(params) {
var _a, _b, _c;
this.metadata = params.metadata;
this.communicator = params.communicator;
this.callback = params.callback;
this.keyManager = new SCWKeyManager();
this.storage = new ScopedLocalStorage("CBWSDK", "SCWStateManager");
this.accounts = (_a = this.storage.loadObject(ACCOUNTS_KEY)) !== null && _a !== void 0 ? _a : [];
this.chain = this.storage.loadObject(ACTIVE_CHAIN_STORAGE_KEY) || {
id: (_c = (_b = params.metadata.appChainIds) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : 1
};
this.handshake = this.handshake.bind(this);
this.request = this.request.bind(this);
this.createRequestMessage = this.createRequestMessage.bind(this);
this.decryptResponseMessage = this.decryptResponseMessage.bind(this);
}
async handshake(args) {
var _a, _b, _c, _d;
await ((_b = (_a = this.communicator).waitForPopupLoaded) === null || _b === void 0 ? void 0 : _b.call(_a));
const handshakeMessage = await this.createRequestMessage({
handshake: {
method: args.method,
params: Object.assign({}, this.metadata, (_c = args.params) !== null && _c !== void 0 ? _c : {})
}
});
const response = await this.communicator.postRequestAndWaitForResponse(handshakeMessage);
if ("failure" in response.content)
throw response.content.failure;
const peerPublicKey = await importKeyFromHexString("public", response.sender);
await this.keyManager.setPeerPublicKey(peerPublicKey);
const decrypted = await this.decryptResponseMessage(response);
const result = decrypted.result;
if ("error" in result)
throw result.error;
switch (args.method) {
case "eth_requestAccounts": {
const accounts = result.value;
this.accounts = accounts;
this.storage.storeObject(ACCOUNTS_KEY, accounts);
(_d = this.callback) === null || _d === void 0 ? void 0 : _d.call(this, "accountsChanged", accounts);
break;
}
}
}
async request(request) {
var _a;
if (this.accounts.length === 0) {
switch (request.method) {
case "wallet_sendCalls":
return this.sendRequestToPopup(request);
default:
throw standardErrors.provider.unauthorized();
}
}
switch (request.method) {
case "eth_requestAccounts":
(_a = this.callback) === null || _a === void 0 ? void 0 : _a.call(this, "connect", { chainId: hexStringFromNumber(this.chain.id) });
return this.accounts;
case "eth_accounts":
return this.accounts;
case "eth_coinbase":
return this.accounts[0];
case "net_version":
return this.chain.id;
case "eth_chainId":
return hexStringFromNumber(this.chain.id);
case "wallet_getCapabilities":
return this.storage.loadObject(WALLET_CAPABILITIES_STORAGE_KEY);
case "wallet_switchEthereumChain":
return this.handleSwitchChainRequest(request);
case "eth_ecRecover":
case "personal_sign":
case "wallet_sign":
case "personal_ecRecover":
case "eth_signTransaction":
case "eth_sendTransaction":
case "eth_signTypedData_v1":
case "eth_signTypedData_v3":
case "eth_signTypedData_v4":
case "eth_signTypedData":
case "wallet_addEthereumChain":
case "wallet_watchAsset":
case "wallet_sendCalls":
case "wallet_showCallsStatus":
case "wallet_grantPermissions":
return this.sendRequestToPopup(request);
default:
if (!this.chain.rpcUrl)
throw standardErrors.rpc.internal("No RPC URL set for chain");
return fetchRPCRequest(request, this.chain.rpcUrl);
}
}
async sendRequestToPopup(request) {
var _a, _b;
await ((_b = (_a = this.communicator).waitForPopupLoaded) === null || _b === void 0 ? void 0 : _b.call(_a));
const response = await this.sendEncryptedRequest(request);
const decrypted = await this.decryptResponseMessage(response);
const result = decrypted.result;
if ("error" in result)
throw result.error;
return result.value;
}
async cleanup() {
var _a, _b;
this.storage.clear();
await this.keyManager.clear();
this.accounts = [];
this.chain = {
id: (_b = (_a = this.metadata.appChainIds) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 1
};
}
/**
* @returns `null` if the request was successful.
* https://eips.ethereum.org/EIPS/eip-3326#wallet_switchethereumchain
*/
async handleSwitchChainRequest(request) {
var _a;
const params = request.params;
if (!params || !((_a = params[0]) === null || _a === void 0 ? void 0 : _a.chainId)) {
throw standardErrors.rpc.invalidParams();
}
const chainId = ensureIntNumber(params[0].chainId);
const localResult = this.updateChain(chainId);
if (localResult)
return null;
const popupResult = await this.sendRequestToPopup(request);
if (popupResult === null) {
this.updateChain(chainId);
}
return popupResult;
}
async sendEncryptedRequest(request) {
const sharedSecret = await this.keyManager.getSharedSecret();
if (!sharedSecret) {
throw standardErrors.provider.unauthorized("No valid session found, try requestAccounts before other methods");
}
const encrypted = await encryptContent({
action: request,
chainId: this.chain.id
}, sharedSecret);
const message = await this.createRequestMessage({ encrypted });
return this.communicator.postRequestAndWaitForResponse(message);
}
async createRequestMessage(content) {
const publicKey = await exportKeyToHexString("public", await this.keyManager.getOwnPublicKey());
return {
id: crypto.randomUUID(),
sender: publicKey,
content,
timestamp: /* @__PURE__ */ new Date()
};
}
async decryptResponseMessage(message) {
var _a, _b;
const content = message.content;
if ("failure" in content) {
throw content.failure;
}
const sharedSecret = await this.keyManager.getSharedSecret();
if (!sharedSecret) {
throw standardErrors.provider.unauthorized("Invalid session");
}
const response = await decryptContent(content.encrypted, sharedSecret);
const availableChains = (_a = response.data) === null || _a === void 0 ? void 0 : _a.chains;
if (availableChains) {
const chains = Object.entries(availableChains).map(([id, rpcUrl]) => ({
id: Number(id),
rpcUrl
}));
this.storage.storeObject(AVAILABLE_CHAINS_STORAGE_KEY, chains);
this.updateChain(this.chain.id, chains);
}
const walletCapabilities = (_b = response.data) === null || _b === void 0 ? void 0 : _b.capabilities;
if (walletCapabilities) {
this.storage.storeObject(WALLET_CAPABILITIES_STORAGE_KEY, walletCapabilities);
}
return response;
}
updateChain(chainId, newAvailableChains) {
var _a;
const chains = newAvailableChains !== null && newAvailableChains !== void 0 ? newAvailableChains : this.storage.loadObject(AVAILABLE_CHAINS_STORAGE_KEY);
const chain = chains === null || chains === void 0 ? void 0 : chains.find((chain2) => chain2.id === chainId);
if (!chain)
return false;
if (chain !== this.chain) {
this.chain = chain;
this.storage.storeObject(ACTIVE_CHAIN_STORAGE_KEY, chain);
(_a = this.callback) === null || _a === void 0 ? void 0 : _a.call(this, "chainChanged", hexStringFromNumber(chain.id));
}
return true;
}
}
const require$$0 = /* @__PURE__ */ getAugmentedNamespace(sha3);
const { keccak_256 } = require$$0;
function zeros(bytes) {
return Buffer.allocUnsafe(bytes).fill(0);
}
function bitLengthFromBigInt(num) {
return num.toString(2).length;
}
function bufferBEFromBigInt(num, length) {
let hex = num.toString(16);
if (hex.length % 2 !== 0) hex = "0" + hex;
const byteArray = hex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16));
while (byteArray.length < length) {
byteArray.unshift(0);
}
return Buffer.from(byteArray);
}
function twosFromBigInt(value, width) {
const isNegative = value < 0n;
let result;
if (isNegative) {
const mask = (1n << BigInt(width)) - 1n;
result = (~value & mask) + 1n;
} else {
result = value;
}
result &= (1n << BigInt(width)) - 1n;
return result;
}
function setLength(msg, length, right) {
const buf = zeros(length);
msg = toBuffer(msg);
if (right) {
if (msg.length < length) {
msg.copy(buf);
return buf;
}
return msg.slice(0, length);
} else {
if (msg.length < length) {
msg.copy(buf, length - msg.length);
return buf;
}
return msg.slice(-length);
}
}
function setLengthRight(msg, length) {
return setLength(msg, length, true);
}
function toBuffer(v) {
if (!Buffer.isBuffer(v)) {
if (Array.isArray(v)) {
v = Buffer.from(v);
} else if (typeof v === "string") {
if (isHexString(v)) {
v = Buffer.from(padToEven(stripHexPrefix(v)), "hex");
} else {
v = Buffer.from(v);
}
} else if (typeof v === "number") {
v = intToBuffer(v);
} else if (v === null || v === void 0) {
v = Buffer.allocUnsafe(0);
} else if (typeof v === "bigint") {
v = bufferBEFromBigInt(v);
} else if (v.toArray) {
v = Buffer.from(v.toArray());
} else {
throw new Error("invalid type");
}
}
return v;
}
function bufferToHex(buf) {
buf = toBuffer(buf);
return "0x" + buf.toString("hex");
}
function keccak(a, bits) {
a = toBuffer(a);
if (!bits) bits = 256;
if (bits !== 256) {
throw new Error("unsupported");
}
return Buffer.from(keccak_256(new Uint8Array(a)));
}
function padToEven(str) {
return str.length % 2 ? "0" + str : str;
}
function isHexString(str) {
return typeof str === "string" && str.match(/^0x[0-9A-Fa-f]*$/);
}
function stripHexPrefix(str) {
if (typeof str === "string" && str.startsWith("0x")) {
return str.slice(2);
}
return str;
}
var util$2 = {
zeros,
setLength,
setLengthRight,
isHexString,
stripHexPrefix,
toBuffer,
bufferToHex,
keccak,
bitLengthFromBigInt,
bufferBEFromBigInt,
twosFromBigInt
};
const util$1 = util$2;
function elementaryName(name) {
if (name.startsWith("int[")) {
return "int256" + name.slice(3);
} else if (name === "int") {
return "int256";
} else if (name.startsWith("uint[")) {
return "uint256" + name.slice(4);
} else if (name === "uint") {
return "uint256";
} else if (name.startsWith("fixed[")) {
return "fixed128x128" + name.slice(5);
} else if (name === "fixed") {
return "fixed128x128";
} else if (name.startsWith("ufixed[")) {
return "ufixed128x128" + name.slice(6);
} else if (name === "ufixed") {
return "ufixed128x128";
}
return name;
}
function parseTypeN(type) {
return Number.parseInt(/^\D+(\d+)$/.exec(type)[1], 10);
}
function parseTypeNxM(type) {
var tmp = /^\D+(\d+)x(\d+)$/.exec(type);
return [Number.parseInt(tmp[1], 10), Number.parseInt(tmp[2], 10)];
}
function parseTypeArray(type) {
var tmp = type.match(/(.*)\[(.*?)\]$/);
if (tmp) {
return tmp[2] === "" ? "dynamic" : Number.parseInt(tmp[2], 10);
}
return null;
}
function parseNumber(arg) {
var type = typeof arg;
if (type === "string" || type === "number") {
return BigInt(arg);
} else if (type === "bigint") {
return arg;
} else {
throw new Error("Argument is not a number");
}
}
function encodeSingle(type, arg) {
var size, num, ret, i;
if (type === "address") {
return encodeSingle("uint160", parseNumber(arg));
} else if (type === "bool") {
return encodeSingle("uint8", arg ? 1 : 0);
} else if (type === "string") {
return encodeSingle("bytes", new Buffer(arg, "utf8"));
} else if (isArray(type)) {
if (typeof arg.length === "undefined") {
throw new Error("Not an array?");
}
size = parseTypeArray(type);
if (size !== "dynamic" && size !== 0 && arg.length > size) {
throw new Error("Elements exceed array size: " + size);
}
ret = [];
type = type.slice(0, type.lastIndexOf("["));
if (typeof arg === "string") {
arg = JSON.parse(arg);
}
for (i in arg) {
ret.push(encodeSingle(type, arg[i]));
}
if (size === "dynamic") {
var length = encodeSingle("uint256", arg.length);
ret.unshift(length);
}
return Buffer.concat(ret);
} else if (type === "bytes") {
arg = new Buffer(arg);
ret = Buffer.concat([encodeSingle("uint256", arg.length), arg]);
if (arg.length % 32 !== 0) {
ret = Buffer.concat([ret, util$1.zeros(32 - arg.length % 32)]);
}
return ret;
} else if (type.startsWith("bytes")) {
size = parseTypeN(type);
if (size < 1 || size > 32) {
throw new Error("Invalid bytes<N> width: " + size);
}
return util$1.setLengthRight(arg, 32);
} else if (type.startsWith("uint")) {
size = parseTypeN(type);
if (size % 8 || size < 8 || size > 256) {
throw new Error("Invalid uint<N> width: " + size);
}
num = parseNumber(arg);
const bitLength = util$1.bitLengthFromBigInt(num);
if (bitLength > size) {
throw new Error("Supplied uint exceeds width: " + size + " vs " + bitLength);
}
if (num < 0) {
throw new Error("Supplied uint is negative");
}
return util$1.bufferBEFromBigInt(num, 32);
} else if (type.startsWith("int")) {
size = parseTypeN(type);
if (size % 8 || size < 8 || size > 256) {
throw new Error("Invalid int<N> width: " + size);
}
num = parseNumber(arg);
const bitLength = util$1.bitLengthFromBigInt(num);
if (bitLength > size) {
throw new Error("Supplied int exceeds width: " + size + " vs " + bitLength);
}
const twos = util$1.twosFromBigInt(num, 256);
return util$1.bufferBEFromBigInt(twos, 32);
} else if (type.startsWith("ufixed")) {
size = parseTypeNxM(type);
num = parseNumber(arg);
if (num < 0) {
throw new Error("Supplied ufixed is negative");
}
return encodeSingle("uint256", num * BigInt(2) ** BigInt(size[1]));
} else if (type.startsWith("fixed")) {
size = parseTypeNxM(type);
return encodeSingle("int256", parseNumber(arg) * BigInt(2) ** BigInt(size[1]));
}
throw new Error("Unsupported or invalid type: " + type);
}
function isDynamic(type) {
return type === "string" || type === "bytes" || parseTypeArray(type) === "dynamic";
}
function isArray(type) {
return type.lastIndexOf("]") === type.length - 1;
}
function rawEncode(types, values) {
var output = [];
var data = [];
var headLength = 32 * types.length;
for (var i in types) {
var type = elementaryName(types[i]);
var value = values[i];
var cur = encodeSingle(type, value);
if (isDynamic(type)) {
output.push(encodeSingle("uint256", headLength));
data.push(cur);
headLength += cur.length;
} else {
output.push(cur);
}
}
return Buffer.concat(output.concat(data));
}
function solidityPack(types, values) {
if (types.length !== values.length) {
throw new Error("Number of types are not matching the values");
}
var size, num;
var ret = [];
for (var i = 0; i < types.length; i++) {
var type = elementaryName(types[i]);
var value = values[i];
if (type === "bytes") {
ret.push(value);
} else if (type === "string") {
ret.push(new Buffer(value, "utf8"));
} else if (type === "bool") {
ret.push(new Buffer(value ? "01" : "00", "hex"));
} else if (type === "address") {
ret.push(util$1.setLength(value, 20));
} else if (type.startsWith("bytes")) {
size = parseTypeN(type);
if (size < 1 || size > 32) {
throw new Error("Invalid bytes<N> width: " + size);
}
ret.push(util$1.setLengthRight(value, size));
} else if (type.startsWith("uint")) {
size = parseTypeN(type);
if (size % 8 || size < 8 || size > 256) {
throw new Error("Invalid uint<N> width: " + size);
}
num = parseNumber(value);
const bitLength = util$1.bitLengthFromBigInt(num);
if (bitLength > size) {
throw new Error("Supplied uint exceeds width: " + size + " vs " + bitLength);
}
ret.push(util$1.bufferBEFromBigInt(num, size / 8));
} else if (type.startsWith("int")) {
size = parseTypeN(type);
if (size % 8 || size < 8 || size > 256) {
throw new Error("Invalid int<N> width: " + size);
}
num = parseNumber(value);
const bitLength = util$1.bitLengthFromBigInt(num);
if (bitLength > size) {
throw new Error("Supplied int exceeds width: " + size + " vs " + bitLength);
}
const twos = util$1.twosFromBigInt(num, size);
ret.push(util$1.bufferBEFromBigInt(twos, size / 8));
} else {
throw new Error("Unsupported or invalid type: " + type);
}
}
return Buffer.concat(ret);
}
function soliditySHA3(types, values) {
return util$1.keccak(solidityPack(types, values));
}
var abi$1 = {
rawEncode,
solidityPack,
soliditySHA3
};
const util = util$2;
const abi = abi$1;
const TYPED_MESSAGE_SCHEMA = {
type: "object",
properties: {
types: {
type: "object",
additionalProperties: {
type: "array",
items: {
type: "object",
properties: {
name: { type: "string" },
type: { type: "string" }
},
required: ["name", "type"]
}
}
},
primaryType: { type: "string" },
domain: { type: "object" },
message: { type: "object" }
},
required: ["types", "primaryType", "domain", "message"]
};
const TypedDataUtils = {
/**
* Encodes an object by encoding and concatenating each of its members
*
* @param {string} primaryType - Root type
* @param {Object} data - Object to encode
* @param {Object} types - Type definitions
* @returns {string} - Encoded representation of an object
*/
encodeData(primaryType, data, types, useV4 = true) {
const encodedTypes = ["bytes32"];
const encodedValues = [this.hashType(primaryType, types)];
if (useV4) {
const encodeField = (name, type, value) => {
if (types[type] !== void 0) {
return ["bytes32", value == null ? "0x0000000000000000000000000000000000000000000000000000000000000000" : util.keccak(this.encodeData(type, value, types, useV4))];
}
if (value === void 0)
throw new Error(`missing value for field ${name} of type ${type}`);
if (type === "bytes") {
return ["bytes32", util.keccak(value)];
}
if (type === "string") {
if (typeof value === "string") {
value = Buffer.from(value, "utf8");
}
return ["bytes32", util.keccak(value)];
}
if (type.lastIndexOf("]") === type.length - 1) {
const parsedType = type.slice(0, type.lastIndexOf("["));
const typeValuePairs = value.map((item) => encodeField(name, parsedType, item));
return ["bytes32", util.keccak(abi.rawEncode(
typeValuePairs.map(([type2]) => type2),
typeValuePairs.map(([, value2]) => value2)
))];
}
return [type, value];
};
for (const field of types[primaryType]) {
const [type, value] = encodeField(field.name, field.type, data[field.name]);
encodedTypes.push(type);
encodedValues.push(value);
}
} else {
for (const field of types[primaryType]) {
let value = data[field.name];
if (value !== void 0) {
if (field.type === "bytes") {
encodedTypes.push("bytes32");
value = util.keccak(value);
encodedValues.push(value);
} else if (field.type === "string") {
encodedTypes.push("bytes32");
if (typeof value === "string") {
value = Buffer.from(value, "utf8");
}
value = util.keccak(value);
encodedValues.push(value);
} else if (types[field.type] !== void 0) {
encodedTypes.push("bytes32");
value = util.keccak(this.encodeData(field.type, value, types, useV4));
encodedValues.push(value);
} else if (field.type.lastIndexOf("]") === field.type.length - 1) {
throw new Error("Arrays currently unimplemented in encodeData");
} else {
encodedTypes.push(field.type);
encodedValues.push(value);
}
}
}
}
return abi.rawEncode(encodedTypes, encodedValues);
},
/**
* Encodes the type of an object by encoding a comma delimited list of its members
*
* @param {string} primaryType - Root type to encode
* @param {Object} types - Type definitions
* @returns {string} - Encoded representation of the type of an object
*/
encodeType(primaryType, types) {
let result = "";
let deps = this.findTypeDependencies(primaryType, types).filter((dep) => dep !== primaryType);
deps = [primaryType].concat(deps.sort());
for (const type of deps) {
const children = types[type];
if (!children) {
throw new Error("No type definition specified: " + type);
}
result += type + "(" + types[type].map(({ name, type: type2 }) => type2 + " " + name).join(",") + ")";
}
return result;
},
/**
* Finds all types within a type definition object
*
* @param {string} primaryType - Root type
* @param {Object} types - Type definitions
* @param {Array} results - current set of accumulated types
* @returns {Array} - Set of all types found in the type definition
*/
findTypeDependencies(primaryType, types, results = []) {
primaryType = primaryType.match(/^\w*/)[0];
if (results.includes(primaryType) || types[primaryType] === void 0) {
return results;
}
results.push(primaryType);
for (const field of types[primaryType]) {
for (const dep of this.findTypeDependencies(field.type, types, results)) {
!results.includes(dep) && results.push(dep);
}
}
return results;
},
/**
* Hashes an object
*
* @param {string} primaryType - Root type
* @param {Object} data - Object to hash
* @param {Object} types - Type definitions
* @returns {Buffer} - Hash of an object
*/
hashStruct(primaryType, data, types, useV4 = true) {
return util.keccak(this.encodeData(primaryType, data, types, useV4));
},
/**
* Hashes the type of an object
*
* @param {string} primaryType - Root type to hash
* @param {Object} types - Type definitions
* @returns {string} - Hash of an object
*/
hashType(primaryType, types) {
return util.keccak(this.encodeType(primaryType, types));
},
/**
* Removes properties from a message object that are not defined per EIP-712
*
* @param {Object} data - typed message object
* @returns {Object} - typed message object with only allowed fields
*/
sanitizeData(data) {
const sanitizedData = {};
for (const key in TYPED_MESSAGE_SCHEMA.properties) {
data[key] && (sanitizedData[key] = data[key]);
}
if (sanitizedData.types) {
sanitizedData.types = Object.assign({ EIP712Domain: [] }, sanitizedData.types);
}
return sanitizedData;
},
/**
* Returns the hash of a typed message as per EIP-712 for signing
*
* @param {Object} typedData - Types message data to sign
* @returns {string} - sha3 hash for signing
*/
hash(typedData, useV4 = true) {
const sanitizedData = this.sanitizeData(typedData);
const parts = [Buffer.from("1901", "hex")];
parts.push(this.hashStruct("EIP712Domain", sanitizedData.domain, sanitizedData.types, useV4));
if (sanitizedData.primaryType !== "EIP712Domain") {
parts.push(this.hashStruct(sanitizedData.primaryType, sanitizedData.message, sanitizedData.types, useV4));
}
return util.keccak(Buffer.concat(parts));
}
};
var ethEip712Util = {
TYPED_MESSAGE_SCHEMA,
TypedDataUtils,
hashForSignTypedDataLegacy: function(msgParams) {
return typedSignatureHashLegacy(msgParams.data);
},
hashForSignTypedData_v3: function(msgParams) {
return TypedDataUtils.hash(msgParams.data, false);
},
hashForSignTypedData_v4: function(msgParams) {
return TypedDataUtils.hash(msgParams.data);
}
};
function typedSignatureHashLegacy(typedData) {
const error = new Error("Expect argument to be non-empty array");
if (typeof typedData !== "object" || !typedData.length) throw error;
const data = typedData.map(function(e) {
return e.type === "bytes" ? util.toBuffer(e.value) : e.value;
});
const types = typedData.map(function(e) {
return e.type;
});
const schema = typedData.map(function(e) {
if (!e.name) throw error;
return e.type + " " + e.name;
});
return abi.soliditySHA3(
["bytes32", "bytes32"],
[
abi.soliditySHA3(new Array(typedData.length).fill("string"), schema),
abi.soliditySHA3(types, data)
]
);
}
const eip712 = /* @__PURE__ */ getDefaultExportFromCjs(ethEip712Util);
const WALLET_USER_NAME_KEY = "walletUsername";
const LOCAL_STORAGE_ADDRESSES_KEY = "Addresses";
const APP_VERSION_KEY = "AppVersion";
function isErrorResponse(response) {
return response.errorMessage !== void 0;
}
class WalletLinkCipher {
// @param secret hex representation of 32-byte secret
constructor(secret) {
this.secret = secret;
}
/**
*
* @param plainText string to be encrypted
* returns hex string representation of bytes in the order: initialization vector (iv),
* auth tag, encrypted plaintext. IV is 12 bytes. Auth tag is 16 bytes. Remaining bytes are the
* encrypted plainText.
*/
async encrypt(plainText) {
const secret = this.secret;
if (secret.length !== 64)
throw Error(`secret must be 256 bits`);
const ivBytes = crypto.getRandomValues(new Uint8Array(12));
const secretKey = await crypto.subtle.importKey("raw", hexStringToUint8Array(secret), { name: "aes-gcm" }, false, ["encrypt", "decrypt"]);
const enc = new TextEncoder();
const encryptedResult = await window.crypto.subtle.encrypt({
name: "AES-GCM",
iv: ivBytes
}, secretKey, enc.encode(plainText));
const tagLength = 16;
const authTag = encryptedResult.slice(encryptedResult.byteLength - tagLength);
const encryptedPlaintext = encryptedResult.slice(0, encryptedResult.byteLength - tagLength);
const authTagBytes = new Uint8Array(authTag);
const encryptedPlaintextBytes = new Uint8Array(encryptedPlaintext);
const concatted = new Uint8Array([...ivBytes, ...authTagBytes, ...encryptedPlaintextBytes]);
return uint8ArrayToHex(concatted);
}
/**
*
* @param cipherText hex string representation of bytes in the order: initialization vector (iv),
* auth tag, encrypted plaintext. IV is 12 bytes. Auth tag is 16 bytes.
*/
async decrypt(cipherText) {
const secret = this.secret;
if (secret.length !== 64)
throw Error(`secret must be 256 bits`);
return new Promise((resolve, reject) => {
void async function() {
const secretKey = await crypto.subtle.importKey("raw", hexStringToUint8Array(secret), { name: "aes-gcm" }, false, ["encrypt", "decrypt"]);
const encrypted = hexStringToUint8Array(cipherText);
const ivBytes = encrypted.slice(0, 12);
const authTagBytes = encrypted.slice(12, 28);
const encryptedPlaintextBytes = encrypted.slice(28);
const concattedBytes = new Uint8Array([...encryptedPlaintextBytes, ...authTagBytes]);
const algo = {
name: "AES-GCM",
iv: new Uint8Array(ivBytes)
};
try {
const decrypted = await window.crypto.subtle.decrypt(algo, secretKey, concattedBytes);
const decoder = new TextDecoder();
resolve(decoder.decode(decrypted));
} catch (err) {
reject(err);
}
}();
});
}
}
class WalletLinkHTTP {
constructor(linkAPIUrl, sessionId, sessionKey) {
this.linkAPIUrl = linkAPIUrl;
this.sessionId = sessionId;
const credentials = `${sessionId}:${sessionKey}`;
this.auth = `Basic ${btoa(credentials)}`;
}
// mark unseen events as seen
async markUnseenEventsAsSeen(events) {
return Pro