viem
Version:
163 lines • 6.32 kB
JavaScript
;
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