Builders
Chain Operators
Tutorials
Using the OP Stack Client SDK

Using the OP Stack Client SDK

This tutorial explains how to use the OP Stack Client SDK when working with native and non-native supported chains.

Before You Begin

To configure the CrossDomainMessenger, you'll first need to locate the L1 contract addresses and specify the zero address for unused SDK contracts.

L1 contract addresses

If you followed the directions in Getting Started, the contract addresses are in .../optimism/packages/contracts-bedrock/deployments, which you created when you deployed the L1 contracts.

Contract name when creating CrossDomainMessengerFile with address
AddressManagerLib_AddressManager.json
L1CrossDomainMessengerProxy__OVM_L1CrossDomainMessenger.json
L1StandardBridgeProxy__OVM_L1StandardBridge.json
OptimismPortalOptimismPortalProxy.json
L2OutputOracleL2OutputOracleProxy.json

SDK contract addresses

Some contracts are required by the SDK as a sanity check, but are not actually used. For these contracts you can just specify the zero address:

  • StateCommitmentChain
  • CanonicalTransactionChain
  • BondManager

In JavaScript you can create the zero address using the expression "0x".padEnd(42, "0").

Create the CrossChainMessenger Object

These directions assume you are inside the Hardhat console (opens in a new tab). They further assume that your project already includes the Optimism SDK @eth-optimism/sdk (opens in a new tab).

Import the SDK

optimismSDK = require("@eth-optimism/sdk")

Set the configuration parameters

Variable nameValue
l1UrlURL to an RPC provider for L1, for example https://eth-goerli.g.alchemy.com/v2/<api key>
l2UrlURL to your OP Stack. If running on the same computer, it is http://localhost:8545
privKeyThe private key for an account that has some ETH on the L1

Create the providers (opens in a new tab) and signers (opens in a new tab)

l1Provider = new ethers.providers.JsonRpcProvider(l1Url)
l2Provider = new ethers.providers.JsonRpcProvider(l2Url)
l1Signer = new ethers.Wallet(privKey).connect(l1Provider)
l2Signer = new ethers.Wallet(privKey).connect(l2Provider)

Create the L1 contracts structure

zeroAddr = "0x".padEnd(42, "0")
l1Contracts = {
   StateCommitmentChain: zeroAddr,
   CanonicalTransactionChain: zeroAddr,
   BondManager: zeroAddr,
   // These contracts have the addresses you found out earlier.
   AddressManager: "0x....",   // Lib_AddressManager.json
   L1CrossDomainMessenger: "0x....",   // Proxy__OVM_L1CrossDomainMessenger.json  
   L1StandardBridge: "0x....",   // Proxy__OVM_L1StandardBridge.json
   OptimismPortal: "0x....",   // OptimismPortalProxy.json
   L2OutputOracle: "0x....",   // L2OutputOracleProxy.json
}                       

Create the data structure for the standard bridge

 bridges = { 
   Standard: { 
      l1Bridge: l1Contracts.L1StandardBridge, 
      l2Bridge: "0x4200000000000000000000000000000000000010", 
      Adapter: optimismSDK.StandardBridgeAdapter
   },
   ETH: {
      l1Bridge: l1Contracts.L1StandardBridge, 
      l2Bridge: "0x4200000000000000000000000000000000000010", 
      Adapter: optimismSDK.ETHBridgeAdapter
   }
}

Create the CrossChainMessenger (opens in a new tab) object

crossChainMessenger = new optimismSDK.CrossChainMessenger({
   bedrock: true,
   contracts: {
      l1: l1Contracts
   },
   bridges: bridges,
   l1ChainId: await l1Signer.getChainId(),
   l2ChainId: await l2Signer.getChainId(),
   l1SignerOrProvider: l1Signer,
   l2SignerOrProvider: l2Signer,    
})

Verify SDK Functionality

To verify the SDK's functionality, transfer some ETH from L1 to L2.

Get the current balances

balances0 = [
   await l1Provider.getBalance(l1Signer.address),
   await l2Provider.getBalance(l1Signer.address)
]

Transfer 1 gwei

tx = await crossChainMessenger.depositETH(1e9)
rcpt = await tx.wait()

Get the balances after the transfer

balances1 = [
   await l1Provider.getBalance(l1Signer.address),
   await l2Provider.getBalance(l1Signer.address)
]

See that the L1 balance changed

It probably changed by a lot more than 1 gwei because of the cost of the transaction.

(balances0[0]-balances1[0])/1e9

See that the L2 balance changed

This process might take a few minutes.

((await l2Provider.getBalance(l1Signer.address))-balances0[1])/1e9

That's it! You're all set! 🎉