@unruggable/gateways
Version:
Trustless Ethereum Multichain CCIP-Read Gateway
124 lines (123 loc) • 4.05 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GatewayRequestV1 = void 0;
const constants_1 = require("ethers/constants");
const utils_1 = require("ethers/utils");
const utils_js_1 = require("./utils.cjs");
const vm_js_1 = require("./vm.cjs");
const FLAG_DYNAMIC = 0x01;
const MAX_CONSTS = 32;
const OP_FOLLOW_CONST = 0 << 5;
const OP_FOLLOW_REF = 1 << 5;
const OP_ADD_CONST = 2 << 5;
const OP_END = 0xff;
const OPERAND_MASK = 0x1f;
class GatewayRequestV1 {
target;
commands;
constants;
buf;
constructor(target = constants_1.ZeroAddress, commands = [], constants = [], buf = []) {
this.target = target;
this.commands = commands;
this.constants = constants;
this.buf = buf;
}
clone() {
return new GatewayRequestV1(this.target, this.commands.slice(), this.constants.slice(), this.buf.slice());
}
addConst(x) {
if (this.constants.length >= MAX_CONSTS)
throw new Error('too many inputs');
this.constants.push((0, utils_1.hexlify)(x));
return this.constants.length - 1;
}
start(flags, slot) {
this.end();
this.buf.push(flags);
return this.offset(slot);
}
end() {
const { buf } = this;
if (!buf.length)
return;
if (buf.length < 32 && buf[buf.length - 1] != OP_END)
buf.push(OP_END);
const bytes32 = new Uint8Array(32);
bytes32.set(buf);
this.commands.push((0, utils_1.hexlify)(bytes32));
buf.length = 0;
}
getStatic(slot) {
return this.start(0, slot);
}
getDynamic(slot) {
return this.start(FLAG_DYNAMIC, slot);
}
ref(i) {
if (!Number.isInteger(i) || i < 0 || i >= MAX_CONSTS)
throw new Error(`invalid reference: ${i}`);
this.buf.push(OP_FOLLOW_REF | i);
return this;
}
element(x) {
return this.elementBytes((0, utils_js_1.toPaddedHex)(x));
}
elementStr(s) {
return this.elementBytes((0, utils_1.toUtf8Bytes)(s));
}
elementBytes(x) {
this.buf.push(OP_FOLLOW_CONST | this.addConst(x));
return this;
}
offset(x) {
this.buf.push(OP_ADD_CONST | this.addConst((0, utils_js_1.toPaddedHex)(x)));
return this;
}
v2() {
this.end();
const req = new vm_js_1.GatewayRequest();
req.setTarget(this.target);
for (const cmd of this.commands) {
try {
const v = (0, utils_1.getBytes)(cmd);
// before ADD_CONST was added first op is initial slot offset
req.setSlot(this.constants[v[1] & OPERAND_MASK]);
for (let i = 2; i < v.length; i++) {
const op = v[i];
if (op === OP_END)
break;
const operand = op & OPERAND_MASK;
switch (op & 0xe0) {
case OP_ADD_CONST: {
req.push(this.constants[operand]).addSlot();
continue;
}
case OP_FOLLOW_CONST: {
req.pushBytes(this.constants[operand]).follow();
continue;
}
case OP_FOLLOW_REF: {
req.pushOutput(operand).follow();
continue;
}
default:
throw new Error(`unknown op: ${op}`);
}
}
if (v[0] & FLAG_DYNAMIC) {
req.readBytes();
}
else {
req.read();
}
req.addOutput();
}
catch (cause) {
throw new Error(`command: ${cmd}`, { cause });
}
}
return req;
}
}
exports.GatewayRequestV1 = GatewayRequestV1;