FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

View File

@@ -0,0 +1,7 @@
import { RequestArguments } from '../core/provider/interface.js';
export interface Signer {
handshake(_: RequestArguments): Promise<void>;
request<T>(_: RequestArguments): Promise<T>;
cleanup: () => Promise<void>;
}
//# sourceMappingURL=interface.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/sign/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE/D,MAAM,WAAW,MAAM;IACrB,SAAS,CAAC,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5C,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=interface.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/sign/interface.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,16 @@
export declare class SCWKeyManager {
private readonly storage;
private ownPrivateKey;
private ownPublicKey;
private peerPublicKey;
private sharedSecret;
getOwnPublicKey(): Promise<CryptoKey>;
getSharedSecret(): Promise<CryptoKey | null>;
setPeerPublicKey(key: CryptoKey): Promise<void>;
clear(): Promise<void>;
private generateKeyPair;
private loadKeysIfNeeded;
private loadKey;
private storeKey;
}
//# sourceMappingURL=SCWKeyManager.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"SCWKeyManager.d.ts","sourceRoot":"","sources":["../../../src/sign/scw/SCWKeyManager.ts"],"names":[],"mappings":"AAyBA,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqD;IAC7E,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,YAAY,CAA0B;IAExC,eAAe,IAAI,OAAO,CAAC,SAAS,CAAC;IAMrC,eAAe,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAK5C,gBAAgB,CAAC,GAAG,EAAE,SAAS;IAO/B,KAAK;YAWG,eAAe;YAQf,gBAAgB;YAyBhB,OAAO;YAOP,QAAQ;CAIvB"}

View File

@@ -0,0 +1,85 @@
import { ScopedLocalStorage } from '../../core/storage/ScopedLocalStorage.js';
import { deriveSharedSecret, exportKeyToHexString, generateKeyPair, importKeyFromHexString, } from '../../util/cipher.js';
const OWN_PRIVATE_KEY = {
storageKey: 'ownPrivateKey',
keyType: 'private',
};
const OWN_PUBLIC_KEY = {
storageKey: 'ownPublicKey',
keyType: 'public',
};
const PEER_PUBLIC_KEY = {
storageKey: 'peerPublicKey',
keyType: 'public',
};
export 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);
}
}
//# sourceMappingURL=SCWKeyManager.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"SCWKeyManager.js","sourceRoot":"","sources":["../../../src/sign/scw/SCWKeyManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AAMzB,MAAM,eAAe,GAAG;IACtB,UAAU,EAAE,eAAe;IAC3B,OAAO,EAAE,SAAS;CACV,CAAC;AACX,MAAM,cAAc,GAAG;IACrB,UAAU,EAAE,cAAc;IAC1B,OAAO,EAAE,QAAQ;CACT,CAAC;AACX,MAAM,eAAe,GAAG;IACtB,UAAU,EAAE,eAAe;IAC3B,OAAO,EAAE,QAAQ;CACT,CAAC;AAEX,MAAM,OAAO,aAAa;IAA1B;QACmB,YAAO,GAAG,IAAI,kBAAkB,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QACrE,kBAAa,GAAqB,IAAI,CAAC;QACvC,iBAAY,GAAqB,IAAI,CAAC;QACtC,kBAAa,GAAqB,IAAI,CAAC;QACvC,iBAAY,GAAqB,IAAI,CAAC;IA2EhD,CAAC;IAzEC,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,YAAa,CAAC;IAC5B,CAAC;IAED,uDAAuD;IACvD,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,GAAc;QACnC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC;QACzB,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;QAC1C,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAEzB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;IACtD,CAAC;IAEO,KAAK,CAAC,eAAe;QAC3B,MAAM,UAAU,GAAG,MAAM,eAAe,EAAE,CAAC;QAC3C,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,UAAU,CAAC;QAC3C,IAAI,CAAC,YAAY,GAAG,UAAU,CAAC,SAAS,CAAC;QACzC,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;QAC5D,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC;IAEO,KAAK,CAAC,gBAAgB;QAC5B,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YAChC,IAAI,CAAC,aAAa,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC3D,CAAC;QAED,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YAC/B,IAAI,CAAC,YAAY,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACzD,CAAC;QAED,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YAC9D,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC/B,CAAC;QAED,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YAChC,IAAI,CAAC,aAAa,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC3D,CAAC;QAED,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YAC/B,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI;gBAAE,OAAO;YACvE,IAAI,CAAC,YAAY,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,kBAAkB;IAEV,KAAK,CAAC,OAAO,CAAC,IAAiB;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClD,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QAEtB,OAAO,sBAAsB,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,IAAiB,EAAE,GAAc;QACtD,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAChE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC;CACF"}

View File

@@ -0,0 +1,34 @@
import { Signer } from '../interface.js';
import { Communicator } from '../../core/communicator/Communicator.js';
import { AppMetadata, ProviderEventCallback, RequestArguments } from '../../core/provider/interface.js';
type ConstructorOptions = {
metadata: AppMetadata;
communicator: Communicator;
callback: ProviderEventCallback | null;
};
export declare class SCWSigner implements Signer {
private readonly metadata;
private readonly communicator;
private readonly keyManager;
private readonly storage;
private callback;
private accounts;
private chain;
constructor(params: ConstructorOptions);
handshake(args: RequestArguments): Promise<void>;
request(request: RequestArguments): Promise<any>;
private sendRequestToPopup;
cleanup(): Promise<void>;
/**
* @returns `null` if the request was successful.
* https://eips.ethereum.org/EIPS/eip-3326#wallet_switchethereumchain
*/
private handleSwitchChainRequest;
private handleGetCapabilitiesRequest;
private sendEncryptedRequest;
private createRequestMessage;
private decryptResponseMessage;
private updateChain;
}
export {};
//# sourceMappingURL=SCWSigner.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"SCWSigner.d.ts","sourceRoot":"","sources":["../../../src/sign/scw/SCWSigner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAGzC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAIlE,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAsBnG,KAAK,kBAAkB,GAAG;IACxB,QAAQ,EAAE,WAAW,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACxC,CAAC;AAEF,qBAAa,SAAU,YAAW,MAAM;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAA+B;IAE/C,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,KAAK,CAAQ;gBAET,MAAM,EAAE,kBAAkB;IAkBhC,SAAS,CAAC,IAAI,EAAE,gBAAgB;IAmChC,OAAO,CAAC,OAAO,EAAE,gBAAgB;YAgDzB,kBAAkB;IAc1B,OAAO;IASb;;;OAGG;YACW,wBAAwB;YAqBxB,4BAA4B;YA6C5B,oBAAoB;YAoBpB,oBAAoB;YAYpB,sBAAsB;IAiCpC,OAAO,CAAC,WAAW;CAapB"}

View File

@@ -0,0 +1,243 @@
import { hexToNumber, isAddressEqual } from 'viem';
import { SCWKeyManager } from './SCWKeyManager.js';
import { assertGetCapabilitiesParams } from './utils.js';
import { standardErrors } from '../../core/error/errors.js';
import { ScopedLocalStorage } from '../../core/storage/ScopedLocalStorage.js';
import { ensureIntNumber, hexStringFromNumber } from '../../core/type/util.js';
import { decryptContent, encryptContent, exportKeyToHexString, importKeyFromHexString, } from '../../util/cipher.js';
import { fetchRPCRequest } from '../../util/provider.js';
const ACCOUNTS_KEY = 'accounts';
const ACTIVE_CHAIN_STORAGE_KEY = 'activeChain';
const AVAILABLE_CHAINS_STORAGE_KEY = 'availableChains';
const WALLET_CAPABILITIES_STORAGE_KEY = 'walletCapabilities';
export 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;
// Open the popup before constructing the request message.
// This is to ensure that the popup is not blocked by some browsers (i.e. Safari)
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);
// store peer's public key
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.handleGetCapabilitiesRequest(request);
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;
// Open the popup before constructing the request message.
// This is to ensure that the popup is not blocked by some browsers (i.e. Safari)
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 handleGetCapabilitiesRequest(request) {
assertGetCapabilitiesParams(request.params);
const requestedAccount = request.params[0];
const filterChainIds = request.params[1]; // Optional second parameter
if (!this.accounts.some((account) => isAddressEqual(account, requestedAccount))) {
throw standardErrors.provider.unauthorized('no active account found');
}
const capabilities = this.storage.loadObject(WALLET_CAPABILITIES_STORAGE_KEY);
// Return empty object if capabilities is undefined
if (!capabilities) {
return {};
}
// If no filter is provided, return all capabilities
if (!filterChainIds || filterChainIds.length === 0) {
return capabilities;
}
// Convert filter chain IDs to numbers once for efficient lookup
const filterChainNumbers = new Set(filterChainIds.map((chainId) => hexToNumber(chainId)));
// Filter capabilities
const filteredCapabilities = Object.fromEntries(Object.entries(capabilities).filter(([capabilityKey]) => {
try {
const capabilityChainNumber = hexToNumber(capabilityKey);
return filterChainNumbers.has(capabilityChainNumber);
}
catch (_a) {
// If capabilityKey is not a valid hex string, exclude it
return false;
}
}));
return filteredCapabilities;
}
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: new Date(),
};
}
async decryptResponseMessage(message) {
var _a, _b;
const content = message.content;
// throw protocol level error
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((chain) => chain.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;
}
}
//# sourceMappingURL=SCWSigner.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export declare function assertGetCapabilitiesParams(params: unknown): asserts params is [`0x${string}`, `0x${string}`[]?];
//# sourceMappingURL=utils.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/sign/scw/utils.ts"],"names":[],"mappings":"AAIA,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,EAAE,KAAK,MAAM,EAAE,EAAE,CAAC,CAAC,CAoBrD"}

View File

@@ -0,0 +1,21 @@
import { isAddress } from 'viem';
import { standardErrors } from '../../core/error/errors.js';
export function assertGetCapabilitiesParams(params) {
if (!params || !Array.isArray(params) || (params.length !== 1 && params.length !== 2)) {
throw standardErrors.rpc.invalidParams();
}
if (typeof params[0] !== 'string' || !isAddress(params[0])) {
throw standardErrors.rpc.invalidParams();
}
if (params.length === 2) {
if (!Array.isArray(params[1])) {
throw standardErrors.rpc.invalidParams();
}
for (const param of params[1]) {
if (typeof param !== 'string' || !param.startsWith('0x')) {
throw standardErrors.rpc.invalidParams();
}
}
}
}
//# sourceMappingURL=utils.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/sign/scw/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,UAAU,2BAA2B,CACzC,MAAe;IAEf,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QACtF,MAAM,cAAc,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC3C,CAAC;IAED,IAAI,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,MAAM,cAAc,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC3C,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9B,MAAM,cAAc,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC3C,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzD,MAAM,cAAc,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YAC3C,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}

20
node_modules/@coinbase/wallet-sdk/dist/sign/util.d.ts generated vendored Normal file
View File

@@ -0,0 +1,20 @@
import { Signer } from './interface.js';
import { Communicator } from '../core/communicator/Communicator.js';
import { SignerType } from '../core/message/ConfigMessage.js';
import { AppMetadata, Preference, ProviderEventCallback, RequestArguments } from '../core/provider/interface.js';
export declare function loadSignerType(): SignerType | null;
export declare function storeSignerType(signerType: SignerType): void;
export declare function fetchSignerType(params: {
communicator: Communicator;
preference: Preference;
metadata: AppMetadata;
handshakeRequest: RequestArguments;
callback: ProviderEventCallback;
}): Promise<SignerType>;
export declare function createSigner(params: {
signerType: SignerType;
metadata: AppMetadata;
communicator: Communicator;
callback: ProviderEventCallback;
}): Signer;
//# sourceMappingURL=util.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/sign/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAGxC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAiB,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAE3E,OAAO,EACL,WAAW,EACX,UAAU,EACV,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,6BAA6B,CAAC;AAMrC,wBAAgB,cAAc,IAAI,UAAU,GAAG,IAAI,CAElD;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,QAErD;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,WAAW,CAAC;IACtB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,QAAQ,EAAE,qBAAqB,CAAC;CACjC,GAAG,OAAO,CAAC,UAAU,CAAC,CActB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE;IACnC,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,WAAW,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,qBAAqB,CAAC;CACjC,GAAG,MAAM,CAiBT"}

62
node_modules/@coinbase/wallet-sdk/dist/sign/util.js generated vendored Normal file
View File

@@ -0,0 +1,62 @@
import { SCWSigner } from './scw/SCWSigner.js';
import { WalletLinkSigner } from './walletlink/WalletLinkSigner.js';
import { ScopedLocalStorage } from '../core/storage/ScopedLocalStorage.js';
const SIGNER_TYPE_KEY = 'SignerType';
const storage = new ScopedLocalStorage('CBWSDK', 'SignerConfigurator');
export function loadSignerType() {
return storage.getItem(SIGNER_TYPE_KEY);
}
export function storeSignerType(signerType) {
storage.setItem(SIGNER_TYPE_KEY, signerType);
}
export async function fetchSignerType(params) {
const { communicator, metadata, handshakeRequest, callback } = params;
listenForWalletLinkSessionRequest(communicator, metadata, callback).catch(() => { });
const request = {
id: crypto.randomUUID(),
event: 'selectSignerType',
data: Object.assign(Object.assign({}, params.preference), { handshakeRequest }),
};
const { data } = await communicator.postRequestAndWaitForResponse(request);
return data;
}
export function createSigner(params) {
const { signerType, metadata, communicator, callback } = params;
switch (signerType) {
case 'scw': {
return new SCWSigner({
metadata,
callback,
communicator,
});
}
case 'walletlink': {
return new WalletLinkSigner({
metadata,
callback,
});
}
}
}
async function listenForWalletLinkSessionRequest(communicator, metadata, callback) {
await communicator.onMessage(({ event }) => event === 'WalletLinkSessionRequest');
// temporary walletlink signer instance to handle WalletLinkSessionRequest
// will revisit this when refactoring the walletlink signer
const walletlink = new WalletLinkSigner({
metadata,
callback,
});
// send wallet link session to popup
communicator.postMessage({
event: 'WalletLinkUpdate',
data: { session: walletlink.getSession() },
});
// wait for handshake to complete
await walletlink.handshake();
// send connected status to popup
communicator.postMessage({
event: 'WalletLinkUpdate',
data: { connected: true },
});
}
//# sourceMappingURL=util.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/sign/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAUpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAEzE,MAAM,eAAe,GAAG,YAAY,CAAC;AACrC,MAAM,OAAO,GAAG,IAAI,kBAAkB,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;AAEvE,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAC,OAAO,CAAC,eAAe,CAAe,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,UAAsB;IACpD,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAMrC;IACC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IACtE,iCAAiC,CAAC,YAAY,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAEpF,MAAM,OAAO,GAAsC;QACjD,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;QACvB,KAAK,EAAE,kBAAkB;QACzB,IAAI,kCACC,MAAM,CAAC,UAAU,KACpB,gBAAgB,GACjB;KACF,CAAC;IACF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,YAAY,CAAC,6BAA6B,CAAC,OAAO,CAAC,CAAC;IAC3E,OAAO,IAAkB,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAK5B;IACC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAChE,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,OAAO,IAAI,SAAS,CAAC;gBACnB,QAAQ;gBACR,QAAQ;gBACR,YAAY;aACb,CAAC,CAAC;QACL,CAAC;QACD,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,OAAO,IAAI,gBAAgB,CAAC;gBAC1B,QAAQ;gBACR,QAAQ;aACT,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iCAAiC,CAC9C,YAA0B,EAC1B,QAAqB,EACrB,QAA+B;IAE/B,MAAM,YAAY,CAAC,SAAS,CAAgB,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,KAAK,0BAA0B,CAAC,CAAC;IAEjG,0EAA0E;IAC1E,2DAA2D;IAC3D,MAAM,UAAU,GAAG,IAAI,gBAAgB,CAAC;QACtC,QAAQ;QACR,QAAQ;KACT,CAAC,CAAC;IAEH,oCAAoC;IACpC,YAAY,CAAC,WAAW,CAAC;QACvB,KAAK,EAAE,kBAAkB;QACzB,IAAI,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,UAAU,EAAE,EAAE;KAC1B,CAAC,CAAC;IAEpB,iCAAiC;IACjC,MAAM,UAAU,CAAC,SAAS,EAAE,CAAC;IAE7B,iCAAiC;IACjC,YAAY,CAAC,WAAW,CAAC;QACvB,KAAK,EAAE,kBAAkB;QACzB,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;KACT,CAAC,CAAC;AACtB,CAAC"}

View File

@@ -0,0 +1,40 @@
import { Signer } from '../interface.js';
import { AppMetadata, ProviderEventCallback, RequestArguments } from '../../core/provider/interface.js';
export declare class WalletLinkSigner implements Signer {
private metadata;
private _relay;
private readonly _storage;
private _addresses;
private callback;
constructor(options: {
metadata: AppMetadata;
callback?: ProviderEventCallback;
});
getSession(): {
id: string;
secret: string;
};
handshake(): Promise<void>;
private get selectedAddress();
private get jsonRpcUrl();
private set jsonRpcUrl(value);
private updateProviderInfo;
private watchAsset;
private addEthereumChain;
private switchEthereumChain;
cleanup(): Promise<void>;
private _setAddresses;
request(request: RequestArguments): Promise<any>;
private _ensureKnownAddress;
private _prepareTransactionParams;
private ecRecover;
private getChainId;
private _eth_requestAccounts;
private personalSign;
private _eth_signTransaction;
private _eth_sendRawTransaction;
private _eth_sendTransaction;
private signTypedData;
private initializeRelay;
}
//# sourceMappingURL=WalletLinkSigner.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkSigner.d.ts","sourceRoot":"","sources":["../../../src/sign/walletlink/WalletLinkSigner.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAOzC,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAoBnG,qBAAa,gBAAiB,YAAW,MAAM;IAC7C,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,QAAQ,CAA+B;gBAEnC,OAAO,EAAE;QAAE,QAAQ,EAAE,WAAW,CAAC;QAAC,QAAQ,CAAC,EAAE,qBAAqB,CAAA;KAAE;IAgBhF,UAAU;;;;IAMJ,SAAS;IAIf,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,KAAK,UAAU,QAErB;IAED,OAAO,CAAC,kBAAkB;YAYZ,UAAU;YA4CV,gBAAgB;YA4DhB,mBAAmB;IAsBpB,OAAO;IAQpB,OAAO,CAAC,aAAa;IAgBf,OAAO,CAAC,OAAO,EAAE,gBAAgB;IAqDvC,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,yBAAyB;YA4CnB,SAAS;IAiBvB,OAAO,CAAC,UAAU;YAIJ,oBAAoB;YAmBpB,YAAY;YAsBZ,oBAAoB;YASpB,uBAAuB;YAQvB,oBAAoB;YASpB,aAAa;IAsC3B,OAAO,CAAC,eAAe;CAYxB"}

View File

@@ -0,0 +1,346 @@
// Copyright (c) 2018-2024 Coinbase, Inc. <https://www.coinbase.com/>
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import eip712 from '../../vendor-js/eth-eip712-util/index.cjs';
import { LOCAL_STORAGE_ADDRESSES_KEY } from './relay/constants.js';
import { isErrorResponse } from './relay/type/Web3Response.js';
import { WalletLinkRelay } from './relay/WalletLinkRelay.js';
import { WALLETLINK_URL } from '../../core/constants.js';
import { standardErrors } from '../../core/error/errors.js';
import { ScopedLocalStorage } from '../../core/storage/ScopedLocalStorage.js';
import { encodeToHexString, ensureAddressString, ensureBigInt, ensureBuffer, ensureIntNumber, ensureParsedJSONObject, hexStringFromBuffer, hexStringFromNumber, } from '../../core/type/util.js';
import { fetchRPCRequest } from '../../util/provider.js';
const DEFAULT_CHAIN_ID_KEY = 'DefaultChainId';
const DEFAULT_JSON_RPC_URL = 'DefaultJsonRpcUrl';
// original source: https://github.com/coinbase/coinbase-wallet-sdk/blob/v3.7.1/packages/wallet-sdk/src/provider/CoinbaseWalletProvider.ts
export class WalletLinkSigner {
constructor(options) {
this._relay = null;
this._addresses = [];
this.metadata = options.metadata;
this._storage = new ScopedLocalStorage('walletlink', WALLETLINK_URL);
this.callback = options.callback || null;
const cachedAddresses = this._storage.getItem(LOCAL_STORAGE_ADDRESSES_KEY);
if (cachedAddresses) {
const addresses = cachedAddresses.split(' ');
if (addresses[0] !== '') {
this._addresses = addresses.map((address) => ensureAddressString(address));
}
}
this.initializeRelay();
}
getSession() {
const relay = this.initializeRelay();
const { id, secret } = relay.getWalletLinkSession();
return { id, secret };
}
async handshake() {
await this._eth_requestAccounts();
}
get selectedAddress() {
return this._addresses[0] || undefined;
}
get jsonRpcUrl() {
var _a;
return (_a = this._storage.getItem(DEFAULT_JSON_RPC_URL)) !== null && _a !== void 0 ? _a : undefined;
}
set jsonRpcUrl(value) {
this._storage.setItem(DEFAULT_JSON_RPC_URL, value);
}
updateProviderInfo(jsonRpcUrl, chainId) {
var _a;
this.jsonRpcUrl = jsonRpcUrl;
// emit chainChanged event if necessary
const originalChainId = this.getChainId();
this._storage.setItem(DEFAULT_CHAIN_ID_KEY, chainId.toString(10));
const chainChanged = ensureIntNumber(chainId) !== originalChainId;
if (chainChanged) {
(_a = this.callback) === null || _a === void 0 ? void 0 : _a.call(this, 'chainChanged', hexStringFromNumber(chainId));
}
}
async watchAsset(params) {
const request = (Array.isArray(params) ? params[0] : params);
if (!request.type) {
throw standardErrors.rpc.invalidParams('Type is required');
}
if ((request === null || request === void 0 ? void 0 : request.type) !== 'ERC20') {
throw standardErrors.rpc.invalidParams(`Asset of type '${request.type}' is not supported`);
}
if (!(request === null || request === void 0 ? void 0 : request.options)) {
throw standardErrors.rpc.invalidParams('Options are required');
}
if (!(request === null || request === void 0 ? void 0 : request.options.address)) {
throw standardErrors.rpc.invalidParams('Address is required');
}
const chainId = this.getChainId();
const { address, symbol, image, decimals } = request.options;
const relay = this.initializeRelay();
const result = await relay.watchAsset(request.type, address, symbol, decimals, image, chainId === null || chainId === void 0 ? void 0 : chainId.toString());
if (isErrorResponse(result))
return false;
return !!result.result;
}
async addEthereumChain(params) {
var _a, _b;
const request = params[0];
if (((_a = request.rpcUrls) === null || _a === void 0 ? void 0 : _a.length) === 0) {
throw standardErrors.rpc.invalidParams('please pass in at least 1 rpcUrl');
}
if (!request.chainName || request.chainName.trim() === '') {
throw standardErrors.rpc.invalidParams('chainName is a required field');
}
if (!request.nativeCurrency) {
throw standardErrors.rpc.invalidParams('nativeCurrency is a required field');
}
const chainIdNumber = Number.parseInt(request.chainId, 16);
if (chainIdNumber === this.getChainId()) {
return false;
}
const relay = this.initializeRelay();
const { rpcUrls = [], blockExplorerUrls = [], chainName, iconUrls = [], nativeCurrency, } = request;
const res = await relay.addEthereumChain(chainIdNumber.toString(), rpcUrls, iconUrls, blockExplorerUrls, chainName, nativeCurrency);
if (isErrorResponse(res))
return false;
if (((_b = res.result) === null || _b === void 0 ? void 0 : _b.isApproved) === true) {
this.updateProviderInfo(rpcUrls[0], chainIdNumber);
return null;
}
throw standardErrors.rpc.internal('unable to add ethereum chain');
}
async switchEthereumChain(params) {
const request = params[0];
const chainId = Number.parseInt(request.chainId, 16);
const relay = this.initializeRelay();
const res = await relay.switchEthereumChain(chainId.toString(10), this.selectedAddress || undefined);
if (isErrorResponse(res))
throw res;
const switchResponse = res.result;
if (switchResponse.isApproved && switchResponse.rpcUrl.length > 0) {
this.updateProviderInfo(switchResponse.rpcUrl, chainId);
}
return null;
}
async cleanup() {
this.callback = null;
if (this._relay) {
this._relay.resetAndReload();
}
this._storage.clear();
}
_setAddresses(addresses, _) {
var _a;
if (!Array.isArray(addresses)) {
throw new Error('addresses is not an array');
}
const newAddresses = addresses.map((address) => ensureAddressString(address));
if (JSON.stringify(newAddresses) === JSON.stringify(this._addresses)) {
return;
}
this._addresses = newAddresses;
(_a = this.callback) === null || _a === void 0 ? void 0 : _a.call(this, 'accountsChanged', newAddresses);
this._storage.setItem(LOCAL_STORAGE_ADDRESSES_KEY, newAddresses.join(' '));
}
async request(request) {
const params = request.params || [];
switch (request.method) {
case 'eth_accounts':
return [...this._addresses];
case 'eth_coinbase':
return this.selectedAddress || null;
case 'net_version':
return this.getChainId().toString(10);
case 'eth_chainId':
return hexStringFromNumber(this.getChainId());
case 'eth_requestAccounts':
return this._eth_requestAccounts();
case 'eth_ecRecover':
case 'personal_ecRecover':
return this.ecRecover(request);
case 'personal_sign':
return this.personalSign(request);
case 'eth_signTransaction':
return this._eth_signTransaction(params);
case 'eth_sendRawTransaction':
return this._eth_sendRawTransaction(params);
case 'eth_sendTransaction':
return this._eth_sendTransaction(params);
case 'eth_signTypedData_v1':
case 'eth_signTypedData_v3':
case 'eth_signTypedData_v4':
case 'eth_signTypedData':
return this.signTypedData(request);
case 'wallet_addEthereumChain':
return this.addEthereumChain(params);
case 'wallet_switchEthereumChain':
return this.switchEthereumChain(params);
case 'wallet_watchAsset':
return this.watchAsset(params);
default:
if (!this.jsonRpcUrl)
throw standardErrors.rpc.internal('No RPC URL set for chain');
return fetchRPCRequest(request, this.jsonRpcUrl);
}
}
_ensureKnownAddress(addressString) {
const addressStr = ensureAddressString(addressString);
const lowercaseAddresses = this._addresses.map((address) => ensureAddressString(address));
if (!lowercaseAddresses.includes(addressStr)) {
throw new Error('Unknown Ethereum address');
}
}
_prepareTransactionParams(tx) {
const fromAddress = tx.from ? ensureAddressString(tx.from) : this.selectedAddress;
if (!fromAddress) {
throw new Error('Ethereum address is unavailable');
}
this._ensureKnownAddress(fromAddress);
const toAddress = tx.to ? ensureAddressString(tx.to) : null;
const weiValue = tx.value != null ? ensureBigInt(tx.value) : BigInt(0);
const data = tx.data ? ensureBuffer(tx.data) : Buffer.alloc(0);
const nonce = tx.nonce != null ? ensureIntNumber(tx.nonce) : null;
const gasPriceInWei = tx.gasPrice != null ? ensureBigInt(tx.gasPrice) : null;
const maxFeePerGas = tx.maxFeePerGas != null ? ensureBigInt(tx.maxFeePerGas) : null;
const maxPriorityFeePerGas = tx.maxPriorityFeePerGas != null ? ensureBigInt(tx.maxPriorityFeePerGas) : null;
const gasLimit = tx.gas != null ? ensureBigInt(tx.gas) : null;
const chainId = tx.chainId ? ensureIntNumber(tx.chainId) : this.getChainId();
return {
fromAddress,
toAddress,
weiValue,
data,
nonce,
gasPriceInWei,
maxFeePerGas,
maxPriorityFeePerGas,
gasLimit,
chainId,
};
}
async ecRecover(request) {
const { method, params } = request;
if (!Array.isArray(params))
throw standardErrors.rpc.invalidParams();
const relay = this.initializeRelay();
const res = await relay.sendRequest({
method: 'ethereumAddressFromSignedMessage',
params: {
message: encodeToHexString(params[0]),
signature: encodeToHexString(params[1]),
addPrefix: method === 'personal_ecRecover',
},
});
if (isErrorResponse(res))
throw res;
return res.result;
}
getChainId() {
var _a;
return Number.parseInt((_a = this._storage.getItem(DEFAULT_CHAIN_ID_KEY)) !== null && _a !== void 0 ? _a : '1', 10);
}
async _eth_requestAccounts() {
var _a, _b;
if (this._addresses.length > 0) {
(_a = this.callback) === null || _a === void 0 ? void 0 : _a.call(this, 'connect', { chainId: hexStringFromNumber(this.getChainId()) });
return this._addresses;
}
const relay = this.initializeRelay();
const res = await relay.requestEthereumAccounts();
if (isErrorResponse(res))
throw res;
if (!res.result) {
throw new Error('accounts received is empty');
}
this._setAddresses(res.result);
(_b = this.callback) === null || _b === void 0 ? void 0 : _b.call(this, 'connect', { chainId: hexStringFromNumber(this.getChainId()) });
return this._addresses;
}
async personalSign({ params }) {
if (!Array.isArray(params))
throw standardErrors.rpc.invalidParams();
const address = params[1];
const rawData = params[0];
this._ensureKnownAddress(address);
const relay = this.initializeRelay();
const res = await relay.sendRequest({
method: 'signEthereumMessage',
params: {
address: ensureAddressString(address),
message: encodeToHexString(rawData),
addPrefix: true,
typedDataJson: null,
},
});
if (isErrorResponse(res))
throw res;
return res.result;
}
async _eth_signTransaction(params) {
const tx = this._prepareTransactionParams(params[0] || {});
const relay = this.initializeRelay();
const res = await relay.signEthereumTransaction(tx);
if (isErrorResponse(res))
throw res;
return res.result;
}
async _eth_sendRawTransaction(params) {
const signedTransaction = ensureBuffer(params[0]);
const relay = this.initializeRelay();
const res = await relay.submitEthereumTransaction(signedTransaction, this.getChainId());
if (isErrorResponse(res))
throw res;
return res.result;
}
async _eth_sendTransaction(params) {
const tx = this._prepareTransactionParams(params[0] || {});
const relay = this.initializeRelay();
const res = await relay.signAndSubmitEthereumTransaction(tx);
if (isErrorResponse(res))
throw res;
return res.result;
}
async signTypedData(request) {
const { method, params } = request;
if (!Array.isArray(params))
throw standardErrors.rpc.invalidParams();
const encode = (input) => {
const hashFuncMap = {
eth_signTypedData_v1: eip712.hashForSignTypedDataLegacy,
eth_signTypedData_v3: eip712.hashForSignTypedData_v3,
eth_signTypedData_v4: eip712.hashForSignTypedData_v4,
eth_signTypedData: eip712.hashForSignTypedData_v4,
};
return hexStringFromBuffer(hashFuncMap[method]({
data: ensureParsedJSONObject(input),
}), true);
};
const address = params[method === 'eth_signTypedData_v1' ? 1 : 0];
const rawData = params[method === 'eth_signTypedData_v1' ? 0 : 1];
this._ensureKnownAddress(address);
const relay = this.initializeRelay();
const res = await relay.sendRequest({
method: 'signEthereumMessage',
params: {
address: ensureAddressString(address),
message: encode(rawData),
typedDataJson: JSON.stringify(rawData, null, 2),
addPrefix: false,
},
});
if (isErrorResponse(res))
throw res;
return res.result;
}
initializeRelay() {
if (!this._relay) {
this._relay = new WalletLinkRelay({
linkAPIUrl: WALLETLINK_URL,
storage: this._storage,
metadata: this.metadata,
accountsCallback: this._setAddresses.bind(this),
chainCallback: this.updateProviderInfo.bind(this),
});
}
return this._relay;
}
}
//# sourceMappingURL=WalletLinkSigner.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
import { Web3Response } from './type/Web3Response.js';
type ResponseCallback = (response: Web3Response) => void;
export declare class RelayEventManager {
_nextRequestId: number;
callbacks: Map<string, ResponseCallback>;
makeRequestId(): number;
}
export {};
//# sourceMappingURL=RelayEventManager.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"RelayEventManager.d.ts","sourceRoot":"","sources":["../../../../src/sign/walletlink/relay/RelayEventManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGtD,KAAK,gBAAgB,GAAG,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;AAEzD,qBAAa,iBAAiB;IAC5B,cAAc,SAAK;IACnB,SAAS,gCAAuC;IAEzC,aAAa,IAAI,MAAM;CAY/B"}

