Facet Docs
  • 1. Introduction
    • Overview of Facet Protocol
    • What is Layer 1+?
    • The Based Sovereign Rollup
  • 2. Getting Started
    • Connecting a Wallet
    • Sending Transactions
    • Bridging In (and Out)
    • What about Gas?
    • Facet Apps
  • 3. Technical Details
    • Introduction
    • Facet RPC & Explorer
    • Genesis Contracts
    • Facet Transactions
      • From Calldata
      • From Event Logs
    • Facet Typescript SDK
    • Facet Sol (Foundry)
    • Chain State Derivation
    • Running a Facet Node
    • Bridging Assets
    • Building an Optimistic Bridge on Facet
    • Basic Transaction Flow
    • Facet's Gas Mechanism
      • FCT Issuance Calculation
      • FCT Gas Fee Calculation
    • Security Audits
  • 4. Community & Support
    • FAQs
    • Comparison with Other Rollups
    • Micro-Grants
    • Community Resources
    • Brand Kit
Powered by GitBook
On this page
  • Getting started
  • Installation Instructions
  1. 3. Technical Details

Building an Optimistic Bridge on Facet

PreviousBridging AssetsNextBasic Transaction Flow

Last updated 6 months ago

You can use to build an OP-style optimistic bridge on Facet. Facet Optimism provides tools to run an optimistic bridge on Facet using Optimism's technology. It includes modified versions of:

  1. Op L1 smart contracts

  2. Op L2 smart contracts

  3. op-node

  4. op-proposer

Unused components like op-challenger and op-batcher remain unmodified.

Getting started

Key points:

  1. This code is separate from the Facet protocol. It's a set of third-party tools for working with Facet.

  2. These tools are read-only for the Facet protocol. The op-node here only provides information about Facet and doesn't participate in L2 derivation.

Installation Instructions

Basic Setup

  1. git clone

  2. Use the facetv1.9.1 branch.

  3. Follow for setup.

  4. Use the provided rollup-config.json.

  5. Complete the .envrc file.

  6. Use https://sepolia.facet.org for OP_NODE_L2_ENGINE_RPC.

Deploy the Contracts

cd packages/contracts-bedrock
direnv allow
npx ts-node scripts/setUpFacetBridges.ts

This will deploy and verify all the L1 and L2 contracts you need to bridge. It will also create an L2 token you can bridge into using a public L1 Test Token (0x5589BB8228C07c4e15558875fAf2B859f678d129).

Start op-node and op-proposer

In one terminal: (Assuming you're still in packages/contracts-bedrock)

cd ../..
direnv allow
./init_node.sh

In another terminal:

./init_proposer.sh

Now you are posting L2 outputs to the L2 Output Oracle. Make sure your proposer address has enough testnet ether!

From here on out it's exactly the same as how you'd bridge with Optimism.

Bridge a Token into Facet

  1. Edit TestBridgeIn.s.sol in packages/contracts-bedrock/.

  2. Run:

    forge script -vvv './scripts/TestBridgeIn.s.sol' --private-key $DEPLOY_ETH_KEY --rpc-url "$DEPLOY_ETH_RPC_URL" --broadcast --tc TestBridgeIn
  3. Verify the balance increase on the L2 explorer.

Bridge a Token out of Facet

  1. Visit the L2StandardBridge page on the L2 explorer.

  2. Use the bridgeERC20To function.

  3. Submit the transaction.

  4. Wait for the output to be posted to the L2 Output Oracle (every 30 blocks by default).

You can bridge out the same token you bridged in.

Now wait for the corresponding output to be posted to the L2 Output Oracle. The default configuration is for this to happen every 30 blocks.

Prove and Finalize the Withdrawal

Use the provided example script, adapting it as needed for your specific withdrawal.

async function main() {
  const receipt = await publicClientL2.getTransactionReceipt({
    hash: '0x3b1c2629aae57d61b326ea38d01d297a51600cca88bd3a8e5aaa8b9eedf753b0',
  })

  const [withdrawal] = getWithdrawals(receipt)


  const sourceId = 11155111

  export const facetSepolia = defineChain({
    id: 0xface7a,
    name: "Facet Sepolia",
    nativeCurrency: { name: "Facet Compute Token", symbol: "FCT", decimals: 18 },
    rpcUrls: {
      default: {
        http: ["https://sepolia.facet.org"],
      },
    },
    blockExplorers: {
      default: {
        name: "Blockscout",
        url: "https://sepolia.explorer.facet.org",
      },
    },
    contracts: {
      ...chainConfig.contracts,
      l2OutputOracle: {
        [sepolia.id]: {
          address: "0xDf9aF3B2e9617D53FD2E0096859ec7f4db6c96c9",
        },
      },
      portal: {
        [sepolia.id]: {
          address: "0x34936f885d551C5f887Ed50bDc02eEB89F015930",
        },
      },
      l1StandardBridge: {
        [sepolia.id]: {
          address: "0x46787ffeC1be4dc1c9D8eaD9dE3B83E41063C772",
        },
      },
    },
    sourceId: sourceId,
  });

  const output = await publicClientL1.getL2Output({
    l2BlockNumber: receipt.blockNumber,
    targetChain: facetSepolia,
  })

  console.log({output})

  const args1 = await publicClientL2.buildProveWithdrawal({
    output,
    withdrawal
  })

  const args = {
    ...args1,
    authorizationList: [],
    targetChain: facetSepolia
  }

  console.log({args})

  const proveHash = await walletClientL1.proveWithdrawal(args as any)

  const proveReceipt = await publicClientL1.waitForTransactionReceipt({
    hash: proveHash
  })

  console.log({proveReceipt})

  // Wait for the challenge period to end
  await new Promise(resolve => setTimeout(resolve, 60000));

  const finalizeHash = await walletClientL1.finalizeWithdrawal({
    targetChain: facetSepolia,
    withdrawal,
  })

  // Wait until the withdrawal is finalized.
  const finalizeReceipt = await publicClientL1.waitForTransactionReceipt({
    hash: finalizeHash
  })

  console.log(finalizeReceipt)
}

Find your createOptimismMintableERC20 transaction on the .

facet-optimism
https://github.com/0xFacet/facet-optimism
Optimism's instructions
Facet testnet explorer