@waku/rln
Version:
RLN (Rate Limiting Nullifier) implementation for Waku
97 lines (94 loc) • 4 kB
JavaScript
import { arrayify } from '../../bytes/lib.esm/index.js';
import { defineReadOnly } from '../../properties/lib.esm/index.js';
import { Logger } from '../../logger/lib.esm/index.js';
import { version } from './_version.js';
import { Reader, Writer } from './coders/abstract-coder.js';
import { AddressCoder } from './coders/address.js';
import { ArrayCoder } from './coders/array.js';
import { BooleanCoder } from './coders/boolean.js';
import { BytesCoder } from './coders/bytes.js';
import { FixedBytesCoder } from './coders/fixed-bytes.js';
import { NullCoder } from './coders/null.js';
import { NumberCoder } from './coders/number.js';
import { StringCoder } from './coders/string.js';
import { TupleCoder } from './coders/tuple.js';
import { ParamType } from './fragments.js';
const logger = new Logger(version);
const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/);
const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/);
class AbiCoder {
constructor(coerceFunc) {
defineReadOnly(this, "coerceFunc", coerceFunc || null);
}
_getCoder(param) {
switch (param.baseType) {
case "address":
return new AddressCoder(param.name);
case "bool":
return new BooleanCoder(param.name);
case "string":
return new StringCoder(param.name);
case "bytes":
return new BytesCoder(param.name);
case "array":
return new ArrayCoder(this._getCoder(param.arrayChildren), param.arrayLength, param.name);
case "tuple":
return new TupleCoder((param.components || []).map((component) => {
return this._getCoder(component);
}), param.name);
case "":
return new NullCoder(param.name);
}
// u?int[0-9]*
let match = param.type.match(paramTypeNumber);
if (match) {
let size = parseInt(match[2] || "256");
if (size === 0 || size > 256 || (size % 8) !== 0) {
logger.throwArgumentError("invalid " + match[1] + " bit length", "param", param);
}
return new NumberCoder(size / 8, (match[1] === "int"), param.name);
}
// bytes[0-9]+
match = param.type.match(paramTypeBytes);
if (match) {
let size = parseInt(match[1]);
if (size === 0 || size > 32) {
logger.throwArgumentError("invalid bytes length", "param", param);
}
return new FixedBytesCoder(size, param.name);
}
return logger.throwArgumentError("invalid type", "type", param.type);
}
_getWordSize() { return 32; }
_getReader(data, allowLoose) {
return new Reader(data, this._getWordSize(), this.coerceFunc, allowLoose);
}
_getWriter() {
return new Writer(this._getWordSize());
}
getDefaultValue(types) {
const coders = types.map((type) => this._getCoder(ParamType.from(type)));
const coder = new TupleCoder(coders, "_");
return coder.defaultValue();
}
encode(types, values) {
if (types.length !== values.length) {
logger.throwError("types/values length mismatch", Logger.errors.INVALID_ARGUMENT, {
count: { types: types.length, values: values.length },
value: { types: types, values: values }
});
}
const coders = types.map((type) => this._getCoder(ParamType.from(type)));
const coder = (new TupleCoder(coders, "_"));
const writer = this._getWriter();
coder.encode(writer, values);
return writer.data;
}
decode(types, data, loose) {
const coders = types.map((type) => this._getCoder(ParamType.from(type)));
const coder = new TupleCoder(coders, "_");
return coder.decode(this._getReader(arrayify(data), loose));
}
}
const defaultAbiCoder = new AbiCoder();
export { AbiCoder, defaultAbiCoder };