@unruggable/gateways
Version:
Trustless Ethereum Multichain CCIP-Read Gateway
91 lines (90 loc) • 3.58 kB
JavaScript
import { AbstractRollup } from '../rollup.mjs';
import { NitroRollup } from './NitroRollup.mjs';
import { ABI_CODER } from '../utils.mjs';
import { GatewayRequest } from '../vm.mjs';
// NOTE: when finalized, the delay is 2x7days
// rollup12 finalization works as expected
// rollup23 finalization is latestConfirmed or latestCreated (unfinalized)
// TODO: implement minAgeBlocks for rollup23
// TODO: implement BoLD support for rollup23
function createRequestForNitro(address, unfinalized = false) {
const SLOT_NODE_STORAGE = 117n;
const SLOT_NODES_MAP = 118n;
const SLOT_OFFSET_CONFIRM_DATA = 2n;
//const SLOT_OFFSET_CREATED_AT = 4n;
// uint64 private _latestConfirmed;
// uint64 private _firstUnresolvedNode;
// uint64 private _latestNodeCreated;
// uint64 private _lastStakeBlock;
// mapping(uint64 => Node) private _nodes;
const req = new GatewayRequest(2); // 3
req.setTarget(address).setSlot(SLOT_NODE_STORAGE).read();
// TODO: figure out how to prove a slightly later node
if (unfinalized)
req.shr(128); // use latestNodeCreated instead of latestConfirmed
req.push(0xffffffffffffffffn).and().dup().setOutput(0); // node
req.setSlot(SLOT_NODES_MAP).follow(); // _nodes[node]
req.getSlot(); // save
req.offset(SLOT_OFFSET_CONFIRM_DATA).read().setOutput(1); // confirmData
req.slot(); // restore
// NOTE: createdAtBlock is L1 block not L2
//req.offset(SLOT_OFFSET_CREATED_AT).read().shr(192).setOutput(2); // createdAtBlock
return req;
}
export class DoubleArbitrumRollup extends AbstractRollup {
rollup12;
rollup23;
request;
constructor(rollup12, provider3, config23, minAgeBlocks23 = 0) {
super({ provider1: rollup12.provider1, provider2: provider3 });
this.rollup12 = rollup12;
this.rollup23 = new NitroRollup({ provider1: rollup12.provider2, provider2: provider3 }, config23, minAgeBlocks23);
this.rollup23.latestBlockTag = 'latest'; // TODO: explain this
this.request = createRequestForNitro(config23.Rollup, this.rollup23.unfinalized);
}
get unfinalized() {
return this.rollup12.unfinalized || this.rollup23.unfinalized;
}
fetchLatestCommitIndex() {
return this.rollup12.fetchLatestCommitIndex();
}
_fetchParentCommitIndex(commit) {
return this.rollup12.fetchParentCommitIndex(commit.commit12);
}
async _fetchCommit(index) {
const commit12 = await this.rollup12.fetchCommit(index);
const state = await commit12.prover.evalRequest(this.request);
const [proofSeq12, outputs] = await Promise.all([
commit12.prover.prove(state.needs),
state.resolveOutputs(),
]);
const node = BigInt(outputs[0]);
const commit23 = await this.rollup23.fetchCommit(node);
return {
index,
prover: commit23.prover,
proofSeq12,
commit12,
commit23,
};
}
encodeWitness(commit, proofSeq23) {
return ABI_CODER.encode(['(bytes,bytes[],bytes)[2]'], [
[
[
commit.commit12.encodedRollupProof,
commit.proofSeq12.proofs,
commit.proofSeq12.order,
],
[
commit.commit23.encodedRollupProof,
proofSeq23.proofs,
proofSeq23.order,
],
],
]);
}
windowFromSec(sec) {
return this.rollup12.windowFromSec(sec);
}
}