From 1779109a440145bf0638489d9f5777649f7f0fb1 Mon Sep 17 00:00:00 2001 From: Blessing Krofegha Date: Mon, 30 Sep 2024 16:22:37 +0100 Subject: [PATCH 1/6] initial commit --- .../tutorials/send-tx-from-eth.mdx | 164 ++++++++++-------- 1 file changed, 89 insertions(+), 75 deletions(-) diff --git a/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx b/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx index d7a53efe3..bd285f96a 100644 --- a/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx +++ b/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx @@ -1,37 +1,31 @@ --- -title: Triggering OP Mainnet Transactions from Ethereum +title: Triggering OP Mainnet Transactions from Ethereum using Viem lang: en-US -description: Learn how to force transaction inclusion without the OP Mainnet Sequencer. +description: Learn how to force transaction inclusion without the OP Mainnet Sequencer using Viem. --- import { Callout, Steps } from 'nextra/components' import { WipCallout } from '@/components/WipCallout' -# Triggering OP Mainnet Transactions from Ethereum +# Triggering OP Mainnet Transactions from Ethereum using Viem +OP Mainnet currently uses a single-Sequencer block production model. +This means that there is only one Sequencer active on the network at any given time. Single-Sequencer models are simpler than their highly decentralized counterparts but they are also more vulnerable to potential downtime. -OP Mainnet currently uses a single-Sequencer block production model. -This means that there is only one Sequencer active on the network at any given time. -Single-Sequencer models are simpler than their highly decentralized counterparts but they are also more vulnerable to potential downtime. +Sequencer downtime must not be able to prevent users from transacting on the network. As a result, OP Mainnet includes a mechanism for "forcing" transactions to be included in the blockchain. This mechanism involves triggering a transaction on OP Mainnet by sending a transaction on Ethereum. -Sequencer downtime must not be able to prevent users from transacting on the network. -As a result, OP Mainnet includes a mechanism for "forcing" transactions to be included in the blockchain. -This mechanism involves triggering a transaction on OP Mainnet by sending a transaction on Ethereum. - -In this tutorial you'll learn how to trigger a transaction on OP Mainnet from Ethereum. -You'll use the OP Sepolia testnet, but the same logic will apply to OP Mainnet. +In this tutorial you'll learn how to trigger a transaction on OP Mainnet from Ethereum using Viem. You'll use the OP Sepolia testnet, but the same logic will apply to OP Mainnet. ## Dependencies -* [node](https://nodejs.org/en/) -* [pnpm](https://pnpm.io/installation) +* [node](https://nodejs.org/en/) +* [pnpm](https://pnpm.io/installation) ## Create a Demo Project -You're going to use the `@eth-optimism/contracts-ts` package for this tutorial. -Since the `@eth-optimism/contracts-ts` package is a [Node.js](https://nodejs.org/en/) library, you'll need to create a Node.js project to use it. +You're going to use the `viem` package for this tutorial. Since Viem is a [Node.js](https://nodejs.org/en/) library, you'll need to create a Node.js project to use it. @@ -48,22 +42,10 @@ cd op-sample-project pnpm init ``` -{

Install the Contracts Package

} - -```bash -pnpm add @eth-optimism/contracts-ts -``` - -{

Install the Utils Package

} - -```bash -pnpm add @eth-optimism/core-utils -``` - -{

Install ethers.js

} +{

Install Viem

} ```bash -pnpm add ethers@^5 +pnpm add viem ```
@@ -75,8 +57,7 @@ If you have [`cast`](https://book.getfoundry.sh/getting-started/installation) in ## Get ETH on Sepolia and OP Sepolia -This tutorial explains how to bridge tokens from Sepolia to OP Sepolia. -You will need to get some ETH on both of these testnets. +This tutorial explains how to bridge tokens from Sepolia to OP Sepolia. You will need to get some ETH on both of these testnets. You can use [this faucet](https://sepoliafaucet.com) to get ETH on Sepolia. @@ -85,8 +66,8 @@ You can use the [Superchain Faucet](https://console.optimism.io/faucet?utm_sourc ## Add a Private Key to Your Environment -You need a private key in order to sign transactions. -Set your private key as an environment variable with the `export` command. +You need a private key in order to sign transactions. +Set your private key as an environment variable with the `export` command. Make sure this private key corresponds to an address that has ETH on both Sepolia and OP Sepolia. ```bash @@ -95,7 +76,7 @@ export TUTORIAL_PRIVATE_KEY=0x... ## Start the Node REPL -You're going to use the Node REPL to interact with the Optimism SDK. +You're going to use the Node REPL to interact with Viem. To start the Node REPL run the following command in your terminal: ```bash @@ -110,111 +91,144 @@ You need to import some dependencies into your Node REPL session. -{

Import the Contracts Package

} +{

Import Viem

} -```js file=/public/tutorials/send-tx-from-eth.js#L3 hash=02e8ca4ffb8e411c4b43d969c5533e24 -``` - -{

Import the Utils Package

} - -```js file=/public/tutorials/send-tx-from-eth.js#L4 hash=6e350dd75d29dff73d09b1f0cdd1fe78 -``` - -{

Import ethers.js

} - -```js file=/public/tutorials/send-tx-from-eth.js#L5 hash=69a65ef97862612e4978b8563e6dbe3a +```js +const { createPublicClient, createWalletClient, http, parseEther, formatEther } = require('viem'); +const { optimismSepolia, sepolia } = require('viem/chains'); ```
## Set Session Variables -You'll need a few variables throughout this tutorial. -Let's set those up now. +You'll need a few variables throughout this tutorial. Let's set those up now. {

Load your private key

} -```js file=/public/tutorials/send-tx-from-eth.js#L7 hash=755b77a7ffc7dfdc186f36c37d3d847a +```js +const privateKey = process.env.TUTORIAL_PRIVATE_KEY; ``` {

