UNPKG

@unruggable/gateways

Version:

Trustless Ethereum Multichain CCIP-Read Gateway

78 lines (77 loc) 3.47 kB
import { AbstractRollup, } from '../rollup.mjs'; import { Contract } from 'ethers/contract'; import { dataSlice } from 'ethers/utils'; import { CHAINS } from '../chains.mjs'; import { EthProver } from '../eth/EthProver.mjs'; import { ABI_CODER } from '../utils.mjs'; import { ROLLUP_ABI } from './types.mjs'; // NOTE: this is very similar to Scroll... // https://docs.morphl2.io/docs/about-morph/morphs-architecture // https://docs.morphl2.io/docs/build-on-morph/build-on-morph/bridge-between-morph-and-ethereum // https://docs.morphl2.io/docs/build-on-morph/developer-resources/morph-json-rpc-api-methods export class MorphRollup extends AbstractRollup { // https://docs.morphl2.io/docs/build-on-morph/developer-resources/contracts static mainnetConfig = { chain1: CHAINS.MAINNET, chain2: CHAINS.MORPH, Rollup: '0x759894ced0e6af42c26668076ffa84d02e3cef60', poseidon: '0x3508174Fa966e75f70B15348209E33BC711AE63e', }; static holeskyConfig = { chain1: CHAINS.HOLESKY, chain2: CHAINS.MORPH_HOLESKY, Rollup: '0x759894ced0e6af42c26668076ffa84d02e3cef60', poseidon: '0x3508174Fa966e75f70B15348209E33BC711AE63e', }; Rollup; poseidon; constructor(providers, config) { super(providers); this.Rollup = new Contract(config.Rollup, ROLLUP_ABI, this.provider1); this.poseidon = config.poseidon; } async fetchLatestCommitIndex() { return this.Rollup.lastFinalizedBatchIndex({ blockTag: this.latestBlockTag, }); } async _fetchParentCommitIndex(commit) { return this.Rollup.lastFinalizedBatchIndex({ blockTag: commit.l1BlockNumber - 1, }); } async _fetchCommit(index) { const [[commitEvent], [finalEvent]] = await Promise.all([ this.Rollup.queryFilter(this.Rollup.filters.CommitBatch(index)), this.Rollup.queryFilter(this.Rollup.filters.FinalizeBatch(index)), ]); if (!commitEvent) throw new Error(`unknown batch`); if (!finalEvent) throw new Error('not finalized'); const tx = await commitEvent.getTransaction(); const desc = this.Rollup.interface.parseTransaction(tx); if (!desc) throw new Error(`unknown transaction: ${tx.hash}`); const prover = new EthProver(this.provider2, parseLastBlock(desc.args.batchDataInput.blockContexts)); return { index, prover, l1BlockNumber: finalEvent.blockNumber }; } encodeWitness(commit, proofSeq) { return ABI_CODER.encode(['(uint256, bytes[], bytes)'], [[commit.index, proofSeq.proofs, proofSeq.order]]); } windowFromSec(sec) { // finalization time is not on-chain // https://etherscan.io/advanced-filter?eladd=0x759894ced0e6af42c26668076ffa84d02e3cef60&eltpc=0x26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d // https://explorer.morphl2.io/batches // block time: ~4sec // blocks per batch: ~285 return Math.ceil(sec / 300); // units of batchIndex } } function parseLastBlock(context) { // https://github.com/morph-l2/morph/blob/main/contracts/contracts/libraries/codec/BatchCodecV0.sol const SIZE = 60; const count = parseInt(context.slice(0, 6)); // uint16 => numBlocks const pos = 2 + SIZE * (count - 1); return BigInt(dataSlice(context, pos, pos + 8)); // uint64 => block[numBlocks - 1].blockNumber }