UNPKG

viem

Version:

TypeScript Interface for Ethereum

163 lines • 6.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StoreConflictError = exports.InvalidStoreValueError = void 0; exports.read = read; exports.update = update; exports.readSubmission = readSubmission; exports.removeSubmission = removeSubmission; exports.writeSubmission = writeSubmission; const Json = require("ox/Json"); const tempo_1 = require("ox/tempo"); const base_js_1 = require("../../errors/base.js"); const maxStoredValueLength = 1_048_576; const maxUpdateAttempts = 32; const pendingOperationTtl = 30 * 24 * 60 * 60 * 1_000; async function read(store, hash) { const value = await store.getItem(operationKey(hash)); if (value === null || value === undefined) return null; const operation = deserialize(value); if (operation.hash.toLowerCase() !== hash.toLowerCase()) throw new InvalidStoreValueError(); return operation; } async function update(store, hash, update) { const key = operationKey(hash); for (let attempt = 0; attempt < maxUpdateAttempts; attempt++) { const value = (await store.getItem(key)) ?? null; const current = value === null ? null : deserialize(value); if (current && current.hash.toLowerCase() !== hash.toLowerCase()) throw new InvalidStoreValueError(); const value_ = await update(current); let next; try { next = tempo_1.MultisigOperation.from(value_); } catch (cause) { throw new InvalidStoreValueError({ cause }); } if (next.hash.toLowerCase() !== hash.toLowerCase()) throw new InvalidStoreValueError(); const serialized = serialize(next); const options = next.status === 'success' ? undefined : { expiresAt: Date.now() + pendingOperationTtl }; if (await store.compareAndSet(key, value, serialized, options)) return next; } throw new StoreConflictError(); } async function readSubmission(store, operation, submissionId) { const value = await store.getItem(submissionKey(operation.hash, submissionId)); if (value === null || value === undefined) return null; try { if (value.length > maxStoredValueLength) throw new InvalidStoreValueError(); const transaction = tempo_1.TxEnvelopeTempo.deserialize(value); if (transaction.signature?.type !== 'multisig') throw new InvalidStoreValueError(); const serialized = tempo_1.MultisigOperation.serializeTransaction(operation, { approvals: transaction.signature.signatures.map((signature) => tempo_1.SignatureEnvelope.serialize(signature)), }); if (serialized.toLowerCase() !== value.toLowerCase()) throw new InvalidStoreValueError(); return tempo_1.TxEnvelopeTempo.hash(transaction); } catch (cause) { if (cause instanceof InvalidStoreValueError) throw cause; throw new InvalidStoreValueError({ cause }); } } async function removeSubmission(store, hash, submissionId) { await store.removeItem(submissionKey(hash, submissionId)); } async function writeSubmission(store, hash, submissionId, transaction) { try { if (transaction.length > maxStoredValueLength) throw new InvalidStoreValueError(); const envelope = tempo_1.TxEnvelopeTempo.deserialize(transaction); if (!envelope.signature) throw new InvalidStoreValueError(); tempo_1.TxEnvelopeTempo.hash(envelope); const written = await store.compareAndSet(submissionKey(hash, submissionId), null, transaction, { expiresAt: Date.now() + pendingOperationTtl }); if (!written) throw new InvalidStoreValueError(); } catch (cause) { if (cause instanceof InvalidStoreValueError) throw cause; throw new InvalidStoreValueError({ cause }); } } function deserialize(value) { try { if (value.length > maxStoredValueLength) throw new InvalidStoreValueError(); const operation = tempo_1.MultisigOperation.from(Json.parse(value)); assertHash(operation); return operation; } catch (cause) { if (cause instanceof InvalidStoreValueError) throw cause; throw new InvalidStoreValueError({ cause }); } } function serialize(operation) { try { const operation_ = tempo_1.MultisigOperation.from(operation); assertHash(operation_); const value = Json.stringify(operation_); if (value.length > maxStoredValueLength) throw new InvalidStoreValueError(); return value; } catch (cause) { if (cause instanceof InvalidStoreValueError) throw cause; throw new InvalidStoreValueError({ cause }); } } function assertHash(operation) { const hash = tempo_1.MultisigOperation.getHash(operation.type === 'transaction' ? { account: operation.account, config: operation.config, transaction: operation.transaction, type: operation.type, } : { account: operation.account, config: operation.config, keyAuthorization: operation.keyAuthorization, type: operation.type, }); if (hash.toLowerCase() !== operation.hash.toLowerCase()) throw new InvalidStoreValueError(); } function operationKey(hash) { return `multisig:operation:${hash.toLowerCase()}`; } function submissionKey(hash, submissionId) { return `multisig:submission:${hash.toLowerCase()}:${submissionId.toLowerCase()}`; } class InvalidStoreValueError extends base_js_1.BaseError { constructor(options = {}) { super('Stored multisig operation is malformed or unsupported.', { cause: options.cause, name: 'Multisig.Operation.InvalidStoreValueError', }); } } exports.InvalidStoreValueError = InvalidStoreValueError; class StoreConflictError extends base_js_1.BaseError { constructor() { super('Multisig operation could not be updated after repeated conflicts.', { name: 'Multisig.Operation.StoreConflictError', }); } } exports.StoreConflictError = StoreConflictError; //# sourceMappingURL=Operation.js.map