Create the RPC providers and wallets

} -```js file=/public/tutorials/send-tx-from-eth.js#L9-L12 hash=9afdce50665ae93bce602068071ffaa1 +```js +const l1PublicClient = createPublicClient({ chain: sepolia, transport: http() }); +const l2PublicClient = createPublicClient({ chain: optimismSepolia, transport: http() }); +const l1WalletClient = createWalletClient({ chain: sepolia, transport: http() }); +const l2WalletClient = createWalletClient({ chain: optimismSepolia, transport: http() }); ```
## Check Your Initial Balance -You'll be sending a small amount of ETH as part of this tutorial. -Quickly check your balance on OP Sepolia so that you know how much you had at the start of the tutorial. +You'll be sending a small amount of ETH as part of this tutorial. Quickly check your balance on OP Sepolia so that you know how much you had at the start of the tutorial. -```js file=/public/tutorials/send-tx-from-eth.js#L15-L16 hash=062c80bbd70e12144fe45532611a1846 +```js +const address = await l2WalletClient.account.address; +const initialBalance = await l2PublicClient.getBalance({ address }); +console.log(`Initial balance: ${formatEther(initialBalance)} ETH`); ``` ## Trigger the Transaction -Now you'll use the [`OptimismPortal`](https://github.com/ethereum-optimism/optimism/blob/62c7f3b05a70027b30054d4c8974f44000606fb7/packages/contracts-bedrock/contracts/L1/OptimismPortal.sol) contract to trigger a transaction on OP Sepolia by sending a transaction on Sepolia. +Now you'll use the `OptimismPortal` contract to trigger a transaction on OP Sepolia by sending a transaction on Sepolia. {

Create the OptimismPortal object

} -```js file=/public/tutorials/send-tx-from-eth.js#L18-L22 hash=75e09aebd1fe33724587ce7464f91940 +```js +const optimismPortalAbi = [ + { + inputs: [ + { internalType: 'uint256', name: '_gasLimit', type: 'uint256' }, + { internalType: 'bytes', name: '_data', type: 'bytes' }, + ], + name: 'depositTransaction', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, +]; + +const optimismPortalAddress = '0x16fc5058f25648194471939df75cf27a2fdc48bc'; ``` {

Estimate the required gas

} -When sending transactions via the `OptimismPortal` contract it's important to always include a gas buffer. -This is because the `OptimismPortal` charges a variable amount of gas depending on the current demand for L2 transactions triggered via L1. -If you do not include a gas buffer, your transactions may fail. +When sending transactions via the `OptimismPortal` contract it's important to always include a gas buffer. This is because the `OptimismPortal` charges a variable amount of gas depending on the current demand for L2 transactions triggered via L1. If you do not include a gas buffer, your transactions may fail. -```js file=/public/tutorials/send-tx-from-eth.js#L25-L31 hash=a5ed372cf7ae78a6fea1e7a65c582cee +```js +const gasLimit = 100000n; +const data = '0x'; +const value = parseEther('0.000001'); + +const gasEstimate = await l1PublicClient.estimateContractGas({ + address: optimismPortalAddress, + abi: optimismPortalAbi, + functionName: 'depositTransaction', + args: [gasLimit, data], + value, +}); ``` {

Send the transaction

} -Now you'll send the transaction. -Note that you are including a buffer of 20% on top of the gas estimate. +Now you'll send the transaction. Note that you are including a buffer of 20% on top of the gas estimate. + +```js +const { hash: l1TxHash } = await l1WalletClient.writeContract({ + address: optimismPortalAddress, + abi: optimismPortalAbi, + functionName: 'depositTransaction', + args: [gasLimit, data], + value, + gas: gasEstimate * 120n / 100n, // 20% buffer +}); -```js file=/public/tutorials/send-tx-from-eth.js#L34-L43 hash=57a69ed74c2fb3bf2242b0452ed00f88 +console.log(`L1 transaction hash: ${l1TxHash}`); ``` {

Wait for the L1 transaction

} First you'll need to wait for the L1 transaction to be mined. -```js file=/public/tutorials/send-tx-from-eth.js#L46 hash=efcac85d794ab4711595112fbe2c7a8e +```js +const l1Receipt = await l1PublicClient.waitForTransactionReceipt({ hash: l1TxHash }); ``` {

Wait for the L2 transaction

} -Now you'll need to wait for the corresponding L2 transaction to be included in a block. -This transaction is automatically created as a result of your L1 transaction. -Here you'll determine the hash of the L2 transaction using the `@eth-optimism/core-utils` library and then wait for that transaction to be included in the L2 blockchain. +Now you'll need to wait for the corresponding L2 transaction to be included in a block. This transaction is automatically created as a result of your L1 transaction. Here you'll determine the hash of the L2 transaction and then wait for that transaction to be included in the L2 blockchain. -```js file=/public/tutorials/send-tx-from-eth.js#L49-L50 hash=28b3fcba963fc4b960e89cc96b20aea2 +```js +const l2TxHash = l1Receipt.logs[0].topics[1]; +const l2Receipt = await l2PublicClient.waitForTransactionReceipt({ hash: l2TxHash }); +console.log(`L2 transaction hash: ${l2TxHash}`); ```
## Check Your Updated Balance -You should have a little less ETH on OP Sepolia now. -Check your balance to confirm. +You should have a little less ETH on OP Sepolia now. Check your balance to confirm. -```js file=/public/tutorials/send-tx-from-eth.js#L53-L54 hash=b907d1590d7b39e8cfba4fb84886a8f9 +```js +const finalBalance = await l2PublicClient.getBalance({ address }); +console.log(`Final balance: ${formatEther(finalBalance)} ETH`); ``` Make sure that the difference is equal to the amount you were expecting to send. -```js file=/public/tutorials/send-tx-from-eth.js#L57-L58 hash=e44227b3ca6f46e6a16a10689b11ad39 +```js +const difference = initialBalance - finalBalance; +console.log(`Difference: ${formatEther(difference)} ETH`); ``` ## Next Steps -You've successfully triggered a transaction on OP Sepolia by sending a transaction on Sepolia. -Although this tutorial demonstrated the simple example of sending a basic ETH transfer from your L2 address via the OptimismPortal contract, you can use this same technique to trigger any transaction you want. -You can trigger smart contracts, send ERC-20 tokens, and more. +You've successfully triggered a transaction on OP Sepolia by sending a transaction on Sepolia using Viem. Although this tutorial demonstrated the simple example of sending a basic ETH transfer from your L2 address via the OptimismPortal contract, you can use this same technique to trigger any transaction you want. You can trigger smart contracts, send ERC-20 tokens, and more. \ No newline at end of file From 58fb20b9cfa957fd857061ab50ae617d5fb26f76 Mon Sep 17 00:00:00 2001 From: Blessing Krofegha Date: Mon, 30 Sep 2024 16:26:15 +0100 Subject: [PATCH 2/6] update codebase --- .../app-developers/tutorials/send-tx-from-eth.mdx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx b/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx index bd285f96a..492712ea2 100644 --- a/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx +++ b/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx @@ -5,17 +5,13 @@ description: Learn how to force transaction inclusion without the OP Mainnet Seq --- import { Callout, Steps } from 'nextra/components' -import { WipCallout } from '@/components/WipCallout' - # Triggering OP Mainnet Transactions from Ethereum using Viem OP Mainnet currently uses a single-Sequencer block production model. - This means that there is only one Sequencer active on the network at any given time. Single-Sequencer models are simpler than their highly decentralized counterparts but they are also more vulnerable to potential downtime. Sequencer downtime must not be able to prevent users from transacting on the network. As a result, OP Mainnet includes a mechanism for "forcing" transactions to be included in the blockchain. This mechanism involves triggering a transaction on OP Mainnet by sending a transaction on Ethereum. - In this tutorial you'll learn how to trigger a transaction on OP Mainnet from Ethereum using Viem. You'll use the OP Sepolia testnet, but the same logic will apply to OP Mainnet. ## Dependencies @@ -115,10 +111,10 @@ const privateKey = process.env.TUTORIAL_PRIVATE_KEY; {

Create the RPC providers and wallets

} ```js -const l1PublicClient = createPublicClient({ chain: sepolia, transport: http() }); -const l2PublicClient = createPublicClient({ chain: optimismSepolia, transport: http() }); -const l1WalletClient = createWalletClient({ chain: sepolia, transport: http() }); -const l2WalletClient = createWalletClient({ chain: optimismSepolia, transport: http() }); +const l1PublicClient = createPublicClient({ chain: sepolia, transport: http("https://rpc.ankr.com/eth_sepolia") }); +const l2PublicClient = createPublicClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io") }); +const l1WalletClient = createWalletClient({ chain: sepolia, transport: http("https://rpc.ankr.com/eth_sepolia") }); +const l2WalletClient = createWalletClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io") }); ``` From 4328376b8b65cc8143d6a24f798b35b0e4a0e055 Mon Sep 17 00:00:00 2001 From: Blessing Krofegha Date: Wed, 9 Oct 2024 21:38:31 +0100 Subject: [PATCH 3/6] updated codebase --- .../tutorials/send-tx-from-eth.mdx | 75 ++--------- public/tutorials/send-tx-from-eth.js | 120 ++++++++++-------- 2 files changed, 75 insertions(+), 120 deletions(-) diff --git a/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx b/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx index 492712ea2..022ebd92d 100644 --- a/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx +++ b/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx @@ -89,9 +89,7 @@ You need to import some dependencies into your Node REPL session. {

Import Viem

} -```js -const { createPublicClient, createWalletClient, http, parseEther, formatEther } = require('viem'); -const { optimismSepolia, sepolia } = require('viem/chains'); +```js file=/public/tutorials/send-tx-from-eth.js#L3-L5 hash=7a906fc04fa87f91fc33049240e8e0f8 ``` @@ -104,17 +102,12 @@ You'll need a few variables throughout this tutorial. Let's set those up now. {

Load your private key

} -```js -const privateKey = process.env.TUTORIAL_PRIVATE_KEY; +```js file=/public/tutorials/send-tx-from-eth.js#L7-L8 hash=46ba01375a5d8844b2315f0e579dfac3 ``` {

Create the RPC providers and wallets

} -```js -const l1PublicClient = createPublicClient({ chain: sepolia, transport: http("https://rpc.ankr.com/eth_sepolia") }); -const l2PublicClient = createPublicClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io") }); -const l1WalletClient = createWalletClient({ chain: sepolia, transport: http("https://rpc.ankr.com/eth_sepolia") }); -const l2WalletClient = createWalletClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io") }); +```js file=/public/tutorials/send-tx-from-eth.js#L10-L13 hash=a364c906d788d0614588c8db059cfcca ``` @@ -123,10 +116,7 @@ const l2WalletClient = createWalletClient({ chain: optimismSepolia, transport: h You'll be sending a small amount of ETH as part of this tutorial. Quickly check your balance on OP Sepolia so that you know how much you had at the start of the tutorial. -```js -const address = await l2WalletClient.account.address; -const initialBalance = await l2PublicClient.getBalance({ address }); -console.log(`Initial balance: ${formatEther(initialBalance)} ETH`); +```js file=/public/tutorials/send-tx-from-eth.js#L15-L17 hash=5b95f18440ad72b6200ed7b5df00ca8f ``` ## Trigger the Transaction @@ -137,74 +127,35 @@ Now you'll use the `OptimismPortal` contract to trigger a transaction on OP Sepo {

Create the OptimismPortal object

} -```js -const optimismPortalAbi = [ - { - inputs: [ - { internalType: 'uint256', name: '_gasLimit', type: 'uint256' }, - { internalType: 'bytes', name: '_data', type: 'bytes' }, - ], - name: 'depositTransaction', - outputs: [], - stateMutability: 'payable', - type: 'function', - }, -]; - -const optimismPortalAddress = '0x16fc5058f25648194471939df75cf27a2fdc48bc'; +```js file=/public/tutorials/send-tx-from-eth.js#L19-L30 hash=bb10ed96a0eed859d491afc1929001ce ``` {

Estimate the required gas

} When sending transactions via the `OptimismPortal` contract it's important to always include a gas buffer. This is because the `OptimismPortal` charges a variable amount of gas depending on the current demand for L2 transactions triggered via L1. If you do not include a gas buffer, your transactions may fail. -```js -const gasLimit = 100000n; -const data = '0x'; -const value = parseEther('0.000001'); - -const gasEstimate = await l1PublicClient.estimateContractGas({ - address: optimismPortalAddress, - abi: optimismPortalAbi, - functionName: 'depositTransaction', - args: [gasLimit, data], - value, -}); +```js file=/public/tutorials/send-tx-from-eth.js#L32-L43 hash=ae495cba1a72841059a32edaf20f854d ``` {

Send the transaction

} Now you'll send the transaction. Note that you are including a buffer of 20% on top of the gas estimate. -```js -const { hash: l1TxHash } = await l1WalletClient.writeContract({ - address: optimismPortalAddress, - abi: optimismPortalAbi, - functionName: 'depositTransaction', - args: [gasLimit, data], - value, - gas: gasEstimate * 120n / 100n, // 20% buffer -}); - -console.log(`L1 transaction hash: ${l1TxHash}`); +```js file=/public/tutorials/send-tx-from-eth.js#L45-L54 hash=6fb0ba06fb29be7ee2c945fca75a50f4 ``` {

Wait for the L1 transaction

} First you'll need to wait for the L1 transaction to be mined. -```js -const l1Receipt = await l1PublicClient.waitForTransactionReceipt({ hash: l1TxHash }); +```js file=/public/tutorials/send-tx-from-eth.js#L56 hash=3c0301f8a9ca78bd8bfbff6aef807c77 ``` {

Wait for the L2 transaction

} Now you'll need to wait for the corresponding L2 transaction to be included in a block. This transaction is automatically created as a result of your L1 transaction. Here you'll determine the hash of the L2 transaction and then wait for that transaction to be included in the L2 blockchain. -```js -const l2TxHash = l1Receipt.logs[0].topics[1]; -const l2Receipt = await l2PublicClient.waitForTransactionReceipt({ hash: l2TxHash }); -console.log(`L2 transaction hash: ${l2TxHash}`); +```js file=/public/tutorials/send-tx-from-eth.js#L58-L60 hash=cdd456e54b0f8507f96365dae05b8856 ``` @@ -213,16 +164,12 @@ console.log(`L2 transaction hash: ${l2TxHash}`); You should have a little less ETH on OP Sepolia now. Check your balance to confirm. -```js -const finalBalance = await l2PublicClient.getBalance({ address }); -console.log(`Final balance: ${formatEther(finalBalance)} ETH`); +```js file=/public/tutorials/send-tx-from-eth.js#L62-L63 hash=7cac2670afeb0fcc88346bc59b90466c ``` Make sure that the difference is equal to the amount you were expecting to send. -```js -const difference = initialBalance - finalBalance; -console.log(`Difference: ${formatEther(difference)} ETH`); +```js file=/public/tutorials/send-tx-from-eth.js#L65-L66 hash=e2ef73867c6d755ca89b9d3381522208 ``` ## Next Steps diff --git a/public/tutorials/send-tx-from-eth.js b/public/tutorials/send-tx-from-eth.js index 9666aeb07..c2921b837 100644 --- a/public/tutorials/send-tx-from-eth.js +++ b/public/tutorials/send-tx-from-eth.js @@ -1,60 +1,68 @@ (async () => { -const contracts = require("@eth-optimism/contracts-ts") -const utils = require("@eth-optimism/core-utils") -const ethers = require("ethers") - -const privateKey = process.env.TUTORIAL_PRIVATE_KEY - -const l1Provider = new ethers.providers.StaticJsonRpcProvider("https://rpc.ankr.com/eth_sepolia") -const l2Provider = new ethers.providers.StaticJsonRpcProvider("https://sepolia.optimism.io") -const l1Wallet = new ethers.Wallet(privateKey, l1Provider) -const l2Wallet = new ethers.Wallet(privateKey, l2Provider) - -console.log('Initial balance:') -const initialBalance = await l2Wallet.getBalance() -console.log(ethers.utils.formatEther(initialBalance)) - -const OptimismPortal = new ethers.Contract( - '0x16Fc5058F25648194471939df75CF27A2fdC48BC', - contracts.optimismPortalABI, - l1Wallet, -) - -console.log('Estimating L1 transaction gas...') -const gas = await OptimismPortal.estimateGas.depositTransaction( - '0x1000000000000000000000000000000000000000', // _to - ethers.utils.parseEther('0.000069420'), // _value - 1e6, // _gasLimit - false, // _isCreation - '0x', // _data -) - -console.log('Sending L1 transaction...') -const tx = await OptimismPortal.depositTransaction( - '0x1000000000000000000000000000000000000000', // _to - ethers.utils.parseEther('0.000069420'), // _value - 1e6, // _gasLimit - false, // _isCreation - '0x', // _data - { - gasLimit: gas.mul(120).div(100) // Add 20% buffer - } -) - -console.log('Waiting for L1 transaction...') -const receipt = await tx.wait() - -console.log('Waiting for L2 transaction to be relayed...') -const deposit = utils.DepositTx.fromL1Receipt(receipt, 0) -await l2Provider.waitForTransaction(deposit.hash()) - -console.log('Final balance:') -const finalBalance = await l2Wallet.getBalance() -console.log(ethers.utils.formatEther(finalBalance)) - -console.log('Difference:') -const difference = initialBalance.sub(finalBalance) -console.log(ethers.utils.formatEther(difference)) + const { createPublicClient, createWalletClient, http, parseEther, formatEther } = require('viem'); + const { optimismSepolia, sepolia } = require('viem/chains'); + const { privateKeyToAccount } = require('viem/accounts'); + + const privateKey = process.env.TUTORIAL_PRIVATE_KEY; + const account = privateKeyToAccount(privateKey); + + const l1PublicClient = createPublicClient({ chain: sepolia, transport: http("https://rpc.ankr.com/eth_sepolia") }).extend(publicActionsL1()) + const l2PublicClient = createPublicClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io") }).extend(publicActionsL2()); + const l1WalletClient = createWalletClient({ chain: sepolia, transport: http("https://rpc.ankr.com/eth_sepolia") }).extend(walletActionsL1()); + const l2WalletClient = createWalletClient({ chain: optimismSepolia, transport: http("https://sepolia.optimism.io") }).extend(walletActionsL2()) + + const address = account.address; + const initialBalance = await l2PublicClient.getBalance({ address }); + console.log(`Initial balance: ${formatEther(initialBalance)} ETH`); + + const optimismPortalAbi = [ + { + inputs: [ + { internalType: 'uint256', name: '_gasLimit', type: 'uint256' }, + { internalType: 'bytes', name: '_data', type: 'bytes' }, + ], + name: 'depositTransaction', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + ]; + + const optimismPortalAddress = '0x1000000000000000000000000000000000000000'; + const gasLimit = 100000n; + const data = '0x'; + const value = parseEther('0.000001'); + + const gasEstimate = await l1PublicClient.estimateContractGas({ + address: optimismPortalAddress, + abi: optimismPortalAbi, + functionName: 'depositTransaction', + args: [gasLimit, data], + value, + }); + + const { hash: l1TxHash } = await l1WalletClient.writeContract({ + address: optimismPortalAddress, + abi: optimismPortalAbi, + functionName: 'depositTransaction', + args: [gasLimit, data], + value, + gas: gasEstimate * 120n / 100n, // 20% buffer + }); + + console.log(`L1 transaction hash: ${l1TxHash}`); + + const l1Receipt = await l1PublicClient.waitForTransactionReceipt({ hash: l1TxHash }); + + const l2TxHash = l1Receipt.logs[0].topics[1]; + const l2Receipt = await l2PublicClient.waitForTransactionReceipt({ hash: l2TxHash }); + console.log(`L2 transaction hash: ${l2TxHash}`); + + const finalBalance = await l2PublicClient.getBalance({ address }); + console.log(`Final balance: ${formatEther(finalBalance)} ETH`); + + const difference = initialBalance - finalBalance; + console.log(`Difference: ${formatEther(difference)} ETH`); })() From dcdbcaee59fd9b822b015e1d0a89f81e21f036c8 Mon Sep 17 00:00:00 2001 From: Blessing Krofegha Date: Wed, 16 Oct 2024 21:21:36 +0100 Subject: [PATCH 4/6] updated docs --- .../tutorials/send-tx-from-eth.mdx | 26 +++--- public/tutorials/send-tx-from-eth.js | 81 +++++++++++-------- 2 files changed, 60 insertions(+), 47 deletions(-) diff --git a/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx b/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx index 022ebd92d..1e219b140 100644 --- a/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx +++ b/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx @@ -28,8 +28,8 @@ You're going to use the `viem` package for this tutorial. Since Viem is a [Node. {

Make a Project Folder

} ```bash -mkdir op-sample-project -cd op-sample-project +mkdir trigger-transaction +cd trigger-transaction ``` {

Initialize the Project

} @@ -89,7 +89,7 @@ You need to import some dependencies into your Node REPL session. {

Import Viem

} -```js file=/public/tutorials/send-tx-from-eth.js#L3-L5 hash=7a906fc04fa87f91fc33049240e8e0f8 +```js file=/public/tutorials/send-tx-from-eth.js#L3-L6 hash=1e06dede41cb7ba0bd9414a8962521c6 ``` @@ -102,12 +102,12 @@ You'll need a few variables throughout this tutorial. Let's set those up now. {

Load your private key

} -```js file=/public/tutorials/send-tx-from-eth.js#L7-L8 hash=46ba01375a5d8844b2315f0e579dfac3 +```js file=/public/tutorials/send-tx-from-eth.js#L8-L9 hash=46ba01375a5d8844b2315f0e579dfac3 ``` {

Create the RPC providers and wallets

} -```js file=/public/tutorials/send-tx-from-eth.js#L10-L13 hash=a364c906d788d0614588c8db059cfcca +```js file=/public/tutorials/send-tx-from-eth.js#L11-L13 hash=d5a5a1252f4b6ff026cd58de8e6ae7f1 ``` @@ -116,7 +116,7 @@ You'll need a few variables throughout this tutorial. Let's set those up now. You'll be sending a small amount of ETH as part of this tutorial. Quickly check your balance on OP Sepolia so that you know how much you had at the start of the tutorial. -```js file=/public/tutorials/send-tx-from-eth.js#L15-L17 hash=5b95f18440ad72b6200ed7b5df00ca8f +```js file=/public/tutorials/send-tx-from-eth.js#L17-L18 hash=2bbd74b9de0c0fa0daca043ab9030ff0 ``` ## Trigger the Transaction @@ -127,35 +127,35 @@ Now you'll use the `OptimismPortal` contract to trigger a transaction on OP Sepo {

Create the OptimismPortal object

} -```js file=/public/tutorials/send-tx-from-eth.js#L19-L30 hash=bb10ed96a0eed859d491afc1929001ce +```js file=/public/tutorials/send-tx-from-eth.js#L20-L31 hash=b062257111aacc2f3a985542e451269c ``` {

Estimate the required gas

} When sending transactions via the `OptimismPortal` contract it's important to always include a gas buffer. This is because the `OptimismPortal` charges a variable amount of gas depending on the current demand for L2 transactions triggered via L1. If you do not include a gas buffer, your transactions may fail. -```js file=/public/tutorials/send-tx-from-eth.js#L32-L43 hash=ae495cba1a72841059a32edaf20f854d +```js file=/public/tutorials/send-tx-from-eth.js#L33-L45 hash=f5d0d92f161514a3359997143804af0b ``` {

Send the transaction

} Now you'll send the transaction. Note that you are including a buffer of 20% on top of the gas estimate. -```js file=/public/tutorials/send-tx-from-eth.js#L45-L54 hash=6fb0ba06fb29be7ee2c945fca75a50f4 +```js file=/public/tutorials/send-tx-from-eth.js#L50-L61 hash=59e3ee527809087e9e615f28caa49083 ``` {

Wait for the L1 transaction

} First you'll need to wait for the L1 transaction to be mined. -```js file=/public/tutorials/send-tx-from-eth.js#L56 hash=3c0301f8a9ca78bd8bfbff6aef807c77 +```js file=/public/tutorials/send-tx-from-eth.js#L60 hash=0efd9bd3369de7f5f36ea5540a5d8078 ``` {

Wait for the L2 transaction

} Now you'll need to wait for the corresponding L2 transaction to be included in a block. This transaction is automatically created as a result of your L1 transaction. Here you'll determine the hash of the L2 transaction and then wait for that transaction to be included in the L2 blockchain. -```js file=/public/tutorials/send-tx-from-eth.js#L58-L60 hash=cdd456e54b0f8507f96365dae05b8856 +```js file=/public/tutorials/send-tx-from-eth.js#L67-L73 hash=bf903509fb370c2b4e85dbfbf05650ee ``` @@ -164,12 +164,12 @@ Now you'll need to wait for the corresponding L2 transaction to be included in a You should have a little less ETH on OP Sepolia now. Check your balance to confirm. -```js file=/public/tutorials/send-tx-from-eth.js#L62-L63 hash=7cac2670afeb0fcc88346bc59b90466c +```js file=/public/tutorials/send-tx-from-eth.js#L75-L76 hash=dd456528a8bae103b73c5bcd19216916 ``` Make sure that the difference is equal to the amount you were expecting to send. -```js file=/public/tutorials/send-tx-from-eth.js#L65-L66 hash=e2ef73867c6d755ca89b9d3381522208 +```js file=/public/tutorials/send-tx-from-eth.js#L78-L79 hash=3885097e127ff18b3c2c2fc1d3d5a7c0 ``` ## Next Steps diff --git a/public/tutorials/send-tx-from-eth.js b/public/tutorials/send-tx-from-eth.js index c2921b837..12ea74460 100644 --- a/public/tutorials/send-tx-from-eth.js +++ b/public/tutorials/send-tx-from-eth.js @@ -3,6 +3,7 @@ const { createPublicClient, createWalletClient, http, parseEther, formatEther } = require('viem'); const { optimismSepolia, sepolia } = require('viem/chains'); const { privateKeyToAccount } = require('viem/accounts'); + const { publicActionsL2, publicActionsL1, walletActionsL2, walletActionsL1, getL2TransactionHashes } = require ('viem/op-stack') const privateKey = process.env.TUTORIAL_PRIVATE_KEY; const account = privateKeyToAccount(privateKey); @@ -15,54 +16,66 @@ const address = account.address; const initialBalance = await l2PublicClient.getBalance({ address }); console.log(`Initial balance: ${formatEther(initialBalance)} ETH`); - + const optimismPortalAbi = [ - { + { inputs: [ - { internalType: 'uint256', name: '_gasLimit', type: 'uint256' }, - { internalType: 'bytes', name: '_data', type: 'bytes' }, + { internalType: 'uint256', name: '_gasLimit', type: 'uint256' }, + { internalType: 'bytes', name: '_data', type: 'bytes' }, ], name: 'depositTransaction', outputs: [], stateMutability: 'payable', type: 'function', - }, + }, ]; - - const optimismPortalAddress = '0x1000000000000000000000000000000000000000'; + + const optimismPortalAddress = '0x5b47E1A08Ea6d985D6649300584e6722Ec4B1383'; const gasLimit = 100000n; const data = '0x'; - const value = parseEther('0.000001'); + const value = parseEther('0.000069420'); const gasEstimate = await l1PublicClient.estimateContractGas({ - address: optimismPortalAddress, - abi: optimismPortalAbi, - functionName: 'depositTransaction', - args: [gasLimit, data], - value, + address: optimismPortalAddress, + abi: optimismPortalAbi, + functionName: 'depositTransaction', + args: [gasLimit, data], + value, + account: account.address, }); - const { hash: l1TxHash } = await l1WalletClient.writeContract({ - address: optimismPortalAddress, - abi: optimismPortalAbi, - functionName: 'depositTransaction', - args: [gasLimit, data], - value, - gas: gasEstimate * 120n / 100n, // 20% buffer - }); - - console.log(`L1 transaction hash: ${l1TxHash}`); - - const l1Receipt = await l1PublicClient.waitForTransactionReceipt({ hash: l1TxHash }); - - const l2TxHash = l1Receipt.logs[0].topics[1]; - const l2Receipt = await l2PublicClient.waitForTransactionReceipt({ hash: l2TxHash }); - console.log(`L2 transaction hash: ${l2TxHash}`); - - const finalBalance = await l2PublicClient.getBalance({ address }); + console.log(`Gas estimate: ${gasEstimate}`); + + // Step 3: Send the transaction + const { request } = await l1PublicClient.simulateContract({ + account, + address: optimismPortalAddress, + abi: optimismPortalAbi, + functionName: 'depositTransaction', + args: [gasLimit, data], + value, + gas: gasEstimate * 120n / 100n, // 20% buffer + }) + + const l1TxHash = await l1WalletClient.writeContract(request) + console.log(`L1 transaction hash: ${l1TxHash}`) + + // Step 4: Wait for the L1 transaction + const l1Receipt = await l1PublicClient.waitForTransactionReceipt({hash: l1TxHash}) + console.log('L1 transaction confirmed:', l1Receipt) + + const [l2Hash] = getL2TransactionHashes(l1TxHash) + console.log(`Corresponding L2 transaction hash: ${l2Hash}`); + + const l2Receipt = await l2PublicClient.waitForTransactionReceipt({ + hash: l2Hash, + }); + console.log('L2 transaction confirmed:', l2Receipt); + + const finalBalance = await l2Wallet.getBalance() console.log(`Final balance: ${formatEther(finalBalance)} ETH`); - - const difference = initialBalance - finalBalance; - console.log(`Difference: ${formatEther(difference)} ETH`); + + const difference = initialBalance - finalBalance + console.log(`Difference in balance: ${formatEther(difference)} ETH`); })() From d883e5a10146614fe485f87d3836aa24f87e6eeb Mon Sep 17 00:00:00 2001 From: Blessing Krofegha Date: Wed, 30 Oct 2024 12:03:26 +0100 Subject: [PATCH 5/6] fix lint issues --- .../tutorials/send-tx-from-eth.mdx | 112 ++++++++---------- words.txt | 9 ++ 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx b/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx index 1e219b140..9f20aebfc 100644 --- a/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx +++ b/pages/builders/app-developers/tutorials/send-tx-from-eth.mdx @@ -8,7 +8,7 @@ import { Callout, Steps } from 'nextra/components' # Triggering OP Mainnet Transactions from Ethereum using Viem -OP Mainnet currently uses a single-Sequencer block production model. +OP Mainnet currently uses a single-Sequencer block production model. This means that there is only one Sequencer active on the network at any given time. Single-Sequencer models are simpler than their highly decentralized counterparts but they are also more vulnerable to potential downtime. Sequencer downtime must not be able to prevent users from transacting on the network. As a result, OP Mainnet includes a mechanism for "forcing" transactions to be included in the blockchain. This mechanism involves triggering a transaction on OP Mainnet by sending a transaction on Ethereum. @@ -16,39 +16,37 @@ In this tutorial you'll learn how to trigger a transaction on OP Mainnet from Et ## Dependencies -* [node](https://nodejs.org/en/) -* [pnpm](https://pnpm.io/installation) +* [node](https://nodejs.org/en/) +* [pnpm](https://pnpm.io/installation) ## Create a Demo Project You're going to use the `viem` package for this tutorial. Since Viem is a [Node.js](https://nodejs.org/en/) library, you'll need to create a Node.js project to use it. + {

