Socket
Socket
Sign inDemoInstall

@0xsequence/sessions

Package Overview
Dependencies
Maintainers
5
Versions
257
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@0xsequence/sessions - npm Package Compare versions

Comparing version 0.0.0-20230307215941 to 0.0.0-20230309013947

dist/declarations/src/trackers/promise-cache.d.ts

133

dist/0xsequence-sessions.cjs.dev.js

@@ -346,5 +346,6 @@ 'use strict';

if (isPlainNode(node)) {
const [left, right] = await Promise.all([_this.loadTopology(node.left), _this.loadTopology(node.right)]);
return {
left: await _this.loadTopology(node.left),
right: await _this.loadTopology(node.right)
left,
right
};

@@ -1253,12 +1254,3 @@ }

async function allSafe(promises, fallback) {
const results = [];
for (const p of promises) {
try {
results.push(await p);
} catch (_unused) {
// Ignore
results.push(fallback);
}
}
return results;
return Promise.all(promises.map(promise => promise.catch(() => fallback)));
}

@@ -1448,7 +1440,18 @@ class MultipleTracker {

var _this = this;
const configs = new Map();
const configOf = imageHash => {
if (!configs.has(imageHash)) {
configs.set(imageHash, this.configOfImageHash({
imageHash
}));
}
return configs.get(imageHash);
};
// We need to check both, and return the one with the highest checkpoint
// eventually we could try to combine them, but for now we'll just return
// the one with the highest checkpoint
const results = await Promise.all([this.tracker.loadPresignedConfiguration(args), this.cache.loadPresignedConfiguration(args)]);
const checkpoints = await Promise.all(results.map(async function (r) {
const results = [this.tracker.loadPresignedConfiguration(args), this.cache.loadPresignedConfiguration(args)];
const checkpoints = await Promise.all(results.map(async function (result) {
const r = await result;
const last = r[r.length - 1];

@@ -1458,5 +1461,3 @@ if (!last) return undefined;

// TODO: This will fire a lot of requests, optimize it
const config = await _this.configOfImageHash({
imageHash: last.nextImageHash
});
const config = await configOf(last.nextImageHash);
if (!config) return undefined;

@@ -1475,13 +1476,4 @@ return {

if (!best) return [];
const configs = new Map();
const config = imageHash => {
if (!configs.has(imageHash)) {
configs.set(imageHash, this.configOfImageHash({
imageHash
}));
}
return configs.get(imageHash);
};
best.result.forEach(async function (res) {
const nextConfig = await config(res.nextImageHash);
const nextConfig = await configOf(res.nextImageHash);
if (nextConfig) {

@@ -1571,2 +1563,38 @@ _this.savePresignedConfiguration({

class PromiseCache {
constructor() {
this.cache = void 0;
this.cache = new Map();
}
do(key, validMilliseconds, task, ...args) {
key = `${key}:${ethers.ethers.utils.keccak256(ethers.ethers.utils.toUtf8Bytes(JSON.stringify(args)))}`;
let entry = this.cache.get(key);
if (entry) {
if (entry.expiration) {
if (new Date() >= entry.expiration) {
entry = undefined;
this.cache.delete(key);
}
}
}
if (!entry) {
entry = {
promise: Promise.reject('unreachable')
};
if (validMilliseconds === undefined) {
entry.promise = task(...args);
} else {
entry.promise = task(...args).then(result => {
if (entry) {
entry.expiration = new Date(Date.now() + validMilliseconds);
}
return result;
});
}
this.cache.set(key, entry);
}
return entry.promise;
}
}
// This tracks wraps another tracker and dedupes calls to it, so in any calls

@@ -1580,62 +1608,33 @@ // are sent in short succession, only the first call is forwarded to the

this.verbose = verbose;
this.pending = new Map();
this.cache = new PromiseCache();
}
async dedupe(key, fn, ...args) {
this.clear();
// TODO: Replace with a faster hash function
const subkey = `${key}:${ethers.ethers.utils.keccak256(ethers.ethers.utils.toUtf8Bytes(JSON.stringify(args)))}`;
const now = Date.now();
const pending = this.pending.get(subkey);
if (pending && now - pending.time < this.window) {
if (this.verbose) {
console.log(`dedupe hit: ${subkey} -> found (${pending.time})`);
}
return pending.promise;
}
const promise = fn(...args);
this.pending.set(subkey, {
promise,
time: now
});
return promise;
}
clear() {
// remove all pending calls past the window
const now = Date.now();
for (const [key, pending] of this.pending) {
if (now - pending.time > this.window) {
this.pending.delete(key);
}
}
}
configOfImageHash(args) {
return this.dedupe('configOfImageHash', args => this.tracker.configOfImageHash(args), args);
return this.cache.do('configOfImageHash', this.window, args => this.tracker.configOfImageHash(args), args);
}
getMigration(address, fromImageHash, fromVersion, chainId) {
return this.dedupe('getMigration', (...args) => this.tracker.getMigration(...args), address, fromImageHash, fromVersion, chainId);
return this.cache.do('getMigration', this.window, (...args) => this.tracker.getMigration(...args), address, fromImageHash, fromVersion, chainId);
}
saveMigration(address, signed, contexts) {
return this.dedupe('saveMigration', (...args) => this.tracker.saveMigration(...args), address, signed, contexts);
return this.cache.do('saveMigration', undefined, (...args) => this.tracker.saveMigration(...args), address, signed, contexts);
}
loadPresignedConfiguration(args) {
return this.dedupe('loadPresignedConfiguration', args => this.tracker.loadPresignedConfiguration(args), args);
return this.cache.do('loadPresignedConfiguration', this.window, args => this.tracker.loadPresignedConfiguration(args), args);
}
savePresignedConfiguration(args) {
return this.dedupe('savePresignedConfiguration', args => this.tracker.savePresignedConfiguration(args), args);
return this.cache.do('savePresignedConfiguration', undefined, args => this.tracker.savePresignedConfiguration(args), args);
}
saveWitnesses(args) {
return this.dedupe('saveWitnesses', args => this.tracker.saveWitnesses(args), args);
return this.cache.do('saveWitnesses', undefined, args => this.tracker.saveWitnesses(args), args);
}
saveWalletConfig(args) {
return this.dedupe('saveWalletConfig', args => this.tracker.saveWalletConfig(args), args);
return this.cache.do('saveWalletConfig', undefined, args => this.tracker.saveWalletConfig(args), args);
}
imageHashOfCounterfactualWallet(args) {
return this.dedupe('imageHashOfCounterfactualWallet', args => this.tracker.imageHashOfCounterfactualWallet(args), args);
return this.cache.do('imageHashOfCounterfactualWallet', undefined, args => this.tracker.imageHashOfCounterfactualWallet(args), args);
}
saveCounterfactualWallet(args) {
return this.dedupe('saveCounterfactualWallet', args => this.tracker.saveCounterfactualWallet(args), args);
return this.cache.do('saveCounterfactualWallet', undefined, args => this.tracker.saveCounterfactualWallet(args), args);
}
walletsOfSigner(args) {
return this.dedupe('walletsOfSigner', args => this.tracker.walletsOfSigner(args), args);
return this.cache.do('walletsOfSigner', this.window, args => this.tracker.walletsOfSigner(args), args);
}

@@ -1642,0 +1641,0 @@ }

@@ -346,5 +346,6 @@ 'use strict';

if (isPlainNode(node)) {
const [left, right] = await Promise.all([_this.loadTopology(node.left), _this.loadTopology(node.right)]);
return {
left: await _this.loadTopology(node.left),
right: await _this.loadTopology(node.right)
left,
right
};

@@ -1253,12 +1254,3 @@ }

async function allSafe(promises, fallback) {
const results = [];
for (const p of promises) {
try {
results.push(await p);
} catch (_unused) {
// Ignore
results.push(fallback);
}
}
return results;
return Promise.all(promises.map(promise => promise.catch(() => fallback)));
}

@@ -1448,7 +1440,18 @@ class MultipleTracker {

var _this = this;
const configs = new Map();
const configOf = imageHash => {
if (!configs.has(imageHash)) {
configs.set(imageHash, this.configOfImageHash({
imageHash
}));
}
return configs.get(imageHash);
};
// We need to check both, and return the one with the highest checkpoint
// eventually we could try to combine them, but for now we'll just return
// the one with the highest checkpoint
const results = await Promise.all([this.tracker.loadPresignedConfiguration(args), this.cache.loadPresignedConfiguration(args)]);
const checkpoints = await Promise.all(results.map(async function (r) {
const results = [this.tracker.loadPresignedConfiguration(args), this.cache.loadPresignedConfiguration(args)];
const checkpoints = await Promise.all(results.map(async function (result) {
const r = await result;
const last = r[r.length - 1];

@@ -1458,5 +1461,3 @@ if (!last) return undefined;

// TODO: This will fire a lot of requests, optimize it
const config = await _this.configOfImageHash({
imageHash: last.nextImageHash
});
const config = await configOf(last.nextImageHash);
if (!config) return undefined;

@@ -1475,13 +1476,4 @@ return {

if (!best) return [];
const configs = new Map();
const config = imageHash => {
if (!configs.has(imageHash)) {
configs.set(imageHash, this.configOfImageHash({
imageHash
}));
}
return configs.get(imageHash);
};
best.result.forEach(async function (res) {
const nextConfig = await config(res.nextImageHash);
const nextConfig = await configOf(res.nextImageHash);
if (nextConfig) {

@@ -1571,2 +1563,38 @@ _this.savePresignedConfiguration({

class PromiseCache {
constructor() {
this.cache = void 0;
this.cache = new Map();
}
do(key, validMilliseconds, task, ...args) {
key = `${key}:${ethers.ethers.utils.keccak256(ethers.ethers.utils.toUtf8Bytes(JSON.stringify(args)))}`;
let entry = this.cache.get(key);
if (entry) {
if (entry.expiration) {
if (new Date() >= entry.expiration) {
entry = undefined;
this.cache.delete(key);
}
}
}
if (!entry) {
entry = {
promise: Promise.reject('unreachable')
};
if (validMilliseconds === undefined) {
entry.promise = task(...args);
} else {
entry.promise = task(...args).then(result => {
if (entry) {
entry.expiration = new Date(Date.now() + validMilliseconds);
}
return result;
});
}
this.cache.set(key, entry);
}
return entry.promise;
}
}
// This tracks wraps another tracker and dedupes calls to it, so in any calls

@@ -1580,62 +1608,33 @@ // are sent in short succession, only the first call is forwarded to the

this.verbose = verbose;
this.pending = new Map();
this.cache = new PromiseCache();
}
async dedupe(key, fn, ...args) {
this.clear();
// TODO: Replace with a faster hash function
const subkey = `${key}:${ethers.ethers.utils.keccak256(ethers.ethers.utils.toUtf8Bytes(JSON.stringify(args)))}`;
const now = Date.now();
const pending = this.pending.get(subkey);
if (pending && now - pending.time < this.window) {
if (this.verbose) {
console.log(`dedupe hit: ${subkey} -> found (${pending.time})`);
}
return pending.promise;
}
const promise = fn(...args);
this.pending.set(subkey, {
promise,
time: now
});
return promise;
}
clear() {
// remove all pending calls past the window
const now = Date.now();
for (const [key, pending] of this.pending) {
if (now - pending.time > this.window) {
this.pending.delete(key);
}
}
}
configOfImageHash(args) {
return this.dedupe('configOfImageHash', args => this.tracker.configOfImageHash(args), args);
return this.cache.do('configOfImageHash', this.window, args => this.tracker.configOfImageHash(args), args);
}
getMigration(address, fromImageHash, fromVersion, chainId) {
return this.dedupe('getMigration', (...args) => this.tracker.getMigration(...args), address, fromImageHash, fromVersion, chainId);
return this.cache.do('getMigration', this.window, (...args) => this.tracker.getMigration(...args), address, fromImageHash, fromVersion, chainId);
}
saveMigration(address, signed, contexts) {
return this.dedupe('saveMigration', (...args) => this.tracker.saveMigration(...args), address, signed, contexts);
return this.cache.do('saveMigration', undefined, (...args) => this.tracker.saveMigration(...args), address, signed, contexts);
}
loadPresignedConfiguration(args) {
return this.dedupe('loadPresignedConfiguration', args => this.tracker.loadPresignedConfiguration(args), args);
return this.cache.do('loadPresignedConfiguration', this.window, args => this.tracker.loadPresignedConfiguration(args), args);
}
savePresignedConfiguration(args) {
return this.dedupe('savePresignedConfiguration', args => this.tracker.savePresignedConfiguration(args), args);
return this.cache.do('savePresignedConfiguration', undefined, args => this.tracker.savePresignedConfiguration(args), args);
}
saveWitnesses(args) {
return this.dedupe('saveWitnesses', args => this.tracker.saveWitnesses(args), args);
return this.cache.do('saveWitnesses', undefined, args => this.tracker.saveWitnesses(args), args);
}
saveWalletConfig(args) {
return this.dedupe('saveWalletConfig', args => this.tracker.saveWalletConfig(args), args);
return this.cache.do('saveWalletConfig', undefined, args => this.tracker.saveWalletConfig(args), args);
}
imageHashOfCounterfactualWallet(args) {
return this.dedupe('imageHashOfCounterfactualWallet', args => this.tracker.imageHashOfCounterfactualWallet(args), args);
return this.cache.do('imageHashOfCounterfactualWallet', undefined, args => this.tracker.imageHashOfCounterfactualWallet(args), args);
}
saveCounterfactualWallet(args) {
return this.dedupe('saveCounterfactualWallet', args => this.tracker.saveCounterfactualWallet(args), args);
return this.cache.do('saveCounterfactualWallet', undefined, args => this.tracker.saveCounterfactualWallet(args), args);
}
walletsOfSigner(args) {
return this.dedupe('walletsOfSigner', args => this.tracker.walletsOfSigner(args), args);
return this.cache.do('walletsOfSigner', this.window, args => this.tracker.walletsOfSigner(args), args);
}

@@ -1642,0 +1641,0 @@ }

@@ -342,5 +342,6 @@ import { v2, v1, universal, commons } from '@0xsequence/core';

if (isPlainNode(node)) {
const [left, right] = await Promise.all([_this.loadTopology(node.left), _this.loadTopology(node.right)]);
return {
left: await _this.loadTopology(node.left),
right: await _this.loadTopology(node.right)
left,
right
};

@@ -1249,12 +1250,3 @@ }

async function allSafe(promises, fallback) {
const results = [];
for (const p of promises) {
try {
results.push(await p);
} catch (_unused) {
// Ignore
results.push(fallback);
}
}
return results;
return Promise.all(promises.map(promise => promise.catch(() => fallback)));
}

@@ -1444,7 +1436,18 @@ class MultipleTracker {

var _this = this;
const configs = new Map();
const configOf = imageHash => {
if (!configs.has(imageHash)) {
configs.set(imageHash, this.configOfImageHash({
imageHash
}));
}
return configs.get(imageHash);
};
// We need to check both, and return the one with the highest checkpoint
// eventually we could try to combine them, but for now we'll just return
// the one with the highest checkpoint
const results = await Promise.all([this.tracker.loadPresignedConfiguration(args), this.cache.loadPresignedConfiguration(args)]);
const checkpoints = await Promise.all(results.map(async function (r) {
const results = [this.tracker.loadPresignedConfiguration(args), this.cache.loadPresignedConfiguration(args)];
const checkpoints = await Promise.all(results.map(async function (result) {
const r = await result;
const last = r[r.length - 1];

@@ -1454,5 +1457,3 @@ if (!last) return undefined;

// TODO: This will fire a lot of requests, optimize it
const config = await _this.configOfImageHash({
imageHash: last.nextImageHash
});
const config = await configOf(last.nextImageHash);
if (!config) return undefined;

@@ -1471,13 +1472,4 @@ return {

if (!best) return [];
const configs = new Map();
const config = imageHash => {
if (!configs.has(imageHash)) {
configs.set(imageHash, this.configOfImageHash({
imageHash
}));
}
return configs.get(imageHash);
};
best.result.forEach(async function (res) {
const nextConfig = await config(res.nextImageHash);
const nextConfig = await configOf(res.nextImageHash);
if (nextConfig) {

@@ -1567,2 +1559,38 @@ _this.savePresignedConfiguration({

class PromiseCache {
constructor() {
this.cache = void 0;
this.cache = new Map();
}
do(key, validMilliseconds, task, ...args) {
key = `${key}:${ethers.utils.keccak256(ethers.utils.toUtf8Bytes(JSON.stringify(args)))}`;
let entry = this.cache.get(key);
if (entry) {
if (entry.expiration) {
if (new Date() >= entry.expiration) {
entry = undefined;
this.cache.delete(key);
}
}
}
if (!entry) {
entry = {
promise: Promise.reject('unreachable')
};
if (validMilliseconds === undefined) {
entry.promise = task(...args);
} else {
entry.promise = task(...args).then(result => {
if (entry) {
entry.expiration = new Date(Date.now() + validMilliseconds);
}
return result;
});
}
this.cache.set(key, entry);
}
return entry.promise;
}
}
// This tracks wraps another tracker and dedupes calls to it, so in any calls

@@ -1576,62 +1604,33 @@ // are sent in short succession, only the first call is forwarded to the

this.verbose = verbose;
this.pending = new Map();
this.cache = new PromiseCache();
}
async dedupe(key, fn, ...args) {
this.clear();
// TODO: Replace with a faster hash function
const subkey = `${key}:${ethers.utils.keccak256(ethers.utils.toUtf8Bytes(JSON.stringify(args)))}`;
const now = Date.now();
const pending = this.pending.get(subkey);
if (pending && now - pending.time < this.window) {
if (this.verbose) {
console.log(`dedupe hit: ${subkey} -> found (${pending.time})`);
}
return pending.promise;
}
const promise = fn(...args);
this.pending.set(subkey, {
promise,
time: now
});
return promise;
}
clear() {
// remove all pending calls past the window
const now = Date.now();
for (const [key, pending] of this.pending) {
if (now - pending.time > this.window) {
this.pending.delete(key);
}
}
}
configOfImageHash(args) {
return this.dedupe('configOfImageHash', args => this.tracker.configOfImageHash(args), args);
return this.cache.do('configOfImageHash', this.window, args => this.tracker.configOfImageHash(args), args);
}
getMigration(address, fromImageHash, fromVersion, chainId) {
return this.dedupe('getMigration', (...args) => this.tracker.getMigration(...args), address, fromImageHash, fromVersion, chainId);
return this.cache.do('getMigration', this.window, (...args) => this.tracker.getMigration(...args), address, fromImageHash, fromVersion, chainId);
}
saveMigration(address, signed, contexts) {
return this.dedupe('saveMigration', (...args) => this.tracker.saveMigration(...args), address, signed, contexts);
return this.cache.do('saveMigration', undefined, (...args) => this.tracker.saveMigration(...args), address, signed, contexts);
}
loadPresignedConfiguration(args) {
return this.dedupe('loadPresignedConfiguration', args => this.tracker.loadPresignedConfiguration(args), args);
return this.cache.do('loadPresignedConfiguration', this.window, args => this.tracker.loadPresignedConfiguration(args), args);
}
savePresignedConfiguration(args) {
return this.dedupe('savePresignedConfiguration', args => this.tracker.savePresignedConfiguration(args), args);
return this.cache.do('savePresignedConfiguration', undefined, args => this.tracker.savePresignedConfiguration(args), args);
}
saveWitnesses(args) {
return this.dedupe('saveWitnesses', args => this.tracker.saveWitnesses(args), args);
return this.cache.do('saveWitnesses', undefined, args => this.tracker.saveWitnesses(args), args);
}
saveWalletConfig(args) {
return this.dedupe('saveWalletConfig', args => this.tracker.saveWalletConfig(args), args);
return this.cache.do('saveWalletConfig', undefined, args => this.tracker.saveWalletConfig(args), args);
}
imageHashOfCounterfactualWallet(args) {
return this.dedupe('imageHashOfCounterfactualWallet', args => this.tracker.imageHashOfCounterfactualWallet(args), args);
return this.cache.do('imageHashOfCounterfactualWallet', undefined, args => this.tracker.imageHashOfCounterfactualWallet(args), args);
}
saveCounterfactualWallet(args) {
return this.dedupe('saveCounterfactualWallet', args => this.tracker.saveCounterfactualWallet(args), args);
return this.cache.do('saveCounterfactualWallet', undefined, args => this.tracker.saveCounterfactualWallet(args), args);
}
walletsOfSigner(args) {
return this.dedupe('walletsOfSigner', args => this.tracker.walletsOfSigner(args), args);
return this.cache.do('walletsOfSigner', this.window, args => this.tracker.walletsOfSigner(args), args);
}

@@ -1638,0 +1637,0 @@ }

@@ -9,6 +9,4 @@ import { commons } from "@0xsequence/core";

verbose: boolean;
private readonly pending;
private readonly cache;
constructor(tracker: migrator.PresignedMigrationTracker & ConfigTracker, window?: number, verbose?: boolean);
dedupe<T, Y extends Array<any>>(key: string, fn: (...args: Y) => Promise<T>, ...args: Y): Promise<T>;
clear(): void;
configOfImageHash(args: {

@@ -15,0 +13,0 @@ imageHash: string;

{
"name": "@0xsequence/sessions",
"version": "0.0.0-20230307215941",
"version": "0.0.0-20230309013947",
"description": "tools for migrating sequence wallets to new versions",

@@ -12,5 +12,5 @@ "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/sessions",

"dependencies": {
"@0xsequence/core": "0.0.0-20230307215941",
"@0xsequence/migration": "0.0.0-20230307215941",
"@0xsequence/replacer": "0.0.0-20230307215941",
"@0xsequence/core": "0.0.0-20230309013947",
"@0xsequence/migration": "0.0.0-20230309013947",
"@0xsequence/replacer": "0.0.0-20230309013947",
"ethers": "^5.5.2",

@@ -20,4 +20,4 @@ "idb": "^7.1.1"

"devDependencies": {
"@0xsequence/signhub": "0.0.0-20230307215941",
"@0xsequence/tests": "0.0.0-20230307215941",
"@0xsequence/signhub": "0.0.0-20230309013947",
"@0xsequence/tests": "0.0.0-20230309013947",
"@istanbuljs/nyc-config-typescript": "^1.0.2",

@@ -24,0 +24,0 @@ "fake-indexeddb": "^4.0.1",

@@ -15,7 +15,16 @@

async loadPresignedConfiguration(args: { wallet: string; fromImageHash: string; longestPath?: boolean | undefined }): Promise<PresignedConfigLink[]> {
const configs = new Map<string, Promise<commons.config.Config | undefined>>()
const configOf = (imageHash: string): Promise<commons.config.Config | undefined> => {
if (!configs.has(imageHash)) {
configs.set(imageHash, this.configOfImageHash({ imageHash }))
}
return configs.get(imageHash)!
}
// We need to check both, and return the one with the highest checkpoint
// eventually we could try to combine them, but for now we'll just return
// the one with the highest checkpoint
const results = await Promise.all([this.tracker.loadPresignedConfiguration(args), this.cache.loadPresignedConfiguration(args)])
const checkpoints = await Promise.all(results.map(async (r) => {
const results = [this.tracker.loadPresignedConfiguration(args), this.cache.loadPresignedConfiguration(args)]
const checkpoints = await Promise.all(results.map(async result => {
const r = await result
const last = r[r.length - 1]

@@ -25,3 +34,3 @@ if (!last) return undefined

// TODO: This will fire a lot of requests, optimize it
const config = await this.configOfImageHash({ imageHash: last.nextImageHash })
const config = await configOf(last.nextImageHash)
if (!config) return undefined

@@ -41,11 +50,4 @@

const configs = new Map<string, Promise<commons.config.Config | undefined>>()
const config = (imageHash: string): Promise<commons.config.Config | undefined> => {
if (!configs.has(imageHash)) {
configs.set(imageHash, this.configOfImageHash({ imageHash }))
}
return configs.get(imageHash)!
}
best.result.forEach(async res => {
const nextConfig = await config(res.nextImageHash)
const nextConfig = await configOf(res.nextImageHash)
if (nextConfig) {

@@ -52,0 +54,0 @@ this.savePresignedConfiguration({

import { commons } from "@0xsequence/core"
import { migrator } from "@0xsequence/migration";
import { BigNumber, BigNumberish, ethers } from "ethers";
import { BigNumber, BigNumberish } from "ethers";
import { ConfigTracker, PresignedConfig, PresignedConfigLink } from "../tracker";
import { PromiseCache } from "./promise-cache";

@@ -10,3 +11,3 @@ // This tracks wraps another tracker and dedupes calls to it, so in any calls

export class DedupedTracker implements migrator.PresignedMigrationTracker, ConfigTracker {
private readonly pending: Map<string, { promise: Promise<any>, time: number }> = new Map();
private readonly cache: PromiseCache = new PromiseCache();

@@ -19,71 +20,41 @@ constructor(

async dedupe<T, Y extends Array<any>>(key: string, fn: (...args: Y) => Promise<T>, ...args: Y): Promise<T> {
this.clear()
// TODO: Replace with a faster hash function
const subkey = `${key}:${ethers.utils.keccak256(ethers.utils.toUtf8Bytes(JSON.stringify(args)))}`
const now = Date.now()
const pending = this.pending.get(subkey)
if (pending && now - pending.time < this.window) {
if (this.verbose) {
console.log(`dedupe hit: ${subkey} -> found (${pending.time})`)
}
return pending.promise as Promise<T>
}
const promise = fn(...args)
this.pending.set(subkey, { promise, time: now })
return promise
}
clear() {
// remove all pending calls past the window
const now = Date.now()
for (const [key, pending] of this.pending) {
if (now - pending.time > this.window) {
this.pending.delete(key)
}
}
}
configOfImageHash(args: { imageHash: string; }): Promise<commons.config.Config | undefined> {
return this.dedupe('configOfImageHash', (args) => this.tracker.configOfImageHash(args), args)
return this.cache.do('configOfImageHash', this.window, args => this.tracker.configOfImageHash(args), args)
}
getMigration(address: string, fromImageHash: string, fromVersion: number, chainId: BigNumberish): Promise<migrator.SignedMigration | undefined> {
return this.dedupe('getMigration', (...args) => this.tracker.getMigration(...args), address, fromImageHash, fromVersion, chainId)
return this.cache.do('getMigration', this.window, (...args) => this.tracker.getMigration(...args), address, fromImageHash, fromVersion, chainId)
}
saveMigration(address: string, signed: migrator.SignedMigration, contexts: commons.context.VersionedContext): Promise<void> {
return this.dedupe('saveMigration', (...args) => this.tracker.saveMigration(...args), address, signed, contexts)
return this.cache.do('saveMigration', undefined, (...args) => this.tracker.saveMigration(...args), address, signed, contexts)
}
loadPresignedConfiguration(args: { wallet: string; fromImageHash: string; longestPath?: boolean | undefined; }): Promise<PresignedConfigLink[]> {
return this.dedupe('loadPresignedConfiguration', (args) => this.tracker.loadPresignedConfiguration(args), args)
return this.cache.do('loadPresignedConfiguration', this.window, args => this.tracker.loadPresignedConfiguration(args), args)
}
savePresignedConfiguration(args: PresignedConfig): Promise<void> {
return this.dedupe('savePresignedConfiguration', (args) => this.tracker.savePresignedConfiguration(args), args)
return this.cache.do('savePresignedConfiguration', undefined, args => this.tracker.savePresignedConfiguration(args), args)
}
saveWitnesses(args: { wallet: string; digest: string; chainId: BigNumberish; signatures: string[]; }): Promise<void> {
return this.dedupe('saveWitnesses', (args) => this.tracker.saveWitnesses(args), args)
return this.cache.do('saveWitnesses', undefined, args => this.tracker.saveWitnesses(args), args)
}
saveWalletConfig(args: { config: commons.config.Config; }): Promise<void> {
return this.dedupe('saveWalletConfig', (args) => this.tracker.saveWalletConfig(args), args)
return this.cache.do('saveWalletConfig', undefined, args => this.tracker.saveWalletConfig(args), args)
}
imageHashOfCounterfactualWallet(args: { wallet: string; }): Promise<{ imageHash: string; context: commons.context.WalletContext; } | undefined> {
return this.dedupe('imageHashOfCounterfactualWallet', (args) => this.tracker.imageHashOfCounterfactualWallet(args), args)
return this.cache.do('imageHashOfCounterfactualWallet', undefined, args => this.tracker.imageHashOfCounterfactualWallet(args), args)
}
saveCounterfactualWallet(args: { config: commons.config.Config; context: commons.context.WalletContext[]; }): Promise<void> {
return this.dedupe('saveCounterfactualWallet', (args) => this.tracker.saveCounterfactualWallet(args), args)
return this.cache.do('saveCounterfactualWallet', undefined, args => this.tracker.saveCounterfactualWallet(args), args)
}
walletsOfSigner(args: { signer: string; }): Promise<{ wallet: string; proof: { digest: string; chainId: BigNumber; signature: string; }; }[]> {
return this.dedupe('walletsOfSigner', (args) => this.tracker.walletsOfSigner(args), args)
return this.cache.do('walletsOfSigner', this.window, args => this.tracker.walletsOfSigner(args), args)
}
}

@@ -27,6 +27,4 @@ import { commons, universal, v1, v2 } from '@0xsequence/core'

if (isPlainNode(node)) {
return {
left: await this.loadTopology(node.left),
right: await this.loadTopology(node.right)
}
const [left, right] = await Promise.all([this.loadTopology(node.left), this.loadTopology(node.right)])
return { left, right }
}

@@ -33,0 +31,0 @@

@@ -31,14 +31,3 @@ import { ConfigTracker, PresignedConfig, PresignedConfigLink } from '../tracker'

export async function allSafe<T>(promises: Promise<T>[], fallback: T): Promise<T[]> {
const results: T[] = []
for (const p of promises) {
try {
results.push(await p)
} catch {
// Ignore
results.push(fallback)
}
}
return results
return Promise.all(promises.map(promise => promise.catch(() => fallback)))
}

@@ -45,0 +34,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc