Skip to content

Commit 3f140c7

Browse files
authored
Merge pull request #128 from OffchainLabs/update-tutorials-4
Update tutorials to ArbSDK v4 (4)
2 parents fc2d2df + 8655118 commit 3f140c7

26 files changed

Lines changed: 491 additions & 447 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ yarn install
3232

3333
- 🤝 [Greeter](./packages/greeter/) (parent to child messages)
3434
- 📤 [Outbox](./packages/outbox-execute/) (child to parent messages)
35-
-[L1 Confirmation Checker](./packages/l1-confirmation-checker/)
35+
-[Parent chain confirmation checker](./packages/parent-chain-confirmation-checker/)
3636
-[L2 block verification in assertion](./packages/l2-block-verification-in-assertion/)
3737

3838
#### :white_check_mark: Advanced features
@@ -42,6 +42,7 @@ yarn install
4242
- 🌉 [Bridging a custom token through a custom gateway](./packages/custom-gateway-bridging/)
4343
- ✈️ [Send a signed transaction from the parent chain](./packages/delayedInbox-l2msg/)
4444
- 🎁 [Redeem Retryable Ticket](./packages/redeem-failed-retryable/)
45+
- 🧮 [Gas estimation](./packages/gas-estimation/)
4546
- 🌀 [Deposit Ether or Tokens from L1 to L3](./packages/l1-l3-teleport/)
4647

4748
## How to run the tutorials against a custom network
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
# Hosted Aggregator Node (JSON-RPC Endpoint). This is Arbitrum Sepolia Testnet, can use any Arbitrum chain
1+
# This is a sample .env file for use in local development.
2+
# Duplicate this file as .env here
23

3-
L2RPC="https://sepolia-rollup.arbitrum.io/rpc"
4+
# The main chain's RPC
5+
# (this can be an Arbitrum network, or your Orbit chain)
6+
CHAIN_RPC="https://sepolia-rollup.arbitrum.io/rpc"

packages/gas-estimation/README.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,31 @@
22

33
`gas-estimation` is a simple demo of how a developer can estimate transaction fees on Arbitrum.
44

