UNPKG

@unruggable/gateways

Version:

Trustless Ethereum Multichain CCIP-Read Gateway

124 lines (123 loc) 4.05 kB
"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;