201 lines
6.6 KiB
JavaScript
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)
|
|
})
|