View File

@@ -0,0 +1,20 @@
import { prepend0x } from '../../../core/type/util.js';
export class RelayEventManager {
constructor() {
this._nextRequestId = 0;
this.callbacks = new Map();
}
makeRequestId() {
// max nextId == max int32 for compatibility with mobile
this._nextRequestId = (this._nextRequestId + 1) % 0x7fffffff;
const id = this._nextRequestId;
const idStr = prepend0x(id.toString(16));
// unlikely that this will ever be an issue, but just to be safe
const callback = this.callbacks.get(idStr);
if (callback) {
this.callbacks.delete(idStr);
}
return id;
}
}
//# sourceMappingURL=RelayEventManager.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"RelayEventManager.js","sourceRoot":"","sources":["../../../../src/sign/walletlink/relay/RelayEventManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI/C,MAAM,OAAO,iBAAiB;IAA9B;QACE,mBAAc,GAAG,CAAC,CAAC;QACnB,cAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;IAclD,CAAC;IAZQ,aAAa;QAClB,wDAAwD;QACxD,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC;QAC7D,MAAM,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC;QAC/B,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;QACzC,gEAAgE;QAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}

View File

@@ -0,0 +1,58 @@
import { WalletLinkConnectionUpdateListener } from './connection/WalletLinkConnection.js';
import { EthereumTransactionParams } from './type/EthereumTransactionParams.js';
import { WalletLinkSession } from './type/WalletLinkSession.js';
import { Web3Method, Web3Request } from './type/Web3Request.js';
import { Web3Response } from './type/Web3Response.js';
import { AppMetadata } from '../../../core/provider/interface.js';
import { ScopedLocalStorage } from '../../../core/storage/ScopedLocalStorage.js';
export interface WalletLinkRelayOptions {
linkAPIUrl: string;
storage: ScopedLocalStorage;
metadata: AppMetadata;
accountsCallback: (account: string[]) => void;
chainCallback: (jsonRpcUrl: string, chainId: number) => void;
}
export declare class WalletLinkRelay implements WalletLinkConnectionUpdateListener {
private static accountRequestCallbackIds;
private readonly linkAPIUrl;
private readonly storage;
private _session;
private readonly relayEventManager;
private connection;
private accountsCallback;
private chainCallbackParams;
private chainCallback;
private ui;
private isMobileWeb;
private metadata;
isLinked: boolean | undefined;
isUnlinkedErrorState: boolean | undefined;
constructor(options: Readonly<WalletLinkRelayOptions>);
private subscribe;
linkedUpdated: (linked: boolean) => void;
metadataUpdated: (key: string, value: string) => void;
chainUpdated: (chainId: string, jsonRpcUrl: string) => void;
accountUpdated: (selectedAddress: string) => void;
resetAndReload(): void;
signEthereumTransaction(params: EthereumTransactionParams): Promise<Web3Response<"signEthereumTransaction">>;
signAndSubmitEthereumTransaction(params: EthereumTransactionParams): Promise<Web3Response<"submitEthereumTransaction">>;
submitEthereumTransaction(signedTransaction: Buffer, chainId: number): Promise<Web3Response<"submitEthereumTransaction">>;
getWalletLinkSession(): WalletLinkSession;
sendRequest<RequestMethod extends Web3Method, ResponseMethod extends Web3Method = RequestMethod, Response = Web3Response<ResponseMethod>>(request: Web3Request<RequestMethod>): Promise<Response>;
private publishWeb3RequestEvent;
private openCoinbaseWalletDeeplink;
private publishWeb3RequestCanceledEvent;
private publishEvent;
handleWeb3ResponseMessage(id: string, response: Web3Response): void;
private handleErrorResponse;
private invokeCallback;
requestEthereumAccounts(): Promise<Web3Response<"requestEthereumAccounts">>;
watchAsset(type: string, address: string, symbol?: string, decimals?: number, image?: string, chainId?: string): Promise<Web3Response<'watchAsset'>>;
addEthereumChain(chainId: string, rpcUrls: string[], iconUrls: string[], blockExplorerUrls: string[], chainName?: string, nativeCurrency?: {
name: string;
symbol: string;
decimals: number;
}): Promise<Web3Response<"addEthereumChain">>;
switchEthereumChain(chainId: string, address?: string): Promise<Web3Response<'switchEthereumChain'>>;
}
//# sourceMappingURL=WalletLinkRelay.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkRelay.d.ts","sourceRoot":"","sources":["../../../../src/sign/walletlink/relay/WalletLinkRelay.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,394 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
import { WalletLinkConnection, } from './connection/WalletLinkConnection.js';
import { LOCAL_STORAGE_ADDRESSES_KEY } from './constants.js';
import { RelayEventManager } from './RelayEventManager.js';
import { WalletLinkSession } from './type/WalletLinkSession.js';
import { isErrorResponse } from './type/Web3Response.js';
import { isMobileWeb } from './ui/components/util.js';
import { WalletLinkRelayUI } from './ui/WalletLinkRelayUI.js';
import { WLMobileRelayUI } from './ui/WLMobileRelayUI.js';
import { standardErrors } from '../../../core/error/errors.js';
import { ScopedLocalStorage } from '../../../core/storage/ScopedLocalStorage.js';
import { bigIntStringFromBigInt, hexStringFromBuffer, randomBytesHex } from '../../../core/type/util.js';
export class WalletLinkRelay {
constructor(options) {
this.chainCallbackParams = { chainId: '', jsonRpcUrl: '' }; // to implement distinctUntilChanged
this.isMobileWeb = isMobileWeb();
this.linkedUpdated = (linked) => {
this.isLinked = linked;
const cachedAddresses = this.storage.getItem(LOCAL_STORAGE_ADDRESSES_KEY);
if (linked) {
// Only set linked session variable one way
this._session.linked = linked;
}
this.isUnlinkedErrorState = false;
if (cachedAddresses) {
const addresses = cachedAddresses.split(' ');
const wasConnectedViaStandalone = this.storage.getItem('IsStandaloneSigning') === 'true';
if (addresses[0] !== '' && !linked && this._session.linked && !wasConnectedViaStandalone) {
this.isUnlinkedErrorState = true;
}
}
};
this.metadataUpdated = (key, value) => {
this.storage.setItem(key, value);
};
this.chainUpdated = (chainId, jsonRpcUrl) => {
if (this.chainCallbackParams.chainId === chainId &&
this.chainCallbackParams.jsonRpcUrl === jsonRpcUrl) {
return;
}
this.chainCallbackParams = {
chainId,
jsonRpcUrl,
};
if (this.chainCallback) {
this.chainCallback(jsonRpcUrl, Number.parseInt(chainId, 10));
}
};
this.accountUpdated = (selectedAddress) => {
if (this.accountsCallback) {
this.accountsCallback([selectedAddress]);
}
if (WalletLinkRelay.accountRequestCallbackIds.size > 0) {
// We get the ethereum address from the metadata. If for whatever
// reason we don't get a response via an explicit web3 message
// we can still fulfill the eip1102 request.
Array.from(WalletLinkRelay.accountRequestCallbackIds.values()).forEach((id) => {
this.invokeCallback(id, {
method: 'requestEthereumAccounts',
result: [selectedAddress],
});
});
WalletLinkRelay.accountRequestCallbackIds.clear();
}
};
this.resetAndReload = this.resetAndReload.bind(this);
this.linkAPIUrl = options.linkAPIUrl;
this.storage = options.storage;
this.metadata = options.metadata;
this.accountsCallback = options.accountsCallback;
this.chainCallback = options.chainCallback;
const { session, ui, connection } = this.subscribe();
this._session = session;
this.connection = connection;
this.relayEventManager = new RelayEventManager();
this.ui = ui;
this.ui.attach();
}
subscribe() {
const session = WalletLinkSession.load(this.storage) || WalletLinkSession.create(this.storage);
const { linkAPIUrl } = this;
const connection = new WalletLinkConnection({
session,
linkAPIUrl,
listener: this,
});
const ui = this.isMobileWeb ? new WLMobileRelayUI() : new WalletLinkRelayUI();
connection.connect();
return { session, ui, connection };
}
resetAndReload() {
this.connection
.destroy()
.then(() => {
/**
* Only clear storage if the session id we have in memory matches the one on disk
* Otherwise, in the case where we have 2 tabs, another tab might have cleared
* storage already. In that case if we clear storage again, the user will be in
* a state where the first tab allows the user to connect but the session that
* was used isn't persisted. This leaves the user in a state where they aren't
* connected to the mobile app.
*/
const storedSession = WalletLinkSession.load(this.storage);
if ((storedSession === null || storedSession === void 0 ? void 0 : storedSession.id) === this._session.id) {
ScopedLocalStorage.clearAll();
}
document.location.reload();
})
.catch((_) => { });
}
signEthereumTransaction(params) {
return this.sendRequest({
method: 'signEthereumTransaction',
params: {
fromAddress: params.fromAddress,
toAddress: params.toAddress,
weiValue: bigIntStringFromBigInt(params.weiValue),
data: hexStringFromBuffer(params.data, true),
nonce: params.nonce,
gasPriceInWei: params.gasPriceInWei ? bigIntStringFromBigInt(params.gasPriceInWei) : null,
maxFeePerGas: params.gasPriceInWei ? bigIntStringFromBigInt(params.gasPriceInWei) : null,
maxPriorityFeePerGas: params.gasPriceInWei
? bigIntStringFromBigInt(params.gasPriceInWei)
: null,
gasLimit: params.gasLimit ? bigIntStringFromBigInt(params.gasLimit) : null,
chainId: params.chainId,
shouldSubmit: false,
},
});
}
signAndSubmitEthereumTransaction(params) {
return this.sendRequest({
method: 'signEthereumTransaction',
params: {
fromAddress: params.fromAddress,
toAddress: params.toAddress,
weiValue: bigIntStringFromBigInt(params.weiValue),
data: hexStringFromBuffer(params.data, true),
nonce: params.nonce,
gasPriceInWei: params.gasPriceInWei ? bigIntStringFromBigInt(params.gasPriceInWei) : null,
maxFeePerGas: params.maxFeePerGas ? bigIntStringFromBigInt(params.maxFeePerGas) : null,
maxPriorityFeePerGas: params.maxPriorityFeePerGas
? bigIntStringFromBigInt(params.maxPriorityFeePerGas)
: null,
gasLimit: params.gasLimit ? bigIntStringFromBigInt(params.gasLimit) : null,
chainId: params.chainId,
shouldSubmit: true,
},
});
}
submitEthereumTransaction(signedTransaction, chainId) {
return this.sendRequest({
method: 'submitEthereumTransaction',
params: {
signedTransaction: hexStringFromBuffer(signedTransaction, true),
chainId,
},
});
}
getWalletLinkSession() {
return this._session;
}
sendRequest(request) {
let hideSnackbarItem = null;
const id = randomBytesHex(8);
const cancel = (error) => {
this.publishWeb3RequestCanceledEvent(id);
this.handleErrorResponse(id, request.method, error);
hideSnackbarItem === null || hideSnackbarItem === void 0 ? void 0 : hideSnackbarItem();
};
return new Promise((resolve, reject) => {
{
hideSnackbarItem = this.ui.showConnecting({
isUnlinkedErrorState: this.isUnlinkedErrorState,
onCancel: cancel,
onResetConnection: this.resetAndReload, // eslint-disable-line @typescript-eslint/unbound-method
});
}
this.relayEventManager.callbacks.set(id, (response) => {
hideSnackbarItem === null || hideSnackbarItem === void 0 ? void 0 : hideSnackbarItem();
if (isErrorResponse(response)) {
return reject(new Error(response.errorMessage));
}
resolve(response);
});
this.publishWeb3RequestEvent(id, request);
});
}
publishWeb3RequestEvent(id, request) {
const message = { type: 'WEB3_REQUEST', id, request };
this.publishEvent('Web3Request', message, true)
.then((_) => { })
.catch((err) => {
this.handleWeb3ResponseMessage(message.id, {
method: request.method,
errorMessage: err.message,
});
});
if (this.isMobileWeb) {
this.openCoinbaseWalletDeeplink(request.method);
}
}
// copied from MobileRelay
openCoinbaseWalletDeeplink(method) {
if (!(this.ui instanceof WLMobileRelayUI))
return;
// For mobile relay requests, open the Coinbase Wallet app
switch (method) {
case 'requestEthereumAccounts': // requestEthereumAccounts is handled via popup
case 'switchEthereumChain': // switchEthereumChain doesn't need to open the app
return;
default:
window.addEventListener('blur', () => {
window.addEventListener('focus', () => {
this.connection.checkUnseenEvents();
}, { once: true });
}, { once: true });
this.ui.openCoinbaseWalletDeeplink();
break;
}
}
publishWeb3RequestCanceledEvent(id) {
const message = {
type: 'WEB3_REQUEST_CANCELED',
id,
};
this.publishEvent('Web3RequestCanceled', message, false).then();
}
publishEvent(event, message, callWebhook) {
return this.connection.publishEvent(event, message, callWebhook);
}
handleWeb3ResponseMessage(id, response) {
if (response.method === 'requestEthereumAccounts') {
WalletLinkRelay.accountRequestCallbackIds.forEach((id) => this.invokeCallback(id, response));
WalletLinkRelay.accountRequestCallbackIds.clear();
return;
}
this.invokeCallback(id, response);
}
handleErrorResponse(id, method, error) {
var _a;
const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : 'Unspecified error message.';
this.handleWeb3ResponseMessage(id, {
method,
errorMessage,
});
}
invokeCallback(id, response) {
const callback = this.relayEventManager.callbacks.get(id);
if (callback) {
callback(response);
this.relayEventManager.callbacks.delete(id);
}
}
requestEthereumAccounts() {
const { appName, appLogoUrl } = this.metadata;
const request = {
method: 'requestEthereumAccounts',
params: {
appName,
appLogoUrl,
},
};
const hideSnackbarItem = null;
const id = randomBytesHex(8);
return new Promise((resolve, reject) => {
this.relayEventManager.callbacks.set(id, (response) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
hideSnackbarItem === null || hideSnackbarItem === void 0 ? void 0 : hideSnackbarItem();
if (isErrorResponse(response)) {
return reject(new Error(response.errorMessage));
}
resolve(response);
});
WalletLinkRelay.accountRequestCallbackIds.add(id);
this.publishWeb3RequestEvent(id, request);
});
}
watchAsset(type, address, symbol, decimals, image, chainId) {
const request = {
method: 'watchAsset',
params: {
type,
options: {
address,
symbol,
decimals,
image,
},
chainId,
},
};
let hideSnackbarItem = null;
const id = randomBytesHex(8);
const cancel = (error) => {
this.publishWeb3RequestCanceledEvent(id);
this.handleErrorResponse(id, request.method, error);
hideSnackbarItem === null || hideSnackbarItem === void 0 ? void 0 : hideSnackbarItem();
};
{
hideSnackbarItem = this.ui.showConnecting({
isUnlinkedErrorState: this.isUnlinkedErrorState,
onCancel: cancel,
onResetConnection: this.resetAndReload, // eslint-disable-line @typescript-eslint/unbound-method
});
}
return new Promise((resolve, reject) => {
this.relayEventManager.callbacks.set(id, (response) => {
hideSnackbarItem === null || hideSnackbarItem === void 0 ? void 0 : hideSnackbarItem();
if (isErrorResponse(response)) {
return reject(new Error(response.errorMessage));
}
resolve(response);
});
this.publishWeb3RequestEvent(id, request);
});
}
addEthereumChain(chainId, rpcUrls, iconUrls, blockExplorerUrls, chainName, nativeCurrency) {
const request = {
method: 'addEthereumChain',
params: {
chainId,
rpcUrls,
blockExplorerUrls,
chainName,
iconUrls,
nativeCurrency,
},
};
let hideSnackbarItem = null;
const id = randomBytesHex(8);
const cancel = (error) => {
this.publishWeb3RequestCanceledEvent(id);
this.handleErrorResponse(id, request.method, error);
hideSnackbarItem === null || hideSnackbarItem === void 0 ? void 0 : hideSnackbarItem();
};
{
hideSnackbarItem = this.ui.showConnecting({
isUnlinkedErrorState: this.isUnlinkedErrorState,
onCancel: cancel,
onResetConnection: this.resetAndReload, // eslint-disable-line @typescript-eslint/unbound-method
});
}
return new Promise((resolve, reject) => {
this.relayEventManager.callbacks.set(id, (response) => {
hideSnackbarItem === null || hideSnackbarItem === void 0 ? void 0 : hideSnackbarItem();
if (isErrorResponse(response)) {
return reject(new Error(response.errorMessage));
}
resolve(response);
});
this.publishWeb3RequestEvent(id, request);
});
}
switchEthereumChain(chainId, address) {
const request = {
method: 'switchEthereumChain',
params: Object.assign({ chainId }, { address }),
};
let hideSnackbarItem = null;
const id = randomBytesHex(8);
const cancel = (error) => {
this.publishWeb3RequestCanceledEvent(id);
this.handleErrorResponse(id, request.method, error);
hideSnackbarItem === null || hideSnackbarItem === void 0 ? void 0 : hideSnackbarItem();
};
{
hideSnackbarItem = this.ui.showConnecting({
isUnlinkedErrorState: this.isUnlinkedErrorState,
onCancel: cancel,
onResetConnection: this.resetAndReload, // eslint-disable-line @typescript-eslint/unbound-method
});
}
return new Promise((resolve, reject) => {
this.relayEventManager.callbacks.set(id, (response) => {
hideSnackbarItem === null || hideSnackbarItem === void 0 ? void 0 : hideSnackbarItem();
if (isErrorResponse(response) && response.errorCode) {
return reject(standardErrors.provider.custom({
code: response.errorCode,
message: `Unrecognized chain ID. Try adding the chain using addEthereumChain first.`,
}));
}
else if (isErrorResponse(response)) {
return reject(new Error(response.errorMessage));
}
resolve(response);
});
this.publishWeb3RequestEvent(id, request);
});
}
}
WalletLinkRelay.accountRequestCallbackIds = new Set();
//# sourceMappingURL=WalletLinkRelay.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,19 @@
export declare class WalletLinkCipher {
private readonly secret;
constructor(secret: string);
/**
*
* @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.
*/
encrypt(plainText: string): Promise<string>;
/**
*
* @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.
*/
decrypt(cipherText: string): Promise<string>;
}
//# sourceMappingURL=WalletLinkCipher.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkCipher.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/connection/WalletLinkCipher.ts"],"names":[],"mappings":"AAIA,qBAAa,gBAAgB;IAEf,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C;;;;;;OAMG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkCjD;;;;OAIG;IACG,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAiCnD"}