Make a Project Folder

} -{

Make a Project Folder

} + ```bash + mkdir trigger-transaction + cd trigger-transaction + ``` -```bash -mkdir trigger-transaction -cd trigger-transaction -``` - -{

Initialize the Project

} + {

Initialize the Project

} -```bash -pnpm init -``` + ```bash + pnpm init + ``` -{

Install Viem

} - -```bash -pnpm add viem -``` + {

Install Viem

} + ```bash + pnpm add viem + ```
-Want to create a new wallet for this tutorial? -If you have [`cast`](https://book.getfoundry.sh/getting-started/installation) installed you can run `cast wallet new` in your terminal to create a new wallet and get the private key. + Want to create a new wallet for this tutorial? + If you have [`cast`](https://book.getfoundry.sh/getting-started/installation) installed you can run `cast wallet new` in your terminal to create a new wallet and get the private key. ## Get ETH on Sepolia and OP Sepolia @@ -56,14 +54,14 @@ If you have [`cast`](https://book.getfoundry.sh/getting-started/installation) in This tutorial explains how to bridge tokens from Sepolia to OP Sepolia. You will need to get some ETH on both of these testnets. -You can use [this faucet](https://sepoliafaucet.com) to get ETH on Sepolia. -You can use the [Superchain Faucet](https://console.optimism.io/faucet?utm_source=docs) to get ETH on OP Sepolia. + You can use [this faucet](https://sepoliafaucet.com) to get ETH on Sepolia. + You can use the [Superchain Faucet](https://console.optimism.io/faucet?utm_source=docs) to get ETH on OP Sepolia. ## Add a Private Key to Your Environment -You need a private key in order to sign transactions. -Set your private key as an environment variable with the `export` command. +You need a private key in order to sign transactions. +Set your private key as an environment variable with the `export` command. Make sure this private key corresponds to an address that has ETH on both Sepolia and OP Sepolia. ```bash @@ -72,7 +70,7 @@ export TUTORIAL_PRIVATE_KEY=0x... ## Start the Node REPL -You're going to use the Node REPL to interact with Viem. +You're going to use the Node REPL to interact with Viem. To start the Node REPL run the following command in your terminal: ```bash @@ -86,12 +84,10 @@ This will bring up a Node REPL prompt that allows you to run javascript code. You need to import some dependencies into your Node REPL session. + {

Import Viem

} -{

Import Viem

} - -```js file=/public/tutorials/send-tx-from-eth.js#L3-L6 hash=1e06dede41cb7ba0bd9414a8962521c6 -``` - + ```js file=/public/tutorials/send-tx-from-eth.js#L3-L6 hash=1e06dede41cb7ba0bd9414a8962521c6 + ```
## Set Session Variables @@ -99,17 +95,15 @@ You need to import some dependencies into your Node REPL session. You'll need a few variables throughout this tutorial. Let's set those up now. + {

Load your private key

} -{

Load your private key

} + ```js file=/public/tutorials/send-tx-from-eth.js#L8-L9 hash=46ba01375a5d8844b2315f0e579dfac3 + ``` -```js file=/public/tutorials/send-tx-from-eth.js#L8-L9 hash=46ba01375a5d8844b2315f0e579dfac3 -``` - -{

Create the RPC providers and wallets

} - -```js file=/public/tutorials/send-tx-from-eth.js#L11-L13 hash=d5a5a1252f4b6ff026cd58de8e6ae7f1 -``` + {

Create the RPC providers and wallets

} + ```js file=/public/tutorials/send-tx-from-eth.js#L11-L13 hash=d5a5a1252f4b6ff026cd58de8e6ae7f1 + ```
## Check Your Initial Balance @@ -124,40 +118,38 @@ You'll be sending a small amount of ETH as part of this tutorial. Quickly check Now you'll use the `OptimismPortal` contract to trigger a transaction on OP Sepolia by sending a transaction on Sepolia. + {

