optimism-bridge-snt/index.js

201 lines
6.6 KiB
JavaScript

const contracts = require("./contracts.json");
const ethers = require("ethers")
const optimismSDK = require("@eth-optimism/sdk")
require('dotenv').config()
const l1Url = `https://eth-goerli.g.alchemy.com/v2/${process.env.GOERLI_ALCHEMY_KEY}`
const l2Url = `https://opt-goerli.g.alchemy.com/v2/${process.env.GOERLI_OPT_ALCHEMY_KEY}`
const mnemonic = process.env.GOERLI_MNEMONIC
const words = mnemonic.match(/[a-zA-Z]+/g).length
validLength = [12, 15, 18, 24]
if (!validLength.includes(words)) {
console.log(`The mnemonic (${mnemonic}) is the wrong number of words`)
process.exit(-1)
}
const erc20Addrs = {
l1Addr: contracts.goerli.l1.token,
l2Addr: contracts.goerli.l2.token
}
const faucetAddr = contracts.goerli.l2.controller;
let crossChainMessenger
let l1ERC20, l2ERC20 // OUTb contracts to show ERC-20
let faucet
let ourAddr // The address of the signer we use.
// Get signers on L1 and L2 (for the same address). Note that
// this address needs to have ETH on it, both on Optimism and
// Optimism Georli
const getSigners = async () => {
const l1RpcProvider = new ethers.providers.JsonRpcProvider(l1Url)
const l2RpcProvider = new ethers.providers.JsonRpcProvider(l2Url)
const hdNode = ethers.utils.HDNode.fromMnemonic(mnemonic)
const privateKey = hdNode.derivePath(ethers.utils.defaultPath).privateKey
const l1Wallet = new ethers.Wallet(privateKey, l1RpcProvider)
const l2Wallet = new ethers.Wallet(privateKey, l2RpcProvider)
return [l1Wallet, l2Wallet]
} // getSigners
// The ABI fragment for the contract. We only need to know how to do two things:
// 1. Get an account's balance
// 2. Call the faucet to get more (only works on L1). Of course, production
// ERC-20 tokens tend to be a bit harder to acquire.
const erc20ABI = [
// balanceOf
{
constant: true,
inputs: [{ name: "_owner", type: "address" }],
name: "balanceOf",
outputs: [{ name: "balance", type: "uint256" }],
type: "function",
}
]; // erc20ABI
const faucetABI = [
// faucet
{
inputs: [
{
internalType: "uint256",
name: "_amount",
type: "uint256"
}
],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function"
}
];
const setup = async() => {
const [l1Signer, l2Signer] = await getSigners()
ourAddr = l1Signer.address
crossChainMessenger = new optimismSDK.CrossChainMessenger({
l1ChainId: 5, // Goerli value, 1 for mainnet
l2ChainId: 420, // Goerli value, 10 for mainnet
l1SignerOrProvider: l1Signer,
l2SignerOrProvider: l2Signer,
})
l1ERC20 = new ethers.Contract(erc20Addrs.l1Addr, erc20ABI, l1Signer)
l2ERC20 = new ethers.Contract(erc20Addrs.l2Addr, erc20ABI, l2Signer)
faucet = new ethers.Contract(faucetAddr, faucetABI, l1Signer)
}
const reportERC20Balances = async () => {
const l1Balance = (await l1ERC20.balanceOf(ourAddr)).toString().slice(0,-18)
const l2Balance = (await l2ERC20.balanceOf(ourAddr)).toString().slice(0,-18)
console.log(`OUTb on L1:${l1Balance} OUTb on L2:${l2Balance}`)
if (l1Balance != 0) {
return
}
console.log(`You don't have enough OUTb on L1. Let's call the faucet to fix that`)
const tx = (await faucet.mint("10000000000000000000000"))
console.log(`Faucet tx: ${tx.hash}`)
console.log(`\tMore info: https://goerli.etherscan.io/tx/${tx.hash}`)
await tx.wait()
const newBalance = (await l1ERC20.balanceOf(ourAddr)).toString().slice(0,-18)
console.log(`New L1 OUTb balance: ${newBalance}`)
}
const oneToken = BigInt(1e18)
const depositERC20 = async () => {
console.log("Deposit ERC20")
await reportERC20Balances()
const start = new Date()
// Need the l2 address to know which bridge is responsible
const allowanceResponse = await crossChainMessenger.approveERC20(
erc20Addrs.l1Addr, erc20Addrs.l2Addr, oneToken)
await allowanceResponse.wait()
console.log(`Allowance given by tx ${allowanceResponse.hash}`)
console.log(`\tMore info: https://goerli.etherscan.io/tx/${allowanceResponse.hash}`)
console.log(`Time so far ${(new Date()-start)/1000} seconds`)
const response = await crossChainMessenger.depositERC20(
erc20Addrs.l1Addr, erc20Addrs.l2Addr, oneToken)
console.log(`Deposit transaction hash (on L1): ${response.hash}`)
console.log(`\tMore info: https://goerli.etherscan.io/tx/${response.hash}`)
await response.wait()
console.log("Waiting for status to change to RELAYED")
console.log(`Time so far ${(new Date()-start)/1000} seconds`)
await crossChainMessenger.waitForMessageStatus(response.hash,
optimismSDK.MessageStatus.RELAYED)
await reportERC20Balances()
console.log(`depositERC20 took ${(new Date()-start)/1000} seconds\n\n`)
} // depositERC20()
const withdrawERC20 = async () => {
console.log("Withdraw ERC20")
const start = new Date()
await reportERC20Balances()
const response = await crossChainMessenger.withdrawERC20(
erc20Addrs.l1Addr, erc20Addrs.l2Addr, oneToken)
console.log(`Transaction hash (on L2): ${response.hash}`)
console.log(`\tFor more information: https://goerli-optimism.etherscan.io/tx/${response.hash}`)
await response.wait()
console.log("Waiting for status to be READY_TO_PROVE")
console.log(`Time so far ${(new Date()-start)/1000} seconds`)
await crossChainMessenger.waitForMessageStatus(response.hash,
optimismSDK.MessageStatus.READY_TO_PROVE)
console.log(`Time so far ${(new Date()-start)/1000} seconds`)
await crossChainMessenger.proveMessage(response.hash)
console.log("In the challenge period, waiting for status READY_FOR_RELAY")
console.log(`Time so far ${(new Date()-start)/1000} seconds`)
await crossChainMessenger.waitForMessageStatus(response.hash,
optimismSDK.MessageStatus.READY_FOR_RELAY)
console.log("Ready for relay, finalizing message now")
console.log(`Time so far ${(new Date()-start)/1000} seconds`)
await crossChainMessenger.finalizeMessage(response.hash)
console.log("Waiting for status to change to RELAYED")
console.log(`Time so far ${(new Date()-start)/1000} seconds`)
await crossChainMessenger.waitForMessageStatus(response,
optimismSDK.MessageStatus.RELAYED)
await reportERC20Balances()
console.log(`withdrawERC20 took ${(new Date()-start)/1000} seconds\n\n\n`)
} // withdrawERC20()
const main = async () => {
await setup()
await depositERC20()
await withdrawERC20()
} // main
main().then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})