View File

@@ -0,0 +1,68 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
import { hexStringToUint8Array, uint8ArrayToHex } from '../../../../core/type/util.js';
export 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();
// Will return encrypted plainText with auth tag (ie MAC or checksum) appended at the end
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);
}
})();
});
}
}
//# sourceMappingURL=WalletLinkCipher.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkCipher.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/connection/WalletLinkCipher.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,102 @@
import { WalletLinkEventData } from '../type/WalletLinkEventData.js';
import { WalletLinkSession } from '../type/WalletLinkSession.js';
import { Web3Response } from '../type/Web3Response.js';
export interface WalletLinkConnectionUpdateListener {
linkedUpdated: (linked: boolean) => void;
handleWeb3ResponseMessage: (id: string, response: Web3Response) => void;
chainUpdated: (chainId: string, jsonRpcUrl: string) => void;
accountUpdated: (selectedAddress: string) => void;
metadataUpdated: (key: string, metadataValue: string) => void;
resetAndReload: () => void;
}
interface WalletLinkConnectionParams {
session: WalletLinkSession;
linkAPIUrl: string;
listener: WalletLinkConnectionUpdateListener;
}
/**
* Coinbase Wallet Connection
*/
export declare class WalletLinkConnection {
private destroyed;
private lastHeartbeatResponse;
private nextReqId;
private heartbeatIntervalId?;
private reconnectAttempts;
private visibilityChangeHandler?;
private focusHandler?;
private activeWsInstance?;
private isReconnecting;
private readonly session;
private listener?;
private cipher;
private ws;
private http;
private readonly linkAPIUrl;
private readonly WebSocketClass;
/**
* Constructor
* @param session Session
* @param linkAPIUrl Coinbase Wallet link server URL
* @param listener WalletLinkConnectionUpdateListener
* @param [WebSocketClass] Custom WebSocket implementation
*/
constructor({ session, linkAPIUrl, listener }: WalletLinkConnectionParams);
private createWebSocket;
private setupVisibilityChangeHandler;
private reconnectWithFreshWebSocket;
/**
* Make a connection to the server
*/
connect(): void;
/**
* Terminate connection, and mark as destroyed. To reconnect, create a new
* instance of WalletSDKConnection
*/
destroy(): Promise<void>;
/**
* true if connected and authenticated, else false
* runs listener when connected status changes
*/
private _connected;
private get connected();
private set connected(value);
/**
* true if linked (a guest has joined before)
* runs listener when linked status changes
*/
private _linked;
private get linked();
private set linked(value);
/**
* Execute once when linked
*/
private onceLinked?;
private setOnceLinked;
private handleIncomingEvent;
checkUnseenEvents(): Promise<void>;
private fetchUnseenEventsAPI;
/**
* Publish an event and emit event ID when successful
* @param event event name
* @param unencryptedData unencrypted event data
* @param callWebhook whether the webhook should be invoked
* @returns a Promise that emits event ID when successful
*/
publishEvent(event: string, unencryptedData: WalletLinkEventData, callWebhook?: boolean): Promise<string>;
private sendData;
private updateLastHeartbeat;
private heartbeat;
private requestResolutions;
private makeRequest;
private handleConnected;
private handleSessionMetadataUpdated;
private handleDestroyed;
private handleAccountUpdated;
private handleMetadataUpdated;
private handleWalletUsernameUpdated;
private handleAppVersionUpdated;
private handleChainUpdated;
}
export {};
//# sourceMappingURL=WalletLinkConnection.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkConnection.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/connection/WalletLinkConnection.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,498 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
import { APP_VERSION_KEY, WALLET_USER_NAME_KEY } from '../constants.js';
import { WalletLinkCipher } from './WalletLinkCipher.js';
import { WalletLinkHTTP } from './WalletLinkHTTP.js';
import { ConnectionState, WalletLinkWebSocket } from './WalletLinkWebSocket.js';
import { IntNumber } from '../../../../core/type/index.js';
const HEARTBEAT_INTERVAL = 10000;
const REQUEST_TIMEOUT = 60000;
/**
* Coinbase Wallet Connection
*/
export class WalletLinkConnection {
/**
* Constructor
* @param session Session
* @param linkAPIUrl Coinbase Wallet link server URL
* @param listener WalletLinkConnectionUpdateListener
* @param [WebSocketClass] Custom WebSocket implementation
*/
constructor({ session, linkAPIUrl, listener }) {
this.destroyed = false;
this.lastHeartbeatResponse = 0;
this.nextReqId = IntNumber(1);
this.reconnectAttempts = 0;
this.isReconnecting = false;
/**
* true if connected and authenticated, else false
* runs listener when connected status changes
*/
this._connected = false;
/**
* true if linked (a guest has joined before)
* runs listener when linked status changes
*/
this._linked = false;
this.requestResolutions = new Map();
this.handleSessionMetadataUpdated = (metadata) => {
if (!metadata)
return;
// Map of metadata key to handler function
const handlers = new Map([
['__destroyed', this.handleDestroyed],
['EthereumAddress', this.handleAccountUpdated],
['WalletUsername', this.handleWalletUsernameUpdated],
['AppVersion', this.handleAppVersionUpdated],
[
'ChainId', // ChainId and JsonRpcUrl are always updated together
(v) => metadata.JsonRpcUrl && this.handleChainUpdated(v, metadata.JsonRpcUrl),
],
]);
// call handler for each metadata key if value is defined
handlers.forEach((handler, key) => {
const value = metadata[key];
if (value === undefined)
return;
handler(value);
});
};
this.handleDestroyed = (__destroyed) => {
var _a;
if (__destroyed !== '1')
return;
(_a = this.listener) === null || _a === void 0 ? void 0 : _a.resetAndReload();
};
this.handleAccountUpdated = async (encryptedEthereumAddress) => {
var _a;
try {
const address = await this.cipher.decrypt(encryptedEthereumAddress);
(_a = this.listener) === null || _a === void 0 ? void 0 : _a.accountUpdated(address);
}
catch (_b) {
// Had error decrypting
}
};
this.handleMetadataUpdated = async (key, encryptedMetadataValue) => {
var _a;
try {
const decryptedValue = await this.cipher.decrypt(encryptedMetadataValue);
(_a = this.listener) === null || _a === void 0 ? void 0 : _a.metadataUpdated(key, decryptedValue);
}
catch (_b) {
// Had error decrypting
}
};
this.handleWalletUsernameUpdated = async (walletUsername) => {
this.handleMetadataUpdated(WALLET_USER_NAME_KEY, walletUsername);
};
this.handleAppVersionUpdated = async (appVersion) => {
this.handleMetadataUpdated(APP_VERSION_KEY, appVersion);
};
this.handleChainUpdated = async (encryptedChainId, encryptedJsonRpcUrl) => {
var _a;
try {
const chainId = await this.cipher.decrypt(encryptedChainId);
const jsonRpcUrl = await this.cipher.decrypt(encryptedJsonRpcUrl);
(_a = this.listener) === null || _a === void 0 ? void 0 : _a.chainUpdated(chainId, jsonRpcUrl);
}
catch (_b) {
// Had error decrypting
}
};
this.session = session;
this.cipher = new WalletLinkCipher(session.secret);
this.listener = listener;
this.linkAPIUrl = linkAPIUrl;
this.WebSocketClass = WebSocket;
const ws = this.createWebSocket();
this.ws = ws;
this.http = new WalletLinkHTTP(linkAPIUrl, session.id, session.key);
this.setupVisibilityChangeHandler();
}
createWebSocket() {
const ws = new WalletLinkWebSocket(`${this.linkAPIUrl}/rpc`, this.WebSocketClass);
// Track this as the active WebSocket instance
this.activeWsInstance = ws;
ws.setConnectionStateListener(async (state) => {
// Ignore events from non-active WebSocket instances
if (ws !== this.activeWsInstance) {
return;
}
// attempt to reconnect every 5 seconds when disconnected
let connected = false;
switch (state) {
case ConnectionState.DISCONNECTED:
// Clear heartbeat timer when disconnected
if (this.heartbeatIntervalId) {
clearInterval(this.heartbeatIntervalId);
this.heartbeatIntervalId = undefined;
}
// Reset lastHeartbeatResponse to prevent false timeout on reconnection
this.lastHeartbeatResponse = 0;
// Reset connected state to false on disconnect
connected = false;
// if DISCONNECTED and not destroyed, create a fresh WebSocket connection
if (!this.destroyed) {
const reconnect = async () => {
// Prevent multiple concurrent reconnection attempts
if (this.isReconnecting) {
return;
}
this.isReconnecting = true;
// 0 second delay on first attempt, then 3 seconds
const delay = this.reconnectAttempts === 0 ? 0 : 3000;
// wait before reconnecting
await new Promise((resolve) => setTimeout(resolve, delay));
// check whether it's destroyed again and ensure this is still the active instance
if (!this.destroyed && ws === this.activeWsInstance) {
this.reconnectAttempts++;
// Clean up the old WebSocket instance
if ('cleanup' in this.ws && typeof this.ws.cleanup === 'function') {
this.ws.cleanup();
}
// Create a fresh WebSocket instance
this.ws = this.createWebSocket();
this.ws
.connect()
.catch(() => {
// Reconnection failed, will retry
})
.finally(() => {
this.isReconnecting = false;
});
}
else {
this.isReconnecting = false;
}
};
reconnect();
}
break;
case ConnectionState.CONNECTED:
// Reset reconnect attempts on successful connection
this.reconnectAttempts = 0;
// perform authentication upon connection
try {
// if CONNECTED, authenticate, and then check link status
connected = await this.handleConnected();
// Always fetch unseen events when WebSocket state changes to CONNECTED
this.fetchUnseenEventsAPI().catch(() => {
// Failed to fetch unseen events after connection
});
}
catch (_error) {
// Don't set connected to true if authentication fails
break;
}
// Update connected state immediately after successful authentication
// This ensures heartbeats won't be skipped
this.connected = connected;
// send heartbeat every n seconds while connected
// if CONNECTED, start the heartbeat timer
// first timer event updates lastHeartbeat timestamp
// subsequent calls send heartbeat message
this.updateLastHeartbeat();
// Clear existing heartbeat timer
if (this.heartbeatIntervalId) {
clearInterval(this.heartbeatIntervalId);
}
this.heartbeatIntervalId = window.setInterval(() => {
this.heartbeat();
}, HEARTBEAT_INTERVAL);
// Send an immediate heartbeat
setTimeout(() => {
this.heartbeat();
}, 100);
break;
case ConnectionState.CONNECTING:
break;
}
// Update connected state for DISCONNECTED and CONNECTING cases
// For CONNECTED case, it's already set above
if (state !== ConnectionState.CONNECTED) {
this.connected = connected;
}
});
ws.setIncomingDataListener((m) => {
var _a;
switch (m.type) {
// handle server's heartbeat responses
case 'Heartbeat':
this.updateLastHeartbeat();
return;
// handle link status updates
case 'IsLinkedOK':
case 'Linked': {
const linked = m.type === 'IsLinkedOK' ? m.linked : undefined;
this.linked = linked || m.onlineGuests > 0;
break;
}
// handle session config updates
case 'GetSessionConfigOK':
case 'SessionConfigUpdated': {
this.handleSessionMetadataUpdated(m.metadata);
break;
}
case 'Event': {
this.handleIncomingEvent(m);
break;
}
}
// resolve request promises
if (m.id !== undefined) {
(_a = this.requestResolutions.get(m.id)) === null || _a === void 0 ? void 0 : _a(m);
}
});
return ws;
}
setupVisibilityChangeHandler() {
this.visibilityChangeHandler = () => {
if (!document.hidden && !this.destroyed) {
if (!this.connected) {
// Force a fresh connection if we're disconnected
this.reconnectWithFreshWebSocket();
}
else {
// Otherwise send a heartbeat to check if connection is still alive
this.heartbeat();
}
}
};
// Handle focus events (when user switches back to the tab/app)
this.focusHandler = () => {
if (!this.destroyed && !this.connected) {
this.reconnectWithFreshWebSocket();
}
};
// Add event listeners
document.addEventListener('visibilitychange', this.visibilityChangeHandler);
window.addEventListener('focus', this.focusHandler);
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
if (this.focusHandler) {
this.focusHandler();
}
}
});
}
reconnectWithFreshWebSocket() {
if (this.destroyed)
return;
// Clear the active instance reference before disconnecting
const oldWs = this.ws;
this.activeWsInstance = undefined;
// Disconnect current WebSocket
oldWs.disconnect();
// Clean up the old instance
if ('cleanup' in oldWs && typeof oldWs.cleanup === 'function') {
oldWs.cleanup();
}
// Create and connect fresh WebSocket
this.ws = this.createWebSocket();
this.ws.connect().catch(() => {
// Fresh reconnection failed
});
}
/**
* Make a connection to the server
*/
connect() {
if (this.destroyed) {
throw new Error('instance is destroyed');
}
this.ws.connect();
}
/**
* Terminate connection, and mark as destroyed. To reconnect, create a new
* instance of WalletSDKConnection
*/
async destroy() {
if (this.destroyed)
return;
await this.makeRequest({
type: 'SetSessionConfig',
id: IntNumber(this.nextReqId++),
sessionId: this.session.id,
metadata: { __destroyed: '1' },
}, { timeout: 1000 });
this.destroyed = true;
// Clear the active instance reference
this.activeWsInstance = undefined;
// Clear heartbeat timer
if (this.heartbeatIntervalId) {
clearInterval(this.heartbeatIntervalId);
this.heartbeatIntervalId = undefined;
}
// Remove event listeners
if (this.visibilityChangeHandler) {
document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
}
if (this.focusHandler) {
window.removeEventListener('focus', this.focusHandler);
}
this.ws.disconnect();
// Call cleanup on the WebSocket instance if it has the method
if ('cleanup' in this.ws && typeof this.ws.cleanup === 'function') {
this.ws.cleanup();
}
this.listener = undefined;
}
get connected() {
return this._connected;
}
set connected(connected) {
this._connected = connected;
}
get linked() {
return this._linked;
}
set linked(linked) {
var _a, _b;
this._linked = linked;
if (linked)
(_a = this.onceLinked) === null || _a === void 0 ? void 0 : _a.call(this);
(_b = this.listener) === null || _b === void 0 ? void 0 : _b.linkedUpdated(linked);
}
setOnceLinked(callback) {
return new Promise((resolve) => {
if (this.linked) {
callback().then(resolve);
}
else {
this.onceLinked = () => {
callback().then(resolve);
this.onceLinked = undefined;
};
}
});
}
async handleIncomingEvent(m) {
var _a;
if (m.type !== 'Event' || m.event !== 'Web3Response') {
return;
}
try {
const decryptedData = await this.cipher.decrypt(m.data);
const message = JSON.parse(decryptedData);
if (message.type !== 'WEB3_RESPONSE')
return;
(_a = this.listener) === null || _a === void 0 ? void 0 : _a.handleWeb3ResponseMessage(message.id, message.response);
}
catch (_error) {
// Had error decrypting
}
}
async checkUnseenEvents() {
// Add a small delay to ensure any pending operations complete
await new Promise((resolve) => setTimeout(resolve, 250));
try {
await this.fetchUnseenEventsAPI();
}
catch (e) {
console.error('Unable to check for unseen events', e);
}
}
async fetchUnseenEventsAPI() {
try {
const responseEvents = await this.http.fetchUnseenEvents();
responseEvents.forEach((e) => {
this.handleIncomingEvent(e);
});
}
catch (_error) {
// Failed to fetch unseen events
}
}
/**
* Publish an event and emit event ID when successful
* @param event event name
* @param unencryptedData unencrypted event data
* @param callWebhook whether the webhook should be invoked
* @returns a Promise that emits event ID when successful
*/
async publishEvent(event, unencryptedData, callWebhook = false) {
const data = await this.cipher.encrypt(JSON.stringify(Object.assign(Object.assign({}, unencryptedData), { origin: location.origin, location: location.href, relaySource: 'coinbaseWalletExtension' in window && window.coinbaseWalletExtension
? 'injected_sdk'
: 'sdk' })));
const message = {
type: 'PublishEvent',
id: IntNumber(this.nextReqId++),
sessionId: this.session.id,
event,
data,
callWebhook,
};
return this.setOnceLinked(async () => {
const res = await this.makeRequest(message);
if (res.type === 'Fail') {
throw new Error(res.error || 'failed to publish event');
}
return res.eventId;
});
}
sendData(message) {
this.ws.sendData(JSON.stringify(message));
}
updateLastHeartbeat() {
this.lastHeartbeatResponse = Date.now();
}
heartbeat() {
if (Date.now() - this.lastHeartbeatResponse > HEARTBEAT_INTERVAL * 2) {
this.ws.disconnect();
return;
}
// Only send heartbeat if we're connected
if (!this.connected) {
return;
}
try {
this.ws.sendData('h');
}
catch (_error) {
// Error sending heartbeat
}
}
async makeRequest(message, options = { timeout: REQUEST_TIMEOUT }) {
const reqId = message.id;
this.sendData(message);
// await server message with corresponding id
let timeoutId;
return Promise.race([
new Promise((_, reject) => {
timeoutId = window.setTimeout(() => {
reject(new Error(`request ${reqId} timed out`));
}, options.timeout);
}),
new Promise((resolve) => {
this.requestResolutions.set(reqId, (m) => {
clearTimeout(timeoutId); // clear the timeout
resolve(m);
this.requestResolutions.delete(reqId);
});
}),
]);
}
async handleConnected() {
const res = await this.makeRequest({
type: 'HostSession',
id: IntNumber(this.nextReqId++),
sessionId: this.session.id,
sessionKey: this.session.key,
});
if (res.type === 'Fail') {
return false;
}
this.sendData({
type: 'IsLinked',
id: IntNumber(this.nextReqId++),
sessionId: this.session.id,
});
this.sendData({
type: 'GetSessionConfig',
id: IntNumber(this.nextReqId++),
sessionId: this.session.id,
});
return true;
}
}
//# sourceMappingURL=WalletLinkConnection.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
import { ServerMessage } from '../type/ServerMessage.js';
export declare class WalletLinkHTTP {
private readonly linkAPIUrl;
private readonly sessionId;
private readonly auth;
constructor(linkAPIUrl: string, sessionId: string, sessionKey: string);
private markUnseenEventsAsSeen;
fetchUnseenEvents(): Promise<ServerMessage<'Event'>[]>;
}
//# sourceMappingURL=WalletLinkHTTP.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkHTTP.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/connection/WalletLinkHTTP.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,qBAAa,cAAc;IAIvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAGX,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EAClC,UAAU,EAAE,MAAM;YAON,sBAAsB;IAa9B,iBAAiB,IAAI,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;CAuC7D"}