Create the OptimismPortal object

} -{

Create the OptimismPortal object

} + ```js file=/public/tutorials/send-tx-from-eth.js#L20-L31 hash=b062257111aacc2f3a985542e451269c + ``` -```js file=/public/tutorials/send-tx-from-eth.js#L20-L31 hash=b062257111aacc2f3a985542e451269c -``` + {

Estimate the required gas

} -{

Estimate the required gas

} + When sending transactions via the `OptimismPortal` contract it's important to always include a gas buffer. This is because the `OptimismPortal` charges a variable amount of gas depending on the current demand for L2 transactions triggered via L1. If you do not include a gas buffer, your transactions may fail. -When sending transactions via the `OptimismPortal` contract it's important to always include a gas buffer. This is because the `OptimismPortal` charges a variable amount of gas depending on the current demand for L2 transactions triggered via L1. If you do not include a gas buffer, your transactions may fail. + ```js file=/public/tutorials/send-tx-from-eth.js#L33-L45 hash=f5d0d92f161514a3359997143804af0b + ``` -```js file=/public/tutorials/send-tx-from-eth.js#L33-L45 hash=f5d0d92f161514a3359997143804af0b -``` + {

Send the transaction

} -{

Send the transaction

} + Now you'll send the transaction. Note that you are including a buffer of 20% on top of the gas estimate. -Now you'll send the transaction. Note that you are including a buffer of 20% on top of the gas estimate. + ```js file=/public/tutorials/send-tx-from-eth.js#L50-L61 hash=59e3ee527809087e9e615f28caa49083 + ``` -```js file=/public/tutorials/send-tx-from-eth.js#L50-L61 hash=59e3ee527809087e9e615f28caa49083 -``` - -{

Wait for the L1 transaction

} + {

Wait for the L1 transaction

} -First you'll need to wait for the L1 transaction to be mined. + First you'll need to wait for the L1 transaction to be mined. -```js file=/public/tutorials/send-tx-from-eth.js#L60 hash=0efd9bd3369de7f5f36ea5540a5d8078 -``` + ```js file=/public/tutorials/send-tx-from-eth.js#L60 hash=0efd9bd3369de7f5f36ea5540a5d8078 + ``` -{

Wait for the L2 transaction

} + {

Wait for the L2 transaction

} -Now you'll need to wait for the corresponding L2 transaction to be included in a block. This transaction is automatically created as a result of your L1 transaction. Here you'll determine the hash of the L2 transaction and then wait for that transaction to be included in the L2 blockchain. - -```js file=/public/tutorials/send-tx-from-eth.js#L67-L73 hash=bf903509fb370c2b4e85dbfbf05650ee -``` + Now you'll need to wait for the corresponding L2 transaction to be included in a block. This transaction is automatically created as a result of your L1 transaction. Here you'll determine the hash of the L2 transaction and then wait for that transaction to be included in the L2 blockchain. + ```js file=/public/tutorials/send-tx-from-eth.js#L67-L73 hash=bf903509fb370c2b4e85dbfbf05650ee + ```
## Check Your Updated Balance @@ -174,4 +166,4 @@ Make sure that the difference is equal to the amount you were expecting to send. ## Next Steps -You've successfully triggered a transaction on OP Sepolia by sending a transaction on Sepolia using Viem. Although this tutorial demonstrated the simple example of sending a basic ETH transfer from your L2 address via the OptimismPortal contract, you can use this same technique to trigger any transaction you want. You can trigger smart contracts, send ERC-20 tokens, and more. \ No newline at end of file +You've successfully triggered a transaction on OP Sepolia by sending a transaction on Sepolia using Viem. Although this tutorial demonstrated the simple example of sending a basic ETH transfer from your L2 address via the OptimismPortal contract, you can use this same technique to trigger any transaction you want. You can trigger smart contracts, send ERC-20 tokens, and more. diff --git a/words.txt b/words.txt index 90467007b..142a34158 100644 --- a/words.txt +++ b/words.txt @@ -10,6 +10,7 @@ Allnodes Allocs allocs ANDI +Ankr Apeworx Arweave authrpc @@ -138,6 +139,7 @@ Holesky holesky IGNOREPRICE ignoreprice +Immunefi implicity Inator inator @@ -187,6 +189,7 @@ minsuggestedpriorityfee Mintable Mintplex MIPSEVM +Mitigations Moralis Mordor mountpoint @@ -274,6 +277,8 @@ Protip Proxied proxyd pseudorandomly +Pyth +Pyth's QRNG Quicknode quicknode @@ -304,6 +309,9 @@ RWAs Schnorr secp SELFDESTRUCT +SEPOLIA +Sepolia +sepolia seqnr SEQUENCERHTTP sequencerhttp @@ -366,6 +374,7 @@ VMDEBUG vmdebug VMODULE vmodule +voxel wagmi Warpcast XORI From fcdbea958f27bcc1a000f2d9806418e963bfb1fe Mon Sep 17 00:00:00 2001 From: Blessing Krofegha Date: Wed, 30 Oct 2024 12:06:58 +0100 Subject: [PATCH 6/6] fix merge conflict --- words.txt | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/words.txt b/words.txt index 142a34158..376553b4f 100644 --- a/words.txt +++ b/words.txt @@ -1,5 +1,5 @@ -ACCOUNTQUEUE accountqueue +ACCOUNTQUEUE ACCOUNTSLOTS accountslots ADDI @@ -9,6 +9,7 @@ airgap Allnodes Allocs allocs +altda ANDI Ankr Apeworx @@ -16,6 +17,7 @@ Arweave authrpc Badgeholder's Badgeholders +badgeholders basefee BGEZ BGTZ @@ -27,8 +29,8 @@ BLOBPOOL blobpool blobspace blockhash -blocklists BLOCKLOGS +blocklists blocklogs BLOCKPROFILERATE blockprofilerate @@ -38,7 +40,6 @@ blocktime BLOOMFILTER bloomfilter BLTZ -Bluesweep Bootcamp BOOTNODES Bootnodes @@ -65,6 +66,8 @@ computependingblock confs corsdomain counterfactually +Crosschain +crosschain Crossmint daserver DATACAP @@ -83,6 +86,8 @@ Discv discv DIVU Drand +dripcheck +Drippie Eigen ENABLEDEPRECATEDPERSONAL enabledeprecatedpersonal @@ -96,15 +101,19 @@ ETHSTATS ethstats EVMTIMEOUT evmtimeout +executability +exfiltrate EXITWHENSYNCED exitwhensynced EXTRADATA extradata Farcaster farcaster +Faultproof FDLIMIT fdlimit featureset +Flashbots forkable forkchoice FPVM @@ -164,7 +173,6 @@ leveldb lightkdf logfile logfmt -marketshare MAXAGE maxage MAXBACKUPS @@ -190,6 +198,7 @@ Mintable Mintplex MIPSEVM Mitigations +Monitorism Moralis Mordor mountpoint @@ -199,6 +208,7 @@ MTHI MTLO MULT multiaddr +multichain multiclient multisigs MULTU @@ -230,9 +240,12 @@ nosyncserve Numba Offchain offchain +OPCM +opcm Openfort oplabs opnode's +opstack Opti pausable pcscdpath @@ -252,6 +265,7 @@ POAPs PPROF pprof preconfigured +Predeploy predeploy Predeployed predeployed @@ -291,10 +305,10 @@ rejournal REMOTEDB remotedb replayability -reproven +replayor REQUIREDBLOCKS requiredblocks -Rollouts +rollouts Rollups rollups Routescan @@ -305,13 +319,14 @@ rpcs RPGF Rpgf rpgf +Runbooks +runbooks RWAs +safedb Schnorr secp SELFDESTRUCT -SEPOLIA Sepolia -sepolia seqnr SEQUENCERHTTP sequencerhttp @@ -337,12 +352,15 @@ subcomponents subgame subheaders SUBU +Sunnyside SUPERCHAIN Superchain superchain Superchain's Superchains Superscan +Supersim +supersim SYNCMODE syncmode SYNCTARGET @@ -358,8 +376,10 @@ trustlessly trustrpc txfeecap txmgr +txns TXPOOL txpool +txproxy uncountered Unprotect unsubmitted @@ -377,9 +397,10 @@ vmodule voxel wagmi Warpcast +xlarge XORI xtensibility ZKPs ZKVM Zora -zora +zora \ No newline at end of file