import { AbiCoder, BigNumberish, BytesLike, hexlify, toBeHex, keccak256, toUtf8Bytes, zeroPadValue, id, } from 'ethers'; export interface ERC20Details { name: string; symbol: string; decimals: BigNumberish; maxSupply: BigNumberish; } export interface EncodedPartition { name: BytesLike; data: BytesLike; } export class Document { name: string; nameHash: BytesLike; uri: string; documentHash: BytesLike; timestamp: BigNumberish; constructor( name: string, uri: string, hash?: string, timestamp?: BigNumberish, ) { this.name = name; this.nameHash = keccak256(toUtf8Bytes(name)); this.uri = uri; this.documentHash = hash ?? keccak256(this.nameHash); this.timestamp = timestamp ?? 0n; } } export class Variable { name: string; kind: string; key: BytesLike; value: BigNumberish; encodedValue: BytesLike; constructor(name: string, kind: string, value: BigNumberish) { this.name = name; this.kind = kind; this.value = value; this.key = toBytes32(name); this.encodedValue = Variable.encodeValue(value); } // eslint-disable-next-line @typescript-eslint/no-explicit-any static encodeValue(value: any): BytesLike { return zeroPadValue(toBeHex(value.toString()), 32); } get() { return { key: this.key, kind: this.kind, }; } encode(): BytesLike { return AbiCoder.defaultAbiCoder().encode( ['bytes32[]', 'bytes32[]'], [[this.key], [this.encodedValue]], ); } } export class Partition { name: string; key: BytesLike; private variables: Map; constructor(name: string, variables: Array) { this.name = name; this.key = toBytes32(name); this.variables = new Map(); variables.forEach(this.addVariable.bind(this)); } getVariableValue(name: string): BigNumberish { const variable = this.getVariable(name); return variable.value; } getVariable(name: string): Variable { const key = toBytes32(name); if (!this.variables.has(key)) { throw Error('invalid variable'); } return this.variables.get(key); } getVariables(): Array { const variables = Array(); this.variables.forEach(variable => { variables.push(variable); }); return variables; } addVariable(variable: Variable) { this.variables.set(variable.key, variable); } setVariable(variable: Variable) { if (this.variables.has(variable.key)) { throw Error('variable already exist'); } this.variables.set(variable.key, variable); } // eslint-disable-next-line @typescript-eslint/no-explicit-any setVariableValue(name: string, value: any) { const variable = this.getVariable(name); variable.value = value; } encode(): BytesLike { return AbiCoder.defaultAbiCoder().encode( ['bytes32[]', 'bytes32[]'], [this.getKeys(), this.getEncodedValues()], ); } toPartitionStruct() { return { name: this.key, data: this.encode(), }; } private getEncodedValues(): Array { const values = Array(); this.variables.forEach(variable => { values.push(variable.encodedValue); }); return values; } private getKeys(): Array { const keys = Array(); this.variables.forEach((variable, key) => { keys.push(key); }); return keys; } } /** * Converts string to solidity byte32 representation */ export function toBytes32(data: string): BytesLike { return hexlify(zeroPadValue(toUtf8Bytes(data), 32)); } /** * @returns random(not that random though) keccak256 hash */ export function randomID() { const idx = Math.floor(Math.random() * 1_000_000); return id(`random:${idx}`); }