View File

@@ -0,0 +1,42 @@
export 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 Promise.all(events.map((e) => fetch(`${this.linkAPIUrl}/events/${e.eventId}/seen`, {
method: 'POST',
headers: {
Authorization: this.auth,
},
}))).catch((error) => console.error('Unabled to mark event as failed:', error));
}
async fetchUnseenEvents() {
var _a;
const response = await fetch(`${this.linkAPIUrl}/events?unseen=true`, {
headers: {
Authorization: this.auth,
},
});
if (response.ok) {
const { events, error } = (await response.json());
if (error) {
throw new Error(`Check unseen events failed: ${error}`);
}
const responseEvents = (_a = events === null || events === void 0 ? void 0 : events.filter((e) => e.event === 'Web3Response').map((e) => ({
type: 'Event',
sessionId: this.sessionId,
eventId: e.id,
event: e.event,
data: e.data,
}))) !== null && _a !== void 0 ? _a : [];
this.markUnseenEventsAsSeen(responseEvents);
return responseEvents;
}
throw new Error(`Check unseen events failed: ${response.status}`);
}
}
//# sourceMappingURL=WalletLinkHTTP.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkHTTP.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/connection/WalletLinkHTTP.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,cAAc;IAGzB,YACmB,UAAkB,EAClB,SAAiB,EAClC,UAAkB;QAFD,eAAU,GAAV,UAAU,CAAQ;QAClB,cAAS,GAAT,SAAS,CAAQ;QAGlC,MAAM,WAAW,GAAG,GAAG,SAAS,IAAI,UAAU,EAAE,CAAC;QACjD,IAAI,CAAC,IAAI,GAAG,SAAS,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;IAC3C,CAAC;IAED,6BAA6B;IACrB,KAAK,CAAC,sBAAsB,CAAC,MAAgC;QACnE,OAAO,OAAO,CAAC,GAAG,CAChB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACf,KAAK,CAAC,GAAG,IAAI,CAAC,UAAU,WAAW,CAAC,CAAC,OAAO,OAAO,EAAE;YACnD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,IAAI,CAAC,IAAI;aACzB;SACF,CAAC,CACH,CACF,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC,CAAC;IAC/E,CAAC;IAED,KAAK,CAAC,iBAAiB;;QACrB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,UAAU,qBAAqB,EAAE;YACpE,OAAO,EAAE;gBACP,aAAa,EAAE,IAAI,CAAC,IAAI;aACzB;SACF,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAQ/C,CAAC;YAEF,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,+BAA+B,KAAK,EAAE,CAAC,CAAC;YAC1D,CAAC;YAED,MAAM,cAAc,GAClB,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CACF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,cAAc,EACzC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACX,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,OAAO,EAAE,CAAC,CAAC,EAAE;gBACb,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,IAAI,EAAE,CAAC,CAAC,IAAI;aACb,CAAC,CAAC,mCAAI,EAAE,CAAC;YAEd,IAAI,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAC;YAE5C,OAAO,cAAc,CAAC;QACxB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;CACF"}