5-
It uses the formula described in this Medium article to estimate the fees to be paid on a transaction, also estimating each component of the formula sepparately: [Understanding Arbitrum: 2-Dimensional Fees](https://medium.com/offchainlabs/understanding-arbitrum-2-dimensional-fees-fd1d582596c9).
5+
It uses the formula described in this Medium article to estimate the fees to be paid on a transaction, also estimating each component of the formula sepparately: [Understanding Arbitrum: 2-Dimensional Fees](https://medium.com/offchainlabs/understanding-arbitrum-2-dimensional-fees-fd1d582596c9). For more information, you can also see [How to estimate gas](https://docs.arbitrum.io/build-decentralized-apps/how-to-estimate-gas) in the Arbitrum documentation portal.
66

77
See [./exec.ts](./scripts/exec.ts) for inline explanations.
88

9-
Inside the script, you can edit `txData` constant to suit your needs.
10-
11-
To run:
12-
13-
```
14-
yarn run exec
15-
```
16-
17-
## Config Environment Variables
9+
## Set environment variables
1810

1911
Set the values shown in `.env-sample` as environmental variables. To copy it into a `.env` file:
2012

2113
```bash
2214
cp .env-sample .env
2315
```
2416

25-
(you'll still need to edit some variables, i.e., `L2RPC`)
17+
You'll still need to edit some variables, i.e., `CHAIN_RPC`.
18+
19+
Note that you can also set the environment variables in an `.env` file in the root of the monorepo, which will be available in all tutorials.
20+
21+
## Run
22+
23+
Inside the script, you can edit the `txData` constant to suit your needs.
24+
25+
To run:
26+
27+
```
28+
yarn run exec
29+
```
2630

2731
<p align="left">
2832
<img width="350" height="150" src= "../../assets/logo.svg" />
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
{
22
"name": "gas-estimation",
3+
"license": "Apache-2.0",
34
"version": "1.0.0",
4-
"description": "",
55
"scripts": {
66
"exec": "ts-node scripts/exec.ts"
77
},
88
"dependencies": {
9-
"@arbitrum/sdk": "^v3.1.9",
10-
"ts-node": "^10.8.1",
11-
"typescript": "^4.7.3"
12-
},
13-
"author": "",
14-
"license": "ISC"
9+
"@arbitrum/sdk": "^v4.0.1",
10+
"ts-node": "^10.9.2",
11+
"typescript": "^4.9.5"
12+
}
1513
}

packages/gas-estimation/scripts/exec.ts

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import { utils, providers } from "ethers";
2-
import { addDefaultLocalNetwork } from "@arbitrum/sdk";
32
import { NodeInterface__factory } from "@arbitrum/sdk/dist/lib/abi/factories/NodeInterface__factory";
43
import { NODE_INTERFACE_ADDRESS } from "@arbitrum/sdk/dist/lib/dataEntities/constants";
5-
const { requireEnvVariables } = require('arb-shared-dependencies');
4+
const { requireEnvVariables, addCustomNetworkFromFile } = require('arb-shared-dependencies');
65

76
// Importing configuration //
87
require('dotenv').config();
9-
requireEnvVariables(['L2RPC']);
8+
requireEnvVariables(['CHAIN_RPC']);
109

1110
// Initial setup //
12-
const baseL2Provider = new providers.StaticJsonRpcProvider(process.env.L2RPC);
11+
const provider = new providers.StaticJsonRpcProvider(process.env.CHAIN_RPC);
1312

1413
///////////////////////////////////////////
1514
// Values of the transaction to estimate //
@@ -29,6 +28,9 @@ const gasEstimator = async () => {
2928
// * Gas formula explanation *
3029
// ***************************
3130
//
31+
// NOTE: In this explanation, L1 and L2 terms are used to represent the Layer-1 and Layer-2 components.
32+
// For L3 Orbit chains, L1 should be viewed as the parent chain (Layer 2), and L2 as the orbit chain (L3)
33+
//
3234
// Transaction fees (TXFEES) = L2 Gas Price (P) * Gas Limit (G)
3335
// ----> Gas Limit (G) = L2 Gas used (L2G) + Extra Buffer for L1 cost (B)
3436
// ----> L1 Estimated Cost (L1C) = L1 estimated calldata price per byte (L1P) * L1 Calldata size in bytes (L1S)
@@ -45,13 +47,13 @@ const gasEstimator = async () => {
4547
// NodeInterface.GasEstimateComponents() and get the third element => result[2]
4648
// L2G (L2 Gas used) => Will depend on the transaction itself
4749
// L1P (L1 estimated calldata price per byte) =>
48-
// (this is the L2's estimated view of the current L1's price per byte of data, which the L2 dynamically adjusts over time)
50+
// (this is the child-chain's estimated view of the current parent-chain's price per byte of data, which the child-chain dynamically adjusts over time)
4951
// ArbGasInfo.getL1BaseFeeEstimate() and multiply by 16
5052
// ArbGasInfo.getL1GasPriceEstimate() and multiply by 16
5153
// ArbGasInfo.getPricesInWei() and get the second element => result[1]
5254
// NodeInterface.GasEstimateL1Component() and get the third element and multiply by 16 => result[2]*16
5355
// NodeInterface.GasEstimateComponents() and get the fourth element and multiply by 16 => result[3]*16
54-
// L1S (Size in bytes of the calldata to post on L1) =>
56+
// L1S (Size in bytes of the calldata to post on the parent chain) =>
5557
// Will depend on the size (in bytes) of the calldata of the transaction
5658
// We add a fixed amount of 140 bytes to that amount for the transaction metadata (recipient, nonce, gas price, ...)
5759
// Final size will be less after compression, but this calculation gives a good estimation
@@ -64,14 +66,13 @@ const gasEstimator = async () => {
6466
// NodeInterface.GasEstimateComponents() and get the second element => result[1]
6567
//
6668

67-
// Add the default local network configuration to the SDK
68-
// to allow this script to run on a local node
69-
addDefaultLocalNetwork()
69+
// dd the custom network configuration to the SDK if present
70+
addCustomNetworkFromFile()
7071

7172
// Instantiation of the NodeInterface object
7273
const nodeInterface = NodeInterface__factory.connect(
7374
NODE_INTERFACE_ADDRESS,
74-
baseL2Provider
75+
provider
7576
);
7677

7778
// Getting the estimations from NodeInterface.GasEstimateComponents()
@@ -86,26 +87,26 @@ const gasEstimator = async () => {
8687
);
8788

8889
// Getting useful values for calculating the formula
89-
const l1GasEstimated = gasEstimateComponents.gasEstimateForL1;
90-
const l2GasUsed = gasEstimateComponents.gasEstimate.sub(gasEstimateComponents.gasEstimateForL1);
91-
const l2EstimatedPrice = gasEstimateComponents.baseFee;
92-
const l1EstimatedPrice = gasEstimateComponents.l1BaseFeeEstimate.mul(16);
90+
const parentChainGasEstimated = gasEstimateComponents.gasEstimateForL1;
91+
const childChainGasUsed = gasEstimateComponents.gasEstimate.sub(gasEstimateComponents.gasEstimateForL1);
92+
const childChainEstimatedPrice = gasEstimateComponents.baseFee;
93+
const parentChainEstimatedPrice = gasEstimateComponents.l1BaseFeeEstimate.mul(16);
9394

9495

9596
// Calculating some extra values to be able to apply all variables of the formula
9697
// -------------------------------------------------------------------------------
97-
// NOTE: This one might be a bit confusing, but l1GasEstimated (B in the formula) is calculated based on l2 gas fees
98-
const l1Cost = l1GasEstimated.mul(l2EstimatedPrice);
98+
// NOTE: This one might be a bit confusing, but parentChainGasEstimated (B in the formula) is calculated based on child-chain's gas fees
99+
const parentChainCost = parentChainGasEstimated.mul(childChainEstimatedPrice);
99100
// NOTE: This is similar to 140 + utils.hexDataLength(txData);
100-
const l1Size = l1Cost.div(l1EstimatedPrice);
101+
const parentChainSize = parentChainCost.div(parentChainEstimatedPrice);
101102

102103
// Getting the result of the formula
103104
// ---------------------------------
104105
// Setting the basic variables of the formula
105-
const P = l2EstimatedPrice;
106-
const L2G = l2GasUsed;
107-
const L1P = l1EstimatedPrice;
108-
const L1S = l1Size;
106+
const P = childChainEstimatedPrice;
107+
const L2G = childChainGasUsed;
108+
const L1P = parentChainEstimatedPrice;
109+
const L1S = parentChainSize;
109110

110111
// L1C (L1 Cost) = L1P * L1S
111112
const L1C = L1P.mul(L1S);
@@ -122,12 +123,12 @@ const gasEstimator = async () => {
122123
console.log("Gas estimation components");
123124
console.log("-------------------");
124125
console.log(`Full gas estimation = ${gasEstimateComponents.gasEstimate.toNumber()} units`);
125-
console.log(`L2 Gas (L2G) = ${L2G.toNumber()} units`);
126-
console.log(`L1 estimated Gas (L1G) = ${l1GasEstimated.toNumber()} units`);
126+
console.log(`Child chain Gas (L2G) = ${L2G.toNumber()} units`);
127+
console.log(`Parent chain estimated Gas (L1G) = ${parentChainGasEstimated.toNumber()} units`);
127128

128-
console.log(`P (L2 Gas Price) = ${utils.formatUnits(P, "gwei")} gwei`);
129-
console.log(`L1P (L1 estimated calldata price per byte) = ${utils.formatUnits(L1P, "gwei")} gwei`);
130-
console.log(`L1S (L1 Calldata size in bytes) = ${L1S} bytes`);
129+
console.log(`P (Child chain gas price) = ${utils.formatUnits(P, "gwei")} gwei`);
130+
console.log(`L1P (Parent chain estimated calldata price per byte) = ${utils.formatUnits(L1P, "gwei")} gwei`);
131+
console.log(`L1S (Parent chain calldata size in bytes) = ${L1S} bytes`);
131132

132133
console.log("-------------------");
133134
console.log(`Transaction estimated fees to pay = ${utils.formatEther(TXFEES)} ETH`);

packages/greeter/.env-sample

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
# This is a sample .env file for use in local development.
2-
32
# Duplicate this file as .env here
43

5-
# Your Private key
6-
7-
DEVNET_PRIVKEY="0x your key here"
8-
9-
# Hosted Aggregator Node (JSON-RPC Endpoint). This is Arbitrum Sepolia Testnet, can use any Arbitrum chain
10-
11-
L2RPC="https://sepolia-rollup.arbitrum.io/rpc"
4+
# Your private key
5+
PRIVATE_KEY="0x your key here"
126

13-
# Ethereum RPC; i.e., for Sepolia https://sepolia.infura.io/v3/<your infura key>
7+
# The main chain's RPC
8+
# (this can be an Arbitrum network, or your Orbit chain)
9+
CHAIN_RPC="https://sepolia-rollup.arbitrum.io/rpc"
1410

15-
L1RPC=""
11+
# The parent chain's RPC
12+
# (this can be Ethereum, or the chain your Orbit chain settles to)
13+
PARENT_CHAIN_RPC="https://sepolia.infura.io/v3/<your infura key>"

packages/greeter/.gitignore

Lines changed: 0 additions & 4 deletions
This file was deleted.

packages/greeter/README.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
1-
# Greeter Tutorial
1+
# Greeter tutorial
22

3-
`greeter` is a simple demo of Arbitrum's L1-to-L2 message passing system (aka "retryable tickets").
3+
`greeter` is a simple demo of Arbitrum's Parent-to-child message passing system (aka "L1-to-L2" or "retryable tickets").
44

5-
It deploys 2 contracts - one to L1, and another to L2, and has the L1 contract send a message to the L2 contract to be executed automatically.
5+
It deploys 2 contracts - one to the parent chain, and another to the child chain, and has the parent chain contract send a message to the child chain contract to be executed automatically.
66

7-
The script and contracts demonstrate how to interact with Arbitrum's core bridge contracts to create these retryable messages, how to calculate and forward appropriate fees from L1 to L2, and how to use Arbitrum's L1-to-L2 message [address aliasing](https://developer.offchainlabs.com/docs/l1_l2_messages#address-aliasing).
7+
The script and contracts demonstrate how to interact with Arbitrum's core bridge contracts to create these retryable messages, how to calculate and forward appropriate fees from parent to child, and how to use Arbitrum's Parent-to-child message [address aliasing](https://docs.arbitrum.io/how-arbitrum-works/arbos/l1-l2-messaging#address-aliasing).
88

99
See [./exec.js](./scripts/exec.js) for inline explanation.
1010

11-
[Click here](https://developer.offchainlabs.com/docs/l1_l2_messages) for more info on retryable tickets.
11+
[Click here](https://docs.arbitrum.io/how-arbitrum-works/arbos/l1-l2-messaging) for more info on retryable tickets.
1212

13-
### Run Demo:
14-
15-
```
16-
yarn run greeter
17-
```
18-
19-
## Config Environment Variables
13+
## Set environment variables
2014

2115
Set the values shown in `.env-sample` as environmental variables. To copy it into a `.env` file:
2216

2317
```bash
2418
cp .env-sample .env
2519
```
2620

27-
(you'll still need to edit some variables, i.e., `DEVNET_PRIVKEY`)
21+
You'll still need to edit some variables, i.e., `PRIVATE_KEY`, `CHAIN_RPC` and `PARENT_CHAIN_RPC`.
22+
23+
Note that you can also set the environment variables in an `.env` file in the root of the monorepo, which will be available in all tutorials.
24+
25+
## Run
26+
27+
To run:
28+
29+
```
30+
yarn run greeter
31+
```
2832

2933
<p align="left">
3034
<img width="350" height="150" src= "../../assets/logo.svg" />

packages/greeter/contracts/Greeter.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: Apache-2.0
2-
pragma solidity >=0.6.11;
2+
pragma solidity ^0.8.0;
33

44
contract Greeter {
55
string greeting;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import "@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol";
5+
import "@arbitrum/nitro-contracts/src/libraries/AddressAliasHelper.sol";
6+
import "../Greeter.sol";
7+
8+
contract GreeterChild is Greeter {
9+
ArbSys constant arbsys = ArbSys(address(100));
10+
address public parentTarget;
11+
12+
event ChildToParentTxCreated(uint256 indexed withdrawalId);
13+
14+
constructor(string memory _greeting, address _parentTarget) Greeter(_greeting) {
15+
parentTarget = _parentTarget;
16+
}
17+
18+
function updateParentTarget(address _parentTarget) public {
19+
parentTarget = _parentTarget;
20+
}
21+
22+
function setGreetingInParent(string memory _greeting) public returns (uint256) {
23+
bytes memory data = abi.encodeWithSelector(Greeter.setGreeting.selector, _greeting);
24+
25+
uint256 withdrawalId = arbsys.sendTxToL1(parentTarget, data);
26+
27+
emit ChildToParentTxCreated(withdrawalId);
28+
return withdrawalId;
29+
}
30+
31+
/// @notice only parentTarget can update greeting
32+
function setGreeting(string memory _greeting) public override {
33+
// To check that message came from the parent chain,
34+
// we check that the sender is the parent chain contract's alias.
35+
require(
36+
msg.sender == AddressAliasHelper.applyL1ToL2Alias(parentTarget),
37+
"Greeting only updateable by parent chain's address"
38+
);
39+
Greeter.setGreeting(_greeting);
40+
}
41+
}

0 commit comments

Comments
 (0)