UNPKG

viem

Version:

TypeScript Interface for Ethereum

89 lines 3.63 kB
import * as Address from 'ox/Address'; import * as Hash from 'ox/Hash'; import * as Json from 'ox/Json'; import { MultisigConfig } from 'ox/tempo'; import { BaseError } from '../../errors/base.js'; import { nativeMultisigFactory } from '../Addresses.js'; /** A valid 48-owner config is much smaller; 64 KiB bounds hostile store parsing work. */ const maxStoredValueLength = 65_536; /** Zero commitment used before an account is initialized. */ const zeroCommitment = `0x${'00'.repeat(32)}`; /** Reads a cached multisig config. */ export async function read(store, options) { const { address, commitment } = options; const value = await store.getItem(key({ address, commitment })); if (value === null || value === undefined) return null; const config = deserialize(value); assertKey({ address, commitment, config }); return config; } /** Writes a validated multisig config. */ export async function write(store, options) { const { address, commitment } = options; const config = MultisigConfig.from(options.config); assertKey({ address, commitment, config }); const value = serialize(config); await store.setItem(key({ address, commitment }), value); // Initialization commits the version-zero config without changing its version. if (commitment.toLowerCase() === zeroCommitment) await store.setItem(key({ address, commitment: MultisigConfig.getCommitment(config) }), value); } /** Verifies that a config matches its account-and-commitment key. */ function assertKey(options) { const { address, commitment, config } = options; if (!Address.validate(address) || !Hash.validate(commitment)) throw new InvalidStoreValueError(); if (config.version === 0n) { if (!Address.isEqual(MultisigConfig.getAddress(config, { factory: nativeMultisigFactory }), address)) throw new InvalidStoreValueError(); if (commitment.toLowerCase() === zeroCommitment) return; } if (MultisigConfig.getCommitment(config).toLowerCase() !== commitment.toLowerCase()) throw new InvalidStoreValueError(); } /** Deserializes a multisig config from storage. */ function deserialize(value) { try { if (value.length > maxStoredValueLength) throw new InvalidStoreValueError(); return MultisigConfig.fromRpc(Json.parse(value)); } catch (cause) { if (cause instanceof InvalidStoreValueError) throw cause; throw new InvalidStoreValueError({ cause }); } } /** Returns the store key for an account and config commitment. */ function key(options) { const { address, commitment } = options; return `multisig:config:${address.toLowerCase()}:${commitment.toLowerCase()}`; } /** Serializes a multisig config for storage. */ function serialize(config) { try { const value = Json.stringify(MultisigConfig.toRpc(config)); if (value.length > maxStoredValueLength) throw new InvalidStoreValueError(); return value; } catch (cause) { if (cause instanceof InvalidStoreValueError) throw cause; throw new InvalidStoreValueError({ cause }); } } /** Thrown when a stored multisig config is malformed or mismatched. */ export class InvalidStoreValueError extends BaseError { /** Creates an invalid store value error. */ constructor(options = {}) { super('Stored multisig config is malformed or mismatched.', { cause: options.cause, name: 'Multisig.Config.InvalidStoreValueError', }); } } //# sourceMappingURL=Config.js.map