View File

@@ -0,0 +1,46 @@
import { ServerMessage } from '../type/ServerMessage.js';
export declare enum ConnectionState {
DISCONNECTED = 0,
CONNECTING = 1,
CONNECTED = 2
}
export declare class WalletLinkWebSocket {
private readonly WebSocketClass;
private static instanceCounter;
private static activeInstances;
private static pendingData;
private readonly instanceId;
private readonly url;
private webSocket;
private isDisconnecting;
private connectionStateListener?;
setConnectionStateListener(listener: (_: ConnectionState) => void): void;
private incomingDataListener?;
setIncomingDataListener(listener: (_: ServerMessage) => void): void;
/**
* Constructor
* @param url WebSocket server URL
* @param [WebSocketClass] Custom WebSocket implementation
*/
constructor(url: string, WebSocketClass?: typeof WebSocket);
/**
* Make a websocket connection
* @returns a Promise that resolves when connected
*/
connect(): Promise<void>;
/**
* Disconnect from server
*/
disconnect(): void;
/**
* Send data to server
* @param data text to send
*/
sendData(data: string): void;
private clearWebSocket;
/**
* remove ws from active instances
*/
cleanup(): void;
}
//# sourceMappingURL=WalletLinkWebSocket.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkWebSocket.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/connection/WalletLinkWebSocket.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,oBAAY,eAAe;IACzB,YAAY,IAAA;IACZ,UAAU,IAAA;IACV,SAAS,IAAA;CACV;AAED,qBAAa,mBAAmB;IA4B5B,OAAO,CAAC,QAAQ,CAAC,cAAc;IA1BjC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAK;IACnC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAqB;IACnD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAgB;IAE1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,uBAAuB,CAAC,CAA+B;IAC/D,0BAA0B,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;IAIxE,OAAO,CAAC,oBAAoB,CAAC,CAA6B;IAC1D,uBAAuB,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI;IAInE;;;;OAIG;gBAED,GAAG,EAAE,MAAM,EACM,cAAc,GAAE,OAAO,SAAqB;IAO/D;;;OAGG;IACU,OAAO;IAsDpB;;OAEG;IACI,UAAU,IAAI,IAAI;IAsBzB;;;OAGG;IACI,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAmBnC,OAAO,CAAC,cAAc;IAYtB;;OAEG;IACI,OAAO,IAAI,IAAI;CAGvB"}

View File

@@ -0,0 +1,153 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
export var ConnectionState;
(function (ConnectionState) {
ConnectionState[ConnectionState["DISCONNECTED"] = 0] = "DISCONNECTED";
ConnectionState[ConnectionState["CONNECTING"] = 1] = "CONNECTING";
ConnectionState[ConnectionState["CONNECTED"] = 2] = "CONNECTED";
})(ConnectionState || (ConnectionState = {}));
export class WalletLinkWebSocket {
setConnectionStateListener(listener) {
this.connectionStateListener = listener;
}
setIncomingDataListener(listener) {
this.incomingDataListener = listener;
}
/**
* Constructor
* @param url WebSocket server URL
* @param [WebSocketClass] Custom WebSocket implementation
*/
constructor(url, WebSocketClass = WebSocket) {
this.WebSocketClass = WebSocketClass;
this.webSocket = null;
this.isDisconnecting = false;
this.url = url.replace(/^http/, 'ws');
this.instanceId = WalletLinkWebSocket.instanceCounter++;
WalletLinkWebSocket.activeInstances.add(this.instanceId);
}
/**
* Make a websocket connection
* @returns a Promise that resolves when connected
*/
async connect() {
if (this.webSocket) {
throw new Error('webSocket object is not null');
}
if (this.isDisconnecting) {
throw new Error('WebSocket is disconnecting, cannot reconnect on same instance');
}
return new Promise((resolve, reject) => {
var _a;
let webSocket;
try {
this.webSocket = webSocket = new this.WebSocketClass(this.url);
}
catch (err) {
reject(err);
return;
}
(_a = this.connectionStateListener) === null || _a === void 0 ? void 0 : _a.call(this, ConnectionState.CONNECTING);
webSocket.onclose = (evt) => {
var _a;
this.clearWebSocket();
// Only reject the connection promise if we haven't connected yet
if (webSocket.readyState !== WebSocket.OPEN) {
reject(new Error(`websocket error ${evt.code}: ${evt.reason}`));
}
(_a = this.connectionStateListener) === null || _a === void 0 ? void 0 : _a.call(this, ConnectionState.DISCONNECTED);
};
webSocket.onopen = (_) => {
var _a;
resolve();
(_a = this.connectionStateListener) === null || _a === void 0 ? void 0 : _a.call(this, ConnectionState.CONNECTED);
if (WalletLinkWebSocket.pendingData.length > 0) {
const pending = [...WalletLinkWebSocket.pendingData];
pending.forEach((data) => this.sendData(data));
WalletLinkWebSocket.pendingData = [];
}
};
webSocket.onmessage = (evt) => {
var _a, _b;
if (evt.data === 'h') {
(_a = this.incomingDataListener) === null || _a === void 0 ? void 0 : _a.call(this, {
type: 'Heartbeat',
});
}
else {
try {
const message = JSON.parse(evt.data);
(_b = this.incomingDataListener) === null || _b === void 0 ? void 0 : _b.call(this, message);
}
catch (_c) {
// noop
}
}
};
});
}
/**
* Disconnect from server
*/
disconnect() {
var _a;
const { webSocket } = this;
if (!webSocket) {
return;
}
// Mark as disconnecting to prevent reconnection attempts on this instance
this.isDisconnecting = true;
this.clearWebSocket();
// Clear listeners
(_a = this.connectionStateListener) === null || _a === void 0 ? void 0 : _a.call(this, ConnectionState.DISCONNECTED);
this.connectionStateListener = undefined;
this.incomingDataListener = undefined;
try {
webSocket.close();
}
catch (_b) {
// noop
}
}
/**
* Send data to server
* @param data text to send
*/
sendData(data) {
const { webSocket } = this;
if (!webSocket) {
WalletLinkWebSocket.pendingData.push(data);
if (!this.isDisconnecting) {
this.connect();
}
return;
}
// Check if WebSocket is actually open before sending
if (webSocket.readyState !== WebSocket.OPEN) {
WalletLinkWebSocket.pendingData.push(data);
return;
}
webSocket.send(data);
}
clearWebSocket() {
const { webSocket } = this;
if (!webSocket) {
return;
}
this.webSocket = null;
webSocket.onclose = null;
webSocket.onerror = null;
webSocket.onmessage = null;
webSocket.onopen = null;
}
/**
* remove ws from active instances
*/
cleanup() {
WalletLinkWebSocket.activeInstances.delete(this.instanceId);
}
}
// used to differentiate instances
WalletLinkWebSocket.instanceCounter = 0;
WalletLinkWebSocket.activeInstances = new Set();
WalletLinkWebSocket.pendingData = [];
//# sourceMappingURL=WalletLinkWebSocket.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkWebSocket.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/connection/WalletLinkWebSocket.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,4 @@
export declare const WALLET_USER_NAME_KEY = "walletUsername";
export declare const LOCAL_STORAGE_ADDRESSES_KEY = "Addresses";
export declare const APP_VERSION_KEY = "AppVersion";
//# sourceMappingURL=constants.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/sign/walletlink/relay/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AACrD,eAAO,MAAM,2BAA2B,cAAc,CAAC;AACvD,eAAO,MAAM,eAAe,eAAe,CAAC"}

View File

@@ -0,0 +1,4 @@
export const WALLET_USER_NAME_KEY = 'walletUsername';
export const LOCAL_STORAGE_ADDRESSES_KEY = 'Addresses';
export const APP_VERSION_KEY = 'AppVersion';
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/sign/walletlink/relay/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AACrD,MAAM,CAAC,MAAM,2BAA2B,GAAG,WAAW,CAAC;AACvD,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC"}

View File

@@ -0,0 +1,5 @@
export declare const MOCK_ADDERESS = "0xFadAFCE89EA2221fa33005640Acf2C923312F2b9";
export declare const MOCK_TX = "0xc21a1aaace40a8ee9dd3827ae5a85412a05755cc004469efaf3cfdd82c59a670";
export declare const MOCK_SIGNED_TX = ":f87a1b8504a817c80082520894c589ac793af309db9690d819abc9aab37d169f6a8814d1120d7b1600008e0deadbeef0cafebabe01234567891ba03cd26b08b246f23f74fceb2c063021955e691cf7d45fba443a2e504a4700dba5a0337b1f8dbf21ef35adf6e2a867d9c7bc836d1b79c8ab40c670385a2d0abca88c";
export declare const MOCK_TYPED_DATA: string;
//# sourceMappingURL=fixtures.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/mocks/fixtures.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,+CAA+C,CAAC;AAE1E,eAAO,MAAM,OAAO,uEAAuE,CAAC;AAE5F,eAAO,MAAM,cAAc,8PACkO,CAAC;AAE9P,eAAO,MAAM,eAAe,QAiC1B,CAAC"}

View File

@@ -0,0 +1,38 @@
export const MOCK_ADDERESS = '0xFadAFCE89EA2221fa33005640Acf2C923312F2b9';
export const MOCK_TX = '0xc21a1aaace40a8ee9dd3827ae5a85412a05755cc004469efaf3cfdd82c59a670';
export const MOCK_SIGNED_TX = ':f87a1b8504a817c80082520894c589ac793af309db9690d819abc9aab37d169f6a8814d1120d7b1600008e0deadbeef0cafebabe01234567891ba03cd26b08b246f23f74fceb2c063021955e691cf7d45fba443a2e504a4700dba5a0337b1f8dbf21ef35adf6e2a867d9c7bc836d1b79c8ab40c670385a2d0abca88c';
export const MOCK_TYPED_DATA = JSON.stringify({
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
{ name: 'salt', type: 'bytes32' },
],
Bid: [
{ name: 'amount', type: 'uint256' },
{ name: 'bidder', type: 'Identity' },
],
Identity: [
{ name: 'userId', type: 'uint256' },
{ name: 'wallet', type: 'address' },
],
},
domain: {
name: 'Provider Test',
version: '1',
chainId: Number.parseInt('1', 10),
verifyingContract: MOCK_ADDERESS,
salt: '0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558',
},
primaryType: 'Bid',
message: {
amount: 100,
bidder: {
userId: 323,
wallet: MOCK_ADDERESS,
},
},
});
//# sourceMappingURL=fixtures.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/mocks/fixtures.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,4CAA4C,CAAC;AAE1E,MAAM,CAAC,MAAM,OAAO,GAAG,oEAAoE,CAAC;AAE5F,MAAM,CAAC,MAAM,cAAc,GACzB,2PAA2P,CAAC;AAE9P,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC;IAC5C,KAAK,EAAE;QACL,YAAY,EAAE;YACZ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;YAChC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE;YACnC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;YACpC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,EAAE;YAC9C,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;SAClC;QACD,GAAG,EAAE;YACH,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;YACnC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE;SACrC;QACD,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;YACnC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;SACpC;KACF;IACD,MAAM,EAAE;QACN,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,GAAG;QACZ,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;QACjC,iBAAiB,EAAE,aAAa;QAChC,IAAI,EAAE,oEAAoE;KAC3E;IACD,WAAW,EAAE,KAAK;IAClB,OAAO,EAAE;QACP,MAAM,EAAE,GAAG;QACX,MAAM,EAAE;YACN,MAAM,EAAE,GAAG;YACX,MAAM,EAAE,aAAa;SACtB;KACF;CACF,CAAC,CAAC"}

View File

@@ -0,0 +1,3 @@
import { WalletLinkRelay } from '../WalletLinkRelay.js';
export declare function mockedWalletLinkRelay(): WalletLinkRelay;
//# sourceMappingURL=relay.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/mocks/relay.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAIxD,wBAAgB,qBAAqB,IAAI,eAAe,CAEvD"}

View File

@@ -0,0 +1,63 @@
import { MOCK_ADDERESS, MOCK_TX } from './fixtures.js';
import { AddressString, HexString } from '../../../../core/type/index.js';
export function mockedWalletLinkRelay() {
return mock;
}
function makeMockReturn(response) {
return Promise.resolve(response);
}
const mock = {
resetAndReload() { },
requestEthereumAccounts() {
return makeMockReturn({
method: 'requestEthereumAccounts',
result: [AddressString(MOCK_ADDERESS)],
});
},
addEthereumChain() {
return makeMockReturn({
method: 'addEthereumChain',
result: {
isApproved: true,
rpcUrl: 'https://node.ethchain.com',
},
});
},
watchAsset() {
return makeMockReturn({
method: 'watchAsset',
result: true,
});
},
switchEthereumChain() {
return makeMockReturn({
method: 'switchEthereumChain',
result: {
isApproved: true,
rpcUrl: 'https://node.ethchain.com',
},
});
},
signEthereumTransaction() {
return makeMockReturn({
method: 'signEthereumTransaction',
result: HexString(MOCK_TX),
});
},
signAndSubmitEthereumTransaction() {
return makeMockReturn({
method: 'submitEthereumTransaction',
result: HexString(MOCK_TX),
});
},
submitEthereumTransaction() {
return makeMockReturn({
method: 'submitEthereumTransaction',
result: HexString(MOCK_TX),
});
},
sendRequest() {
return Promise.reject();
},
};
//# sourceMappingURL=relay.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"relay.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/mocks/relay.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE/D,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAkC,CAAC;AAC5C,CAAC;AAED,SAAS,cAAc,CAAC,QAAsB;IAC5C,OAAO,OAAO,CAAC,OAAO,CAAe,QAAQ,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,IAAI,GAAG;IACX,cAAc,KAAU,CAAC;IACzB,uBAAuB;QACrB,OAAO,cAAc,CAAC;YACpB,MAAM,EAAE,yBAAyB;YACjC,MAAM,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;SACvC,CAAC,CAAC;IACL,CAAC;IACD,gBAAgB;QACd,OAAO,cAAc,CAAC;YACpB,MAAM,EAAE,kBAAkB;YAC1B,MAAM,EAAE;gBACN,UAAU,EAAE,IAAI;gBAChB,MAAM,EAAE,2BAA2B;aACpC;SACF,CAAC,CAAC;IACL,CAAC;IACD,UAAU;QACR,OAAO,cAAc,CAAC;YACpB,MAAM,EAAE,YAAY;YACpB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;IACL,CAAC;IACD,mBAAmB;QACjB,OAAO,cAAc,CAAC;YACpB,MAAM,EAAE,qBAAqB;YAC7B,MAAM,EAAE;gBACN,UAAU,EAAE,IAAI;gBAChB,MAAM,EAAE,2BAA2B;aACpC;SACF,CAAC,CAAC;IACL,CAAC;IACD,uBAAuB;QACrB,OAAO,cAAc,CAAC;YACpB,MAAM,EAAE,yBAAyB;YACjC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IACD,gCAAgC;QAC9B,OAAO,cAAc,CAAC;YACpB,MAAM,EAAE,2BAA2B;YACnC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IACD,yBAAyB;QACvB,OAAO,cAAc,CAAC;YACpB,MAAM,EAAE,2BAA2B;YACnC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IACD,WAAW;QACT,OAAO,OAAO,CAAC,MAAM,EAAgB,CAAC;IACxC,CAAC;CACF,CAAC"}

