@0xsequence/sessions
Advanced tools
Comparing version 0.0.0-20230622154954 to 0.0.0-20230629132619
@@ -428,2 +428,3 @@ 'use strict'; | ||
}; | ||
this.configOfImageHashCache = {}; | ||
this.configOfImageHash = async function (args) { | ||
@@ -433,9 +434,15 @@ const { | ||
} = args; | ||
if (_this.configOfImageHashCache[args.imageHash]) { | ||
return _this.configOfImageHashCache[args.imageHash]; | ||
} | ||
const config = await _this.store.loadConfig(imageHash); | ||
if (!config) return undefined; | ||
if (!config) { | ||
return undefined; | ||
} | ||
if (config.version === 1 || config.version === 2 && !isPlainV2Config(config)) { | ||
_this.configOfImageHashCache[args.imageHash] = config; | ||
return config; | ||
} | ||
if (isPlainV2Config(config)) { | ||
return { | ||
const fullConfig = { | ||
version: 2, | ||
@@ -446,2 +453,4 @@ threshold: ethers.ethers.BigNumber.from(config.threshold), | ||
}; | ||
_this.configOfImageHashCache[args.imageHash] = fullConfig; | ||
return fullConfig; | ||
} | ||
@@ -481,7 +490,15 @@ throw new Error(`Unknown config type: ${config}`); | ||
}; | ||
this.payloadOfSubdigestCache = {}; | ||
this.payloadOfSubdigest = async function (args) { | ||
if (_this.payloadOfSubdigestCache[args.subdigest]) { | ||
return _this.payloadOfSubdigestCache[args.subdigest]; | ||
} | ||
const { | ||
subdigest | ||
} = args; | ||
return _this.store.loadPayloadOfSubdigest(subdigest); | ||
const res = await _this.store.loadPayloadOfSubdigest(subdigest); | ||
if (res) { | ||
_this.payloadOfSubdigestCache[subdigest] = res; | ||
} | ||
return res; | ||
}; | ||
@@ -551,15 +568,35 @@ this.savePresignedConfiguration = async function (args) { | ||
let bestCandidate; | ||
for (const { | ||
payload, | ||
nextImageHash | ||
} of nextImageHashes) { | ||
// Get config of next imageHash | ||
const nextConfigsAndCheckpoints = await Promise.all(nextImageHashes.map(async function ({ | ||
nextImageHash, | ||
payload | ||
}) { | ||
const nextConfig = await _this.configOfImageHash({ | ||
imageHash: nextImageHash | ||
}); | ||
if (!nextConfig || !core.v2.config.isWalletConfig(nextConfig)) continue; | ||
if (!nextConfig || !core.v2.config.isWalletConfig(nextConfig)) return undefined; | ||
const nextCheckpoint = ethers.ethers.BigNumber.from(nextConfig.checkpoint); | ||
// Only consider candidates later than the starting checkpoint | ||
if (nextCheckpoint.lte(fromConfig.checkpoint)) continue; | ||
return { | ||
nextConfig, | ||
nextCheckpoint, | ||
nextImageHash, | ||
payload | ||
}; | ||
})); | ||
const sortedNextConfigsAndCheckpoints = nextConfigsAndCheckpoints.filter(c => c !== undefined).filter(c => c.nextCheckpoint.gt(fromConfig.checkpoint)).sort((a, b) => | ||
// If we are looking for the longest path, sort by ascending checkpoint | ||
// because we want to find the smalles jump, and we should start with the | ||
// closest one. If we are not looking for the longest path, sort by | ||
// descending checkpoint, because we want to find the largest jump. | ||
// | ||
// We don't have a guarantee that all "next configs" will be valid | ||
// so worst case scenario we will need to try all of them. | ||
// But we can try to optimize for the most common case. | ||
a.nextCheckpoint.gt(b.nextCheckpoint) ? longestPath ? 1 : -1 : longestPath ? -1 : 1); | ||
for (const entry of sortedNextConfigsAndCheckpoints) { | ||
const { | ||
nextConfig, | ||
nextCheckpoint, | ||
nextImageHash, | ||
payload | ||
} = entry; | ||
if (bestCandidate) { | ||
@@ -590,3 +627,6 @@ const bestCheckpoint = bestCandidate.checkpoint; | ||
// Encode the full signature | ||
// Skip if we don't have ANY signatures (it can never reach the threshold) | ||
if (signatures.size === 0) continue; | ||
// Encode the full signature (to see if it has enough weight) | ||
const encoded = core.v2.signature.SignatureCoder.encodeSigners(fromConfig, signatures, [], 0); | ||
@@ -602,3 +642,5 @@ if (encoded.weight.lt(fromConfig.threshold)) continue; | ||
} | ||
if (!bestCandidate) return []; | ||
if (!bestCandidate) { | ||
return []; | ||
} | ||
@@ -1461,12 +1503,2 @@ // Get the next step | ||
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 | ||
@@ -1476,35 +1508,36 @@ // eventually we could try to combine them, but for now we'll just return | ||
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]; | ||
if (!last) return undefined; | ||
let best; | ||
// TODO: This will fire a lot of requests, optimize it | ||
const config = await configOf(last.nextImageHash); | ||
if (!config) return undefined; | ||
return { | ||
checkpoint: core.universal.genericCoderFor(config.version).config.checkpointOf(config), | ||
result: r | ||
}; | ||
})); | ||
const best = checkpoints.reduce((acc, val) => { | ||
if (!val) return acc; | ||
if (!acc) return val; | ||
if (val.checkpoint.gt(acc.checkpoint)) return val; | ||
return acc; | ||
}); | ||
// If both results end with the same image hash, we can just return the longest/shortest one | ||
const [result1, result2] = await Promise.all(results); | ||
if (result1.length > 0 && result2.length > 0 && result1[result1.length - 1].nextImageHash === result2[result2.length - 1].nextImageHash) { | ||
best = args.longestPath === true ? result1.length > result2.length ? result1 : result2 : result1.length < result2.length ? result1 : result2; | ||
} else { | ||
var _checkpoints$reduce$r, _checkpoints$reduce; | ||
// Otherwise we need to check the checkpoints | ||
// this requires us to fetch the config for each image hash | ||
const checkpoints = await Promise.all(results.map(async function (result) { | ||
const r = await result; | ||
const last = r[r.length - 1]; | ||
if (!last) return undefined; | ||
// TODO: This will fire a lot of requests, optimize it | ||
const config = await _this.configOfImageHash({ | ||
imageHash: last.nextImageHash | ||
}); | ||
if (!config) return undefined; | ||
return { | ||
checkpoint: core.universal.genericCoderFor(config.version).config.checkpointOf(config), | ||
result: r | ||
}; | ||
})); | ||
best = (_checkpoints$reduce$r = (_checkpoints$reduce = checkpoints.reduce((acc, val) => { | ||
if (!val) return acc; | ||
if (!acc) return val; | ||
if (val.checkpoint.gt(acc.checkpoint)) return val; | ||
return acc; | ||
})) == null ? void 0 : _checkpoints$reduce.result) != null ? _checkpoints$reduce$r : []; | ||
} | ||
if (!best) return []; | ||
(async function () { | ||
for (const result of best.result) { | ||
const nextConfig = await configOf(result.nextImageHash); | ||
if (nextConfig) { | ||
_this.cache.savePresignedConfiguration({ | ||
wallet: args.wallet, | ||
nextConfig, | ||
signature: result.signature | ||
}); | ||
} | ||
} | ||
})(); | ||
return best.result; | ||
return best; | ||
} | ||
@@ -1511,0 +1544,0 @@ async savePresignedConfiguration(args) { |
@@ -428,2 +428,3 @@ 'use strict'; | ||
}; | ||
this.configOfImageHashCache = {}; | ||
this.configOfImageHash = async function (args) { | ||
@@ -433,9 +434,15 @@ const { | ||
} = args; | ||
if (_this.configOfImageHashCache[args.imageHash]) { | ||
return _this.configOfImageHashCache[args.imageHash]; | ||
} | ||
const config = await _this.store.loadConfig(imageHash); | ||
if (!config) return undefined; | ||
if (!config) { | ||
return undefined; | ||
} | ||
if (config.version === 1 || config.version === 2 && !isPlainV2Config(config)) { | ||
_this.configOfImageHashCache[args.imageHash] = config; | ||
return config; | ||
} | ||
if (isPlainV2Config(config)) { | ||
return { | ||
const fullConfig = { | ||
version: 2, | ||
@@ -446,2 +453,4 @@ threshold: ethers.ethers.BigNumber.from(config.threshold), | ||
}; | ||
_this.configOfImageHashCache[args.imageHash] = fullConfig; | ||
return fullConfig; | ||
} | ||
@@ -481,7 +490,15 @@ throw new Error(`Unknown config type: ${config}`); | ||
}; | ||
this.payloadOfSubdigestCache = {}; | ||
this.payloadOfSubdigest = async function (args) { | ||
if (_this.payloadOfSubdigestCache[args.subdigest]) { | ||
return _this.payloadOfSubdigestCache[args.subdigest]; | ||
} | ||
const { | ||
subdigest | ||
} = args; | ||
return _this.store.loadPayloadOfSubdigest(subdigest); | ||
const res = await _this.store.loadPayloadOfSubdigest(subdigest); | ||
if (res) { | ||
_this.payloadOfSubdigestCache[subdigest] = res; | ||
} | ||
return res; | ||
}; | ||
@@ -551,15 +568,35 @@ this.savePresignedConfiguration = async function (args) { | ||
let bestCandidate; | ||
for (const { | ||
payload, | ||
nextImageHash | ||
} of nextImageHashes) { | ||
// Get config of next imageHash | ||
const nextConfigsAndCheckpoints = await Promise.all(nextImageHashes.map(async function ({ | ||
nextImageHash, | ||
payload | ||
}) { | ||
const nextConfig = await _this.configOfImageHash({ | ||
imageHash: nextImageHash | ||
}); | ||
if (!nextConfig || !core.v2.config.isWalletConfig(nextConfig)) continue; | ||
if (!nextConfig || !core.v2.config.isWalletConfig(nextConfig)) return undefined; | ||
const nextCheckpoint = ethers.ethers.BigNumber.from(nextConfig.checkpoint); | ||
// Only consider candidates later than the starting checkpoint | ||
if (nextCheckpoint.lte(fromConfig.checkpoint)) continue; | ||
return { | ||
nextConfig, | ||
nextCheckpoint, | ||
nextImageHash, | ||
payload | ||
}; | ||
})); | ||
const sortedNextConfigsAndCheckpoints = nextConfigsAndCheckpoints.filter(c => c !== undefined).filter(c => c.nextCheckpoint.gt(fromConfig.checkpoint)).sort((a, b) => | ||
// If we are looking for the longest path, sort by ascending checkpoint | ||
// because we want to find the smalles jump, and we should start with the | ||
// closest one. If we are not looking for the longest path, sort by | ||
// descending checkpoint, because we want to find the largest jump. | ||
// | ||
// We don't have a guarantee that all "next configs" will be valid | ||
// so worst case scenario we will need to try all of them. | ||
// But we can try to optimize for the most common case. | ||
a.nextCheckpoint.gt(b.nextCheckpoint) ? longestPath ? 1 : -1 : longestPath ? -1 : 1); | ||
for (const entry of sortedNextConfigsAndCheckpoints) { | ||
const { | ||
nextConfig, | ||
nextCheckpoint, | ||
nextImageHash, | ||
payload | ||
} = entry; | ||
if (bestCandidate) { | ||
@@ -590,3 +627,6 @@ const bestCheckpoint = bestCandidate.checkpoint; | ||
// Encode the full signature | ||
// Skip if we don't have ANY signatures (it can never reach the threshold) | ||
if (signatures.size === 0) continue; | ||
// Encode the full signature (to see if it has enough weight) | ||
const encoded = core.v2.signature.SignatureCoder.encodeSigners(fromConfig, signatures, [], 0); | ||
@@ -602,3 +642,5 @@ if (encoded.weight.lt(fromConfig.threshold)) continue; | ||
} | ||
if (!bestCandidate) return []; | ||
if (!bestCandidate) { | ||
return []; | ||
} | ||
@@ -1461,12 +1503,2 @@ // Get the next step | ||
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 | ||
@@ -1476,35 +1508,36 @@ // eventually we could try to combine them, but for now we'll just return | ||
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]; | ||
if (!last) return undefined; | ||
let best; | ||
// TODO: This will fire a lot of requests, optimize it | ||
const config = await configOf(last.nextImageHash); | ||
if (!config) return undefined; | ||
return { | ||
checkpoint: core.universal.genericCoderFor(config.version).config.checkpointOf(config), | ||
result: r | ||
}; | ||
})); | ||
const best = checkpoints.reduce((acc, val) => { | ||
if (!val) return acc; | ||
if (!acc) return val; | ||
if (val.checkpoint.gt(acc.checkpoint)) return val; | ||
return acc; | ||
}); | ||
// If both results end with the same image hash, we can just return the longest/shortest one | ||
const [result1, result2] = await Promise.all(results); | ||
if (result1.length > 0 && result2.length > 0 && result1[result1.length - 1].nextImageHash === result2[result2.length - 1].nextImageHash) { | ||
best = args.longestPath === true ? result1.length > result2.length ? result1 : result2 : result1.length < result2.length ? result1 : result2; | ||
} else { | ||
var _checkpoints$reduce$r, _checkpoints$reduce; | ||
// Otherwise we need to check the checkpoints | ||
// this requires us to fetch the config for each image hash | ||
const checkpoints = await Promise.all(results.map(async function (result) { | ||
const r = await result; | ||
const last = r[r.length - 1]; | ||
if (!last) return undefined; | ||
// TODO: This will fire a lot of requests, optimize it | ||
const config = await _this.configOfImageHash({ | ||
imageHash: last.nextImageHash | ||
}); | ||
if (!config) return undefined; | ||
return { | ||
checkpoint: core.universal.genericCoderFor(config.version).config.checkpointOf(config), | ||
result: r | ||
}; | ||
})); | ||
best = (_checkpoints$reduce$r = (_checkpoints$reduce = checkpoints.reduce((acc, val) => { | ||
if (!val) return acc; | ||
if (!acc) return val; | ||
if (val.checkpoint.gt(acc.checkpoint)) return val; | ||
return acc; | ||
})) == null ? void 0 : _checkpoints$reduce.result) != null ? _checkpoints$reduce$r : []; | ||
} | ||
if (!best) return []; | ||
(async function () { | ||
for (const result of best.result) { | ||
const nextConfig = await configOf(result.nextImageHash); | ||
if (nextConfig) { | ||
_this.cache.savePresignedConfiguration({ | ||
wallet: args.wallet, | ||
nextConfig, | ||
signature: result.signature | ||
}); | ||
} | ||
} | ||
})(); | ||
return best.result; | ||
return best; | ||
} | ||
@@ -1511,0 +1544,0 @@ async savePresignedConfiguration(args) { |
@@ -424,2 +424,3 @@ import { v2, v1, universal, commons } from '@0xsequence/core'; | ||
}; | ||
this.configOfImageHashCache = {}; | ||
this.configOfImageHash = async function (args) { | ||
@@ -429,9 +430,15 @@ const { | ||
} = args; | ||
if (_this.configOfImageHashCache[args.imageHash]) { | ||
return _this.configOfImageHashCache[args.imageHash]; | ||
} | ||
const config = await _this.store.loadConfig(imageHash); | ||
if (!config) return undefined; | ||
if (!config) { | ||
return undefined; | ||
} | ||
if (config.version === 1 || config.version === 2 && !isPlainV2Config(config)) { | ||
_this.configOfImageHashCache[args.imageHash] = config; | ||
return config; | ||
} | ||
if (isPlainV2Config(config)) { | ||
return { | ||
const fullConfig = { | ||
version: 2, | ||
@@ -442,2 +449,4 @@ threshold: ethers.BigNumber.from(config.threshold), | ||
}; | ||
_this.configOfImageHashCache[args.imageHash] = fullConfig; | ||
return fullConfig; | ||
} | ||
@@ -477,7 +486,15 @@ throw new Error(`Unknown config type: ${config}`); | ||
}; | ||
this.payloadOfSubdigestCache = {}; | ||
this.payloadOfSubdigest = async function (args) { | ||
if (_this.payloadOfSubdigestCache[args.subdigest]) { | ||
return _this.payloadOfSubdigestCache[args.subdigest]; | ||
} | ||
const { | ||
subdigest | ||
} = args; | ||
return _this.store.loadPayloadOfSubdigest(subdigest); | ||
const res = await _this.store.loadPayloadOfSubdigest(subdigest); | ||
if (res) { | ||
_this.payloadOfSubdigestCache[subdigest] = res; | ||
} | ||
return res; | ||
}; | ||
@@ -547,15 +564,35 @@ this.savePresignedConfiguration = async function (args) { | ||
let bestCandidate; | ||
for (const { | ||
payload, | ||
nextImageHash | ||
} of nextImageHashes) { | ||
// Get config of next imageHash | ||
const nextConfigsAndCheckpoints = await Promise.all(nextImageHashes.map(async function ({ | ||
nextImageHash, | ||
payload | ||
}) { | ||
const nextConfig = await _this.configOfImageHash({ | ||
imageHash: nextImageHash | ||
}); | ||
if (!nextConfig || !v2.config.isWalletConfig(nextConfig)) continue; | ||
if (!nextConfig || !v2.config.isWalletConfig(nextConfig)) return undefined; | ||
const nextCheckpoint = ethers.BigNumber.from(nextConfig.checkpoint); | ||
// Only consider candidates later than the starting checkpoint | ||
if (nextCheckpoint.lte(fromConfig.checkpoint)) continue; | ||
return { | ||
nextConfig, | ||
nextCheckpoint, | ||
nextImageHash, | ||
payload | ||
}; | ||
})); | ||
const sortedNextConfigsAndCheckpoints = nextConfigsAndCheckpoints.filter(c => c !== undefined).filter(c => c.nextCheckpoint.gt(fromConfig.checkpoint)).sort((a, b) => | ||
// If we are looking for the longest path, sort by ascending checkpoint | ||
// because we want to find the smalles jump, and we should start with the | ||
// closest one. If we are not looking for the longest path, sort by | ||
// descending checkpoint, because we want to find the largest jump. | ||
// | ||
// We don't have a guarantee that all "next configs" will be valid | ||
// so worst case scenario we will need to try all of them. | ||
// But we can try to optimize for the most common case. | ||
a.nextCheckpoint.gt(b.nextCheckpoint) ? longestPath ? 1 : -1 : longestPath ? -1 : 1); | ||
for (const entry of sortedNextConfigsAndCheckpoints) { | ||
const { | ||
nextConfig, | ||
nextCheckpoint, | ||
nextImageHash, | ||
payload | ||
} = entry; | ||
if (bestCandidate) { | ||
@@ -586,3 +623,6 @@ const bestCheckpoint = bestCandidate.checkpoint; | ||
// Encode the full signature | ||
// Skip if we don't have ANY signatures (it can never reach the threshold) | ||
if (signatures.size === 0) continue; | ||
// Encode the full signature (to see if it has enough weight) | ||
const encoded = v2.signature.SignatureCoder.encodeSigners(fromConfig, signatures, [], 0); | ||
@@ -598,3 +638,5 @@ if (encoded.weight.lt(fromConfig.threshold)) continue; | ||
} | ||
if (!bestCandidate) return []; | ||
if (!bestCandidate) { | ||
return []; | ||
} | ||
@@ -1457,12 +1499,2 @@ // Get the next step | ||
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 | ||
@@ -1472,35 +1504,36 @@ // eventually we could try to combine them, but for now we'll just return | ||
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]; | ||
if (!last) return undefined; | ||
let best; | ||
// TODO: This will fire a lot of requests, optimize it | ||
const config = await configOf(last.nextImageHash); | ||
if (!config) return undefined; | ||
return { | ||
checkpoint: universal.genericCoderFor(config.version).config.checkpointOf(config), | ||
result: r | ||
}; | ||
})); | ||
const best = checkpoints.reduce((acc, val) => { | ||
if (!val) return acc; | ||
if (!acc) return val; | ||
if (val.checkpoint.gt(acc.checkpoint)) return val; | ||
return acc; | ||
}); | ||
// If both results end with the same image hash, we can just return the longest/shortest one | ||
const [result1, result2] = await Promise.all(results); | ||
if (result1.length > 0 && result2.length > 0 && result1[result1.length - 1].nextImageHash === result2[result2.length - 1].nextImageHash) { | ||
best = args.longestPath === true ? result1.length > result2.length ? result1 : result2 : result1.length < result2.length ? result1 : result2; | ||
} else { | ||
var _checkpoints$reduce$r, _checkpoints$reduce; | ||
// Otherwise we need to check the checkpoints | ||
// this requires us to fetch the config for each image hash | ||
const checkpoints = await Promise.all(results.map(async function (result) { | ||
const r = await result; | ||
const last = r[r.length - 1]; | ||
if (!last) return undefined; | ||
// TODO: This will fire a lot of requests, optimize it | ||
const config = await _this.configOfImageHash({ | ||
imageHash: last.nextImageHash | ||
}); | ||
if (!config) return undefined; | ||
return { | ||
checkpoint: universal.genericCoderFor(config.version).config.checkpointOf(config), | ||
result: r | ||
}; | ||
})); | ||
best = (_checkpoints$reduce$r = (_checkpoints$reduce = checkpoints.reduce((acc, val) => { | ||
if (!val) return acc; | ||
if (!acc) return val; | ||
if (val.checkpoint.gt(acc.checkpoint)) return val; | ||
return acc; | ||
})) == null ? void 0 : _checkpoints$reduce.result) != null ? _checkpoints$reduce$r : []; | ||
} | ||
if (!best) return []; | ||
(async function () { | ||
for (const result of best.result) { | ||
const nextConfig = await configOf(result.nextImageHash); | ||
if (nextConfig) { | ||
_this.cache.savePresignedConfiguration({ | ||
wallet: args.wallet, | ||
nextConfig, | ||
signature: result.signature | ||
}); | ||
} | ||
} | ||
})(); | ||
return best.result; | ||
return best; | ||
} | ||
@@ -1507,0 +1540,0 @@ async savePresignedConfiguration(args) { |
@@ -18,2 +18,3 @@ | ||
}) => Promise<void>; | ||
private configOfImageHashCache; | ||
configOfImageHash: (args: { | ||
@@ -35,2 +36,3 @@ imageHash: string; | ||
}) => Promise<void>; | ||
private payloadOfSubdigestCache; | ||
payloadOfSubdigest: (args: { | ||
@@ -37,0 +39,0 @@ subdigest: string; |
{ | ||
"name": "@0xsequence/sessions", | ||
"version": "0.0.0-20230622154954", | ||
"version": "0.0.0-20230629132619", | ||
"description": "tools for migrating sequence wallets to new versions", | ||
@@ -14,5 +14,5 @@ "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/sessions", | ||
"idb": "^7.1.1", | ||
"@0xsequence/core": "0.0.0-20230622154954", | ||
"@0xsequence/migration": "0.0.0-20230622154954", | ||
"@0xsequence/replacer": "0.0.0-20230622154954" | ||
"@0xsequence/core": "0.0.0-20230629132619", | ||
"@0xsequence/migration": "0.0.0-20230629132619", | ||
"@0xsequence/replacer": "0.0.0-20230629132619" | ||
}, | ||
@@ -23,4 +23,4 @@ "devDependencies": { | ||
"nyc": "^15.1.0", | ||
"@0xsequence/signhub": "0.0.0-20230622154954", | ||
"@0xsequence/tests": "0.0.0-20230622154954" | ||
"@0xsequence/signhub": "0.0.0-20230629132619", | ||
"@0xsequence/tests": "0.0.0-20230629132619" | ||
}, | ||
@@ -27,0 +27,0 @@ "files": [ |
@@ -15,10 +15,2 @@ | ||
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 | ||
@@ -28,37 +20,43 @@ // eventually we could try to combine them, but for now we'll just return | ||
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] | ||
if (!last) return undefined | ||
// TODO: This will fire a lot of requests, optimize it | ||
const config = await configOf(last.nextImageHash) | ||
if (!config) return undefined | ||
let best: PresignedConfigLink[] | ||
return { checkpoint: universal.genericCoderFor(config.version).config.checkpointOf(config), result: r } | ||
})) | ||
// If both results end with the same image hash, we can just return the longest/shortest one | ||
const [result1, result2] = await Promise.all(results) | ||
if ( | ||
result1.length > 0 && | ||
result2.length > 0 && | ||
result1[result1.length - 1].nextImageHash === result2[result2.length - 1].nextImageHash | ||
) { | ||
best = ( | ||
args.longestPath === true ? | ||
result1.length > result2.length ? result1 : result2 : | ||
result1.length < result2.length ? result1 : result2 | ||
) | ||
} else { | ||
// Otherwise we need to check the checkpoints | ||
// this requires us to fetch the config for each image hash | ||
const checkpoints = await Promise.all(results.map(async result => { | ||
const r = await result | ||
const last = r[r.length - 1] | ||
if (!last) return undefined | ||
const best = checkpoints.reduce((acc, val) => { | ||
if (!val) return acc | ||
if (!acc) return val | ||
if (val.checkpoint.gt(acc.checkpoint)) return val | ||
return acc | ||
}) | ||
// TODO: This will fire a lot of requests, optimize it | ||
const config = await this.configOfImageHash({ imageHash: last.nextImageHash }) | ||
if (!config) return undefined | ||
return { checkpoint: universal.genericCoderFor(config.version).config.checkpointOf(config), result: r } | ||
})) | ||
best = checkpoints.reduce((acc, val) => { | ||
if (!val) return acc | ||
if (!acc) return val | ||
if (val.checkpoint.gt(acc.checkpoint)) return val | ||
return acc | ||
})?.result ?? [] | ||
} | ||
if (!best) return [] | ||
;(async () => { | ||
for (const result of best.result) { | ||
const nextConfig = await configOf(result.nextImageHash) | ||
if (nextConfig) { | ||
this.cache.savePresignedConfiguration({ | ||
wallet: args.wallet, | ||
nextConfig, | ||
signature: result.signature | ||
}) | ||
} | ||
} | ||
})() | ||
return best.result | ||
return best | ||
} | ||
@@ -65,0 +63,0 @@ |
@@ -131,2 +131,4 @@ import { commons, universal, v1, v2 } from '@0xsequence/core' | ||
private configOfImageHashCache = {} as { [key: string]: commons.config.Config } | ||
configOfImageHash = async (args: { | ||
@@ -137,6 +139,13 @@ imageHash: string | ||
if (this.configOfImageHashCache[args.imageHash]) { | ||
return this.configOfImageHashCache[args.imageHash] | ||
} | ||
const config = await this.store.loadConfig(imageHash) | ||
if (!config) return undefined | ||
if (!config) { | ||
return undefined | ||
} | ||
if (config.version === 1 || (config.version === 2 && !isPlainV2Config(config))) { | ||
this.configOfImageHashCache[args.imageHash] = config | ||
return config | ||
@@ -146,3 +155,3 @@ } | ||
if (isPlainV2Config(config)) { | ||
return { | ||
const fullConfig = { | ||
version: 2, | ||
@@ -153,2 +162,4 @@ threshold: ethers.BigNumber.from(config.threshold), | ||
} as v2.config.WalletConfig | ||
this.configOfImageHashCache[args.imageHash] = fullConfig | ||
return fullConfig | ||
} | ||
@@ -200,7 +211,19 @@ | ||
private payloadOfSubdigestCache = {} as { [key: string]: commons.signature.SignedPayload } | ||
payloadOfSubdigest = async (args: { | ||
subdigest: string | ||
}): Promise<commons.signature.SignedPayload | undefined> => { | ||
if (this.payloadOfSubdigestCache[args.subdigest]) { | ||
return this.payloadOfSubdigestCache[args.subdigest] | ||
} | ||
const { subdigest } = args | ||
return this.store.loadPayloadOfSubdigest(subdigest) | ||
const res = await this.store.loadPayloadOfSubdigest(subdigest) | ||
if (res) { | ||
this.payloadOfSubdigestCache[subdigest] = res | ||
} | ||
return res | ||
} | ||
@@ -272,11 +295,31 @@ | ||
for (const { payload, nextImageHash } of nextImageHashes) { | ||
// Get config of next imageHash | ||
const nextConfigsAndCheckpoints = await Promise.all(nextImageHashes.map(async ({ nextImageHash, payload }) => { | ||
const nextConfig = await this.configOfImageHash({ imageHash: nextImageHash }) | ||
if (!nextConfig || !v2.config.isWalletConfig(nextConfig)) continue | ||
if (!nextConfig || !v2.config.isWalletConfig(nextConfig)) return undefined | ||
const nextCheckpoint = ethers.BigNumber.from(nextConfig.checkpoint) | ||
return { nextConfig, nextCheckpoint, nextImageHash, payload } | ||
})) | ||
// Only consider candidates later than the starting checkpoint | ||
if (nextCheckpoint.lte(fromConfig.checkpoint)) continue | ||
const sortedNextConfigsAndCheckpoints = nextConfigsAndCheckpoints | ||
.filter((c) => c !== undefined) | ||
.filter((c) => c!.nextCheckpoint.gt(fromConfig.checkpoint)) | ||
.sort((a, b) => ( | ||
// If we are looking for the longest path, sort by ascending checkpoint | ||
// because we want to find the smalles jump, and we should start with the | ||
// closest one. If we are not looking for the longest path, sort by | ||
// descending checkpoint, because we want to find the largest jump. | ||
// | ||
// We don't have a guarantee that all "next configs" will be valid | ||
// so worst case scenario we will need to try all of them. | ||
// But we can try to optimize for the most common case. | ||
a!.nextCheckpoint.gt(b!.nextCheckpoint) ? ( | ||
longestPath ? 1 : -1 | ||
) : ( | ||
longestPath ? -1 : 1 | ||
) | ||
)) | ||
for (const entry of sortedNextConfigsAndCheckpoints) { | ||
const { nextConfig, nextCheckpoint, nextImageHash, payload } = entry! | ||
if (bestCandidate) { | ||
@@ -315,3 +358,6 @@ const bestCheckpoint = bestCandidate.checkpoint | ||
// Encode the full signature | ||
// Skip if we don't have ANY signatures (it can never reach the threshold) | ||
if (signatures.size === 0) continue | ||
// Encode the full signature (to see if it has enough weight) | ||
const encoded = v2.signature.SignatureCoder.encodeSigners(fromConfig, signatures, [], 0) | ||
@@ -327,5 +373,7 @@ if (encoded.weight.lt(fromConfig.threshold)) continue | ||
} | ||
if (!bestCandidate) { | ||
return [] | ||
} | ||
if (!bestCandidate) return [] | ||
// Get the next step | ||
@@ -332,0 +380,0 @@ const nextStep = await this.loadPresignedConfiguration({ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
298898
7600
+ Added@0xsequence/abi@0.0.0-20230629132619(transitive)
+ Added@0xsequence/core@0.0.0-20230629132619(transitive)
+ Added@0xsequence/guard@0.0.0-20230629132619(transitive)
+ Added@0xsequence/indexer@0.0.0-20230629132619(transitive)
+ Added@0xsequence/migration@0.0.0-20230629132619(transitive)
+ Added@0xsequence/network@0.0.0-20230629132619(transitive)
+ Added@0xsequence/relayer@0.0.0-20230629132619(transitive)
+ Added@0xsequence/replacer@0.0.0-20230629132619(transitive)
+ Added@0xsequence/signhub@0.0.0-20230629132619(transitive)
+ Added@0xsequence/utils@0.0.0-20230629132619(transitive)
+ Added@0xsequence/wallet@0.0.0-20230629132619(transitive)
- Removed@0xsequence/abi@0.0.0-20230622154954(transitive)
- Removed@0xsequence/core@0.0.0-20230622154954(transitive)
- Removed@0xsequence/guard@0.0.0-20230622154954(transitive)
- Removed@0xsequence/indexer@0.0.0-20230622154954(transitive)
- Removed@0xsequence/migration@0.0.0-20230622154954(transitive)
- Removed@0xsequence/network@0.0.0-20230622154954(transitive)
- Removed@0xsequence/relayer@0.0.0-20230622154954(transitive)
- Removed@0xsequence/replacer@0.0.0-20230622154954(transitive)
- Removed@0xsequence/signhub@0.0.0-20230622154954(transitive)
- Removed@0xsequence/utils@0.0.0-20230622154954(transitive)
- Removed@0xsequence/wallet@0.0.0-20230622154954(transitive)