View File

@@ -0,0 +1,30 @@
import { IntNumber } from '../../../../core/type/index.js';
export type ClientMessage = {
type: 'HostSession';
id: IntNumber;
sessionId: string;
sessionKey: string;
} | {
type: 'IsLinked';
id: IntNumber;
sessionId: string;
} | {
type: 'GetSessionConfig';
id: IntNumber;
sessionId: string;
} | {
type: 'SetSessionConfig';
id: IntNumber;
sessionId: string;
metadata: {
[key: string]: string | null;
};
} | {
type: 'PublishEvent';
id: IntNumber;
sessionId: string;
event: string;
data: string;
callWebhook: boolean;
};
//# sourceMappingURL=ClientMessage.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ClientMessage.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/ClientMessage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,MAAM,aAAa,GACrB;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE,IAAI,EAAE,kBAAkB,CAAC;IACzB,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE,IAAI,EAAE,kBAAkB,CAAC;IACzB,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAC5C,GACD;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC"}

View File

@@ -0,0 +1,3 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
export {};
//# sourceMappingURL=ClientMessage.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ClientMessage.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/ClientMessage.ts"],"names":[],"mappings":"AAAA,qEAAqE"}

View File

@@ -0,0 +1,14 @@
import { AddressString, IntNumber } from '../../../../core/type/index.js';
export interface EthereumTransactionParams {
fromAddress: AddressString;
toAddress: AddressString | null;
weiValue: bigint;
data: Buffer;
nonce: IntNumber | null;
gasPriceInWei: bigint | null;
maxFeePerGas: bigint | null;
maxPriorityFeePerGas: bigint | null;
gasLimit: bigint | null;
chainId: number;
}
//# sourceMappingURL=EthereumTransactionParams.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EthereumTransactionParams.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/EthereumTransactionParams.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE/D,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,aAAa,CAAC;IAC3B,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=EthereumTransactionParams.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EthereumTransactionParams.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/EthereumTransactionParams.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,61 @@
import { IntNumber } from '../../../../core/type/index.js';
export type ServerMessage<T extends Type = Type> = Extract<_ServerMessage, {
type: T;
}>;
export type ServerMessageType = Type;
type Type = _ServerMessage['type'];
type _ServerMessage = {
type: 'Heartbeat';
} | {
type: 'OK';
id: IntNumber;
sessionId: string;
} | {
type: 'Fail';
id: IntNumber;
sessionId: string;
error: string;
} | {
type: 'IsLinkedOK';
id: IntNumber;
sessionId: string;
linked: boolean;
onlineGuests: number;
} | {
type: 'Linked';
id?: IntNumber;
sessionId: string;
onlineGuests: number;
} | {
type: 'GetSessionConfigOK';
id: IntNumber;
sessionId: string;
webhookId: string;
webhookUrl: string;
metadata: {
[field: string]: string;
};
} | {
type: 'SessionConfigUpdated';
id?: IntNumber;
sessionId: string;
webhookId: string;
webhookUrl: string;
metadata: {
[field: string]: string;
};
} | {
type: 'PublishEventOK';
id: IntNumber;
sessionId: string;
eventId: string;
} | {
type: 'Event';
id?: IntNumber;
sessionId: string;
eventId: string;
event: string;
data: string;
};
export {};
//# sourceMappingURL=ServerMessage.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ServerMessage.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/ServerMessage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,IAAI,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,CAAC;AAExF,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC;AACrC,KAAK,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;AAEnC,KAAK,cAAc,GACf;IACE,IAAI,EAAE,WAAW,CAAC;CACnB,GACD;IACE,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,GACD;IACE,IAAI,EAAE,YAAY,CAAC;IACnB,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,IAAI,EAAE,oBAAoB,CAAC;IAC3B,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACvC,GACD;IACE,IAAI,EAAE,sBAAsB,CAAC;IAC7B,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACvC,GACD;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,EAAE,EAAE,SAAS,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC"}

View File

@@ -0,0 +1,3 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
export {};
//# sourceMappingURL=ServerMessage.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ServerMessage.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/ServerMessage.ts"],"names":[],"mappings":"AAAA,qEAAqE"}

View File

@@ -0,0 +1,15 @@
import { Web3Request } from './Web3Request.js';
import { Web3Response } from './Web3Response.js';
export type WalletLinkEventData = {
type: 'WEB3_RESPONSE';
id: string;
response: Web3Response;
} | {
type: 'WEB3_REQUEST';
id: string;
request: Web3Request;
} | {
type: 'WEB3_REQUEST_CANCELED';
id: string;
};
//# sourceMappingURL=WalletLinkEventData.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkEventData.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/WalletLinkEventData.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,MAAM,mBAAmB,GAC3B;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC;CACxB,GACD;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,WAAW,CAAC;CACtB,GACD;IACE,IAAI,EAAE,uBAAuB,CAAC;IAC9B,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC"}

View File

@@ -0,0 +1,3 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
export {};
//# sourceMappingURL=WalletLinkEventData.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkEventData.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/WalletLinkEventData.ts"],"names":[],"mappings":"AAAA,qEAAqE"}

View File

@@ -0,0 +1,16 @@
import { ScopedLocalStorage } from '../../../../core/storage/ScopedLocalStorage.js';
export declare class WalletLinkSession {
readonly storage: ScopedLocalStorage;
readonly id: string;
readonly secret: string;
readonly key: string;
private _linked;
private constructor();
static create(storage: ScopedLocalStorage): WalletLinkSession;
static load(storage: ScopedLocalStorage): WalletLinkSession | null;
get linked(): boolean;
set linked(val: boolean);
save(): WalletLinkSession;
private persistLinked;
}
//# sourceMappingURL=WalletLinkSession.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkSession.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/WalletLinkSession.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAOzE,qBAAa,iBAAiB;IAK1B,QAAQ,CAAC,OAAO,EAAE,kBAAkB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM;IANzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,OAAO,CAAU;IAEzB,OAAO;WAUO,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB;WAMtD,IAAI,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,GAAG,IAAI;IAYzE,IAAW,MAAM,IAAI,OAAO,CAE3B;IAED,IAAW,MAAM,CAAC,GAAG,EAAE,OAAO,EAG7B;IAEM,IAAI,IAAI,iBAAiB;IAOhC,OAAO,CAAC,aAAa;CAGtB"}

View File

@@ -0,0 +1,47 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
import { sha256 } from '@noble/hashes/sha256';
import { bytesToHex } from '@noble/hashes/utils';
import { randomBytesHex } from '../../../../core/type/util.js';
const STORAGE_KEY_SESSION_ID = 'session:id';
const STORAGE_KEY_SESSION_SECRET = 'session:secret';
const STORAGE_KEY_SESSION_LINKED = 'session:linked';
export class WalletLinkSession {
constructor(storage, id, secret, linked = false) {
this.storage = storage;
this.id = id;
this.secret = secret;
this.key = bytesToHex(sha256(`${id}, ${secret} WalletLink`));
this._linked = !!linked;
}
static create(storage) {
const id = randomBytesHex(16);
const secret = randomBytesHex(32);
return new WalletLinkSession(storage, id, secret).save();
}
static load(storage) {
const id = storage.getItem(STORAGE_KEY_SESSION_ID);
const linked = storage.getItem(STORAGE_KEY_SESSION_LINKED);
const secret = storage.getItem(STORAGE_KEY_SESSION_SECRET);
if (id && secret) {
return new WalletLinkSession(storage, id, secret, linked === '1');
}
return null;
}
get linked() {
return this._linked;
}
set linked(val) {
this._linked = val;
this.persistLinked();
}
save() {
this.storage.setItem(STORAGE_KEY_SESSION_ID, this.id);
this.storage.setItem(STORAGE_KEY_SESSION_SECRET, this.secret);
this.persistLinked();
return this;
}
persistLinked() {
this.storage.setItem(STORAGE_KEY_SESSION_LINKED, this._linked ? '1' : '0');
}
}
//# sourceMappingURL=WalletLinkSession.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkSession.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/WalletLinkSession.ts"],"names":[],"mappings":"AAAA,qEAAqE;AAErE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,sBAAsB,GAAG,YAAY,CAAC;AAC5C,MAAM,0BAA0B,GAAG,gBAAgB,CAAC;AACpD,MAAM,0BAA0B,GAAG,gBAAgB,CAAC;AAEpD,MAAM,OAAO,iBAAiB;IAI5B,YACW,OAA2B,EAC3B,EAAU,EACV,MAAc,EACvB,MAAM,GAAG,KAAK;QAHL,YAAO,GAAP,OAAO,CAAoB;QAC3B,OAAE,GAAF,EAAE,CAAQ;QACV,WAAM,GAAN,MAAM,CAAQ;QAGvB,IAAI,CAAC,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,MAAM,aAAa,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,CAAC;IAEM,MAAM,CAAC,MAAM,CAAC,OAA2B;QAC9C,MAAM,EAAE,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;QAClC,OAAO,IAAI,iBAAiB,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3D,CAAC;IAEM,MAAM,CAAC,IAAI,CAAC,OAA2B;QAC5C,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;QAE3D,IAAI,EAAE,IAAI,MAAM,EAAE,CAAC;YACjB,OAAO,IAAI,iBAAiB,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,KAAK,GAAG,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,IAAW,MAAM,CAAC,GAAY;QAC5B,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAEM,IAAI;QACT,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,sBAAsB,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,0BAA0B,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9D,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,aAAa;QACnB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,0BAA0B,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7E,CAAC;CACF"}

View File

@@ -0,0 +1,99 @@
import { AddressString, BigIntString, HexString, IntNumber } from '../../../../core/type/index.js';
export type Web3Method = _Web3Request['method'];
export type Web3Request<M extends Web3Method = Web3Method> = Extract<_Web3Request, {
method: M;
}>;
type _Web3Request = {
method: 'requestEthereumAccounts';
params: {
appName: string;
appLogoUrl: string | null;
};
} | {
method: 'childRequestEthereumAccounts';
} | {
method: 'connectAndSignIn';
params: {
appName: string;
appLogoUrl: string | null;
domain: string;
aud: string;
version: string;
type: string;
nonce: string;
iat: string;
chainId: string;
statement?: string;
resources?: string[];
};
} | {
method: 'addEthereumChain';
params: {
chainId: string;
blockExplorerUrls?: string[];
chainName?: string;
iconUrls?: string[];
rpcUrls: string[];
nativeCurrency?: {
name: string;
symbol: string;
decimals: number;
};
};
} | {
method: 'switchEthereumChain';
params: {
chainId: string;
address?: string;
};
} | {
method: 'signEthereumMessage';
params: {
message: HexString;
address: AddressString;
addPrefix: boolean;
typedDataJson: string | null;
};
} | {
method: 'signEthereumTransaction';
params: {
fromAddress: AddressString;
toAddress: AddressString | null;
weiValue: BigIntString;
data: HexString;
nonce: IntNumber | null;
gasPriceInWei: BigIntString | null;
maxFeePerGas: BigIntString | null;
maxPriorityFeePerGas: BigIntString | null;
gasLimit: BigIntString | null;
chainId: number;
shouldSubmit: boolean;
};
} | {
method: 'submitEthereumTransaction';
params: {
signedTransaction: HexString;
chainId: number;
};
} | {
method: 'ethereumAddressFromSignedMessage';
params: {
message: HexString;
signature: HexString;
addPrefix: boolean;
};
} | {
method: 'watchAsset';
params: {
type: string;
options: {
address: string;
symbol?: string;
decimals?: number;
image?: string;
};
chainId?: string;
};
};
export {};
//# sourceMappingURL=Web3Request.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Web3Request.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/Web3Request.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,3 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
export {};
//# sourceMappingURL=Web3Request.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Web3Request.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/Web3Request.ts"],"names":[],"mappings":"AAAA,qEAAqE"}

View File

@@ -0,0 +1,51 @@
import { Web3Method } from './Web3Request.js';
import { AddressString, HexString } from '../../../../core/type/index.js';
export type Web3Response<M extends Web3Method = Web3Method> = Extract<_Web3Response, {
method: M;
}> | ErrorResponse;
type ErrorResponse = {
method: unknown;
errorCode?: number;
errorMessage: string;
};
export declare function isErrorResponse(response: unknown): response is ErrorResponse;
type _Web3Response = {
method: 'connectAndSignIn';
result: {
accounts: AddressString[];
message: HexString;
signature: HexString;
};
} | {
method: 'addEthereumChain';
result: {
isApproved: boolean;
rpcUrl: string;
};
} | {
method: 'switchEthereumChain';
result: {
isApproved: boolean;
rpcUrl: string;
};
} | {
method: 'requestEthereumAccounts';
result: AddressString[];
} | {
method: 'watchAsset';
result: boolean;
} | {
method: 'signEthereumMessage';
result: HexString;
} | {
method: 'signEthereumTransaction';
result: HexString;
} | {
method: 'submitEthereumTransaction';
result: HexString;
} | {
method: 'ethereumAddressFromSignedMessage';
result: AddressString;
};
export {};
//# sourceMappingURL=Web3Response.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Web3Response.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/Web3Response.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE/D,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,IACtD,OAAO,CAAC,aAAa,EAAE;IAAE,MAAM,EAAE,CAAC,CAAA;CAAE,CAAC,GACrC,aAAa,CAAC;AAElB,KAAK,aAAa,GAAG;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,IAAI,aAAa,CAE5E;AAED,KAAK,aAAa,GACd;IACE,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE;QACN,QAAQ,EAAE,aAAa,EAAE,CAAC;QAC1B,OAAO,EAAE,SAAS,CAAC;QACnB,SAAS,EAAE,SAAS,CAAC;KACtB,CAAC;CACH,GACD;IACE,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE;QACN,UAAU,EAAE,OAAO,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,GACD;IACE,MAAM,EAAE,qBAAqB,CAAC;IAC9B,MAAM,EAAE;QACN,UAAU,EAAE,OAAO,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,GACD;IACE,MAAM,EAAE,yBAAyB,CAAC;IAClC,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB,GACD;IACE,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB,GACD;IACE,MAAM,EAAE,qBAAqB,CAAC;IAC9B,MAAM,EAAE,SAAS,CAAC;CACnB,GACD;IACE,MAAM,EAAE,yBAAyB,CAAC;IAClC,MAAM,EAAE,SAAS,CAAC;CACnB,GACD;IACE,MAAM,EAAE,2BAA2B,CAAC;IACpC,MAAM,EAAE,SAAS,CAAC;CACnB,GACD;IACE,MAAM,EAAE,kCAAkC,CAAC;IAC3C,MAAM,EAAE,aAAa,CAAC;CACvB,CAAC"}

View File

@@ -0,0 +1,5 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
export function isErrorResponse(response) {
return response.errorMessage !== undefined;
}
//# sourceMappingURL=Web3Response.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Web3Response.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/type/Web3Response.ts"],"names":[],"mappings":"AAAA,qEAAqE;AAerE,MAAM,UAAU,eAAe,CAAC,QAAiB;IAC/C,OAAQ,QAA0B,CAAC,YAAY,KAAK,SAAS,CAAC;AAChE,CAAC"}

View File

@@ -0,0 +1,16 @@
export interface RelayUI {
attach(): void;
/**
*
* @param options onCancel callback for user clicking cancel,
* onResetConnection user clicked reset connection
*
* @returns callback that call can call to hide the connecting ui
*/
showConnecting(options: {
isUnlinkedErrorState?: boolean;
onCancel: (error?: Error) => void;
onResetConnection: () => void;
}): () => void;
}
//# sourceMappingURL=RelayUI.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"RelayUI.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/ui/RelayUI.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,MAAM,IAAI,IAAI,CAAC;IAEf;;;;;;OAMG;IACH,cAAc,CAAC,OAAO,EAAE;QACtB,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;QAClC,iBAAiB,EAAE,MAAM,IAAI,CAAC;KAC/B,GAAG,MAAM,IAAI,CAAC;CAChB"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=RelayUI.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"RelayUI.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/ui/RelayUI.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,15 @@
import { RelayUI } from './RelayUI.js';
export declare class WLMobileRelayUI implements RelayUI {
private readonly redirectDialog;
private attached;
constructor();
attach(): void;
private redirectToCoinbaseWallet;
openCoinbaseWalletDeeplink(walletLinkUrl?: string): void;
showConnecting(_options: {
isUnlinkedErrorState?: boolean | undefined;
onCancel: (error?: Error) => void;
onResetConnection: () => void;
}): () => void;
}
//# sourceMappingURL=WLMobileRelayUI.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WLMobileRelayUI.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/ui/WLMobileRelayUI.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,qBAAa,eAAgB,YAAW,OAAO;IAC7C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAS;;IAMzB,MAAM;IAQN,OAAO,CAAC,wBAAwB;IAehC,0BAA0B,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI;IAexD,cAAc,CAAC,QAAQ,EAAE;QACvB,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QAC3C,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;QAClC,iBAAiB,EAAE,MAAM,IAAI,CAAC;KAC/B,GAAG,MAAM,IAAI;CAMf"}

View File

@@ -0,0 +1,48 @@
import { RedirectDialog } from './components/RedirectDialog/RedirectDialog.js';
import { getLocation } from './components/util.js';
import { CBW_MOBILE_DEEPLINK_URL } from '../../../../core/constants.js';
export class WLMobileRelayUI {
constructor() {
this.attached = false;
this.redirectDialog = new RedirectDialog();
}
attach() {
if (this.attached) {
throw new Error('Coinbase Wallet SDK UI is already attached');
}
this.redirectDialog.attach();
this.attached = true;
}
redirectToCoinbaseWallet(walletLinkUrl) {
const url = new URL(CBW_MOBILE_DEEPLINK_URL);
url.searchParams.append('redirect_url', getLocation().href);
if (walletLinkUrl) {
url.searchParams.append('wl_url', walletLinkUrl);
}
const anchorTag = document.createElement('a');
anchorTag.target = 'cbw-opener';
anchorTag.href = url.href;
anchorTag.rel = 'noreferrer noopener';
anchorTag.click();
}
openCoinbaseWalletDeeplink(walletLinkUrl) {
// redirect to coinbase wallet immediately to avoid Safari/Chrome popup(deeplink) blocking
this.redirectToCoinbaseWallet(walletLinkUrl);
setTimeout(() => {
this.redirectDialog.present({
title: 'Redirecting to Coinbase Wallet...',
buttonText: 'Open',
onButtonClick: () => {
this.redirectToCoinbaseWallet(walletLinkUrl);
},
});
}, 99);
}
showConnecting(_options) {
// it uses the return callback to clear the dialog
return () => {
this.redirectDialog.clear();
};
}
}
//# sourceMappingURL=WLMobileRelayUI.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WLMobileRelayUI.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/ui/WLMobileRelayUI.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,+CAA+C,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,MAAM,OAAO,eAAe;IAI1B;QAFQ,aAAQ,GAAG,KAAK,CAAC;QAGvB,IAAI,CAAC,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;IAC7C,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;IAEO,wBAAwB,CAAC,aAAsB;QACrD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,uBAAuB,CAAC,CAAC;QAE7C,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC;QAC5D,IAAI,aAAa,EAAE,CAAC;YAClB,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAC9C,SAAS,CAAC,MAAM,GAAG,YAAY,CAAC;QAChC,SAAS,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QAC1B,SAAS,CAAC,GAAG,GAAG,qBAAqB,CAAC;QACtC,SAAS,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED,0BAA0B,CAAC,aAAsB;QAC/C,0FAA0F;QAC1F,IAAI,CAAC,wBAAwB,CAAC,aAAa,CAAC,CAAC;QAE7C,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;gBAC1B,KAAK,EAAE,mCAAmC;gBAC1C,UAAU,EAAE,MAAM;gBAClB,aAAa,EAAE,GAAG,EAAE;oBAClB,IAAI,CAAC,wBAAwB,CAAC,aAAa,CAAC,CAAC;gBAC/C,CAAC;aACF,CAAC,CAAC;QACL,CAAC,EAAE,EAAE,CAAC,CAAC;IACT,CAAC;IAED,cAAc,CAAC,QAId;QACC,kDAAkD;QAClD,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAC9B,CAAC,CAAC;IACJ,CAAC;CACF"}

View File

@@ -0,0 +1,14 @@
import { RelayUI } from './RelayUI.js';
export declare const RETRY_SVG_PATH = "M5.00008 0.96875C6.73133 0.96875 8.23758 1.94375 9.00008 3.375L10.0001 2.375V5.5H9.53133H7.96883H6.87508L7.80633 4.56875C7.41258 3.3875 6.31258 2.53125 5.00008 2.53125C3.76258 2.53125 2.70633 3.2875 2.25633 4.36875L0.812576 3.76875C1.50008 2.125 3.11258 0.96875 5.00008 0.96875ZM2.19375 6.43125C2.5875 7.6125 3.6875 8.46875 5 8.46875C6.2375 8.46875 7.29375 7.7125 7.74375 6.63125L9.1875 7.23125C8.5 8.875 6.8875 10.0312 5 10.0312C3.26875 10.0312 1.7625 9.05625 1 7.625L0 8.625V5.5H0.46875H2.03125H3.125L2.19375 6.43125Z";
export declare class WalletLinkRelayUI implements RelayUI {
private readonly snackbar;
private attached;
constructor();
attach(): void;
showConnecting(options: {
isUnlinkedErrorState?: boolean;
onCancel: (error?: Error) => void;
onResetConnection: () => void;
}): () => void;
}
//# sourceMappingURL=WalletLinkRelayUI.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkRelayUI.d.ts","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/ui/WalletLinkRelayUI.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,eAAO,MAAM,cAAc,4gBACgf,CAAC;AAE5gB,qBAAa,iBAAkB,YAAW,OAAO;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAS;;IAMzB,MAAM,IAAI,IAAI;IAed,cAAc,CAAC,OAAO,EAAE;QACtB,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;QAClC,iBAAiB,EAAE,MAAM,IAAI,CAAC;KAC/B,GAAG,MAAM,IAAI;CAiDf"}

View File

@@ -0,0 +1,71 @@
import { injectCssReset } from './components/cssReset/cssReset.js';
import { Snackbar } from './components/Snackbar/Snackbar.js';
export const RETRY_SVG_PATH = 'M5.00008 0.96875C6.73133 0.96875 8.23758 1.94375 9.00008 3.375L10.0001 2.375V5.5H9.53133H7.96883H6.87508L7.80633 4.56875C7.41258 3.3875 6.31258 2.53125 5.00008 2.53125C3.76258 2.53125 2.70633 3.2875 2.25633 4.36875L0.812576 3.76875C1.50008 2.125 3.11258 0.96875 5.00008 0.96875ZM2.19375 6.43125C2.5875 7.6125 3.6875 8.46875 5 8.46875C6.2375 8.46875 7.29375 7.7125 7.74375 6.63125L9.1875 7.23125C8.5 8.875 6.8875 10.0312 5 10.0312C3.26875 10.0312 1.7625 9.05625 1 7.625L0 8.625V5.5H0.46875H2.03125H3.125L2.19375 6.43125Z';
export class WalletLinkRelayUI {
constructor() {
this.attached = false;
this.snackbar = new Snackbar();
}
attach() {
if (this.attached) {
throw new Error('Coinbase Wallet SDK UI is already attached');
}
const el = document.documentElement;
const container = document.createElement('div');
container.className = '-cbwsdk-css-reset';
el.appendChild(container);
this.snackbar.attach(container);
this.attached = true;
injectCssReset();
}
showConnecting(options) {
let snackbarProps;
if (options.isUnlinkedErrorState) {
snackbarProps = {
autoExpand: true,
message: 'Connection lost',
menuItems: [
{
isRed: false,
info: 'Reset connection',
svgWidth: '10',
svgHeight: '11',
path: 'M5.00008 0.96875C6.73133 0.96875 8.23758 1.94375 9.00008 3.375L10.0001 2.375V5.5H9.53133H7.96883H6.87508L7.80633 4.56875C7.41258 3.3875 6.31258 2.53125 5.00008 2.53125C3.76258 2.53125 2.70633 3.2875 2.25633 4.36875L0.812576 3.76875C1.50008 2.125 3.11258 0.96875 5.00008 0.96875ZM2.19375 6.43125C2.5875 7.6125 3.6875 8.46875 5 8.46875C6.2375 8.46875 7.29375 7.7125 7.74375 6.63125L9.1875 7.23125C8.5 8.875 6.8875 10.0312 5 10.0312C3.26875 10.0312 1.7625 9.05625 1 7.625L0 8.625V5.5H0.46875H2.03125H3.125L2.19375 6.43125Z',
defaultFillRule: 'evenodd',
defaultClipRule: 'evenodd',
onClick: options.onResetConnection,
},
],
};
}
else {
snackbarProps = {
message: 'Confirm on phone',
menuItems: [
{
isRed: true,
info: 'Cancel transaction',
svgWidth: '11',
svgHeight: '11',
path: 'M10.3711 1.52346L9.21775 0.370117L5.37109 4.21022L1.52444 0.370117L0.371094 1.52346L4.2112 5.37012L0.371094 9.21677L1.52444 10.3701L5.37109 6.53001L9.21775 10.3701L10.3711 9.21677L6.53099 5.37012L10.3711 1.52346Z',
defaultFillRule: 'inherit',
defaultClipRule: 'inherit',
onClick: options.onCancel,
},
{
isRed: false,
info: 'Reset connection',
svgWidth: '10',
svgHeight: '11',
path: RETRY_SVG_PATH,
defaultFillRule: 'evenodd',
defaultClipRule: 'evenodd',
onClick: options.onResetConnection,
},
],
};
}
return this.snackbar.presentItem(snackbarProps);
}
}
//# sourceMappingURL=WalletLinkRelayUI.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"WalletLinkRelayUI.js","sourceRoot":"","sources":["../../../../../src/sign/walletlink/relay/ui/WalletLinkRelayUI.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAyB,MAAM,mCAAmC,CAAC;AAGpF,MAAM,CAAC,MAAM,cAAc,GACzB,ygBAAygB,CAAC;AAE5gB,MAAM,OAAO,iBAAiB;IAI5B;QAFQ,aAAQ,GAAG,KAAK,CAAC;QAGvB,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IACjC,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QACD,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QACpC,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAChD,SAAS,CAAC,SAAS,GAAG,mBAAmB,CAAC;QAC1C,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAE1B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,cAAc,EAAE,CAAC;IACnB,CAAC;IAED,cAAc,CAAC,OAId;QACC,IAAI,aAAoC,CAAC;QACzC,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;YACjC,aAAa,GAAG;gBACd,UAAU,EAAE,IAAI;gBAChB,OAAO,EAAE,iBAAiB;gBAC1B,SAAS,EAAE;oBACT;wBACE,KAAK,EAAE,KAAK;wBACZ,IAAI,EAAE,kBAAkB;wBACxB,QAAQ,EAAE,IAAI;wBACd,SAAS,EAAE,IAAI;wBACf,IAAI,EAAE,ygBAAygB;wBAC/gB,eAAe,EAAE,SAAS;wBAC1B,eAAe,EAAE,SAAS;wBAC1B,OAAO,EAAE,OAAO,CAAC,iBAAiB;qBACnC;iBACF;aACF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,aAAa,GAAG;gBACd,OAAO,EAAE,kBAAkB;gBAC3B,SAAS,EAAE;oBACT;wBACE,KAAK,EAAE,IAAI;wBACX,IAAI,EAAE,oBAAoB;wBAC1B,QAAQ,EAAE,IAAI;wBACd,SAAS,EAAE,IAAI;wBACf,IAAI,EAAE,sNAAsN;wBAC5N,eAAe,EAAE,SAAS;wBAC1B,eAAe,EAAE,SAAS;wBAC1B,OAAO,EAAE,OAAO,CAAC,QAAQ;qBAC1B;oBACD;wBACE,KAAK,EAAE,KAAK;wBACZ,IAAI,EAAE,kBAAkB;wBACxB,QAAQ,EAAE,IAAI;wBACd,SAAS,EAAE,IAAI;wBACf,IAAI,EAAE,cAAc;wBACpB,eAAe,EAAE,SAAS;wBAC1B,eAAe,EAAE,SAAS;wBAC1B,OAAO,EAAE,OAAO,CAAC,iBAAiB;qBACnC;iBACF;aACF,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IAClD,CAAC;CACF"}

Some files were not shown because too many files have changed in this diff Show More