2023-07-17 16:59:00 +00:00
|
|
|
const contracts = require("./contracts.json");
|
2023-10-06 16:52:40 +00:00
|
|
|
const ethers = require("ethers");
|
|
|
|
const optimismSDK = require("@eth-optimism/sdk");
|
|
|
|
require("dotenv").config();
|
2023-07-17 16:59:00 +00:00
|
|
|
|
2023-10-06 16:52:40 +00:00
|
|
|
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;
|
2023-07-17 16:59:00 +00:00
|
|
|
|
2023-10-06 16:52:40 +00:00
|
|
|
const words = mnemonic.match(/[a-zA-Z]+/g).length;
|
|
|
|
validLength = [12, 15, 18, 24];
|
2023-07-17 16:59:00 +00:00
|
|
|
if (!validLength.includes(words)) {
|
2023-10-06 16:52:40 +00:00
|
|
|
console.log(`The mnemonic (${mnemonic}) is the wrong number of words`);
|
|
|
|
process.exit(-1);
|
2023-07-17 16:59:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const erc20Addrs = {
|
|
|
|
l1Addr: contracts.goerli.l1.token,
|
2023-10-06 16:52:40 +00:00
|
|
|
l2Addr: contracts.goerli.l2.token,
|
|
|
|
};
|
|
|
|
const faucetAddr = contracts.goerli.l2.controller;
|
2023-07-17 16:59:00 +00:00
|
|
|
|
2023-10-06 16:52:40 +00:00
|
|
|
let crossChainMessenger;
|
|
|
|
let l1ERC20, l2ERC20; // OUTb contracts to show ERC-20
|
|
|
|
let faucet;
|
|
|
|
let ourAddr; // The address of the signer we use.
|
2023-07-17 16:59:00 +00:00
|
|
|
|
2023-10-06 16:52:40 +00:00
|
|
|
// Get signers on L1 and L2 (for the same address). Note that
|
2023-07-17 16:59:00 +00:00
|
|
|
// this address needs to have ETH on it, both on Optimism and
|
|
|
|
// Optimism Georli
|
|
|
|
const getSigners = async () => {
|
2023-10-06 16:52:40 +00:00
|
|
|
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);
|
2023-07-17 16:59:00 +00:00
|
|
|
|
2023-10-06 16:52:40 +00:00
|
|
|
return [l1Wallet, l2Wallet];
|
|
|
|
}; // getSigners
|
2023-07-17 16:59:00 +00:00
|
|
|
|
|
|
|
// The ABI fragment for the contract. We only need to know how to do two things:
|
|
|
|
// 1. Get an account's balance
|
2023-10-06 16:52:40 +00:00
|
|
|
// 2. Call the faucet to get more (only works on L1). Of course, production
|
2023-07-17 16:59:00 +00:00
|
|
|
// 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",
|
2023-10-06 16:52:40 +00:00
|
|
|
},
|
|
|
|
]; // erc20ABI
|
2023-07-17 16:59:00 +00:00
|
|
|
const faucetABI = [
|
2023-10-06 16:52:40 +00:00
|
|
|
// faucet
|
|
|
|
{
|
|
|
|
inputs: [
|
|
|
|
{
|
|
|
|
internalType: "uint256",
|
|
|
|
name: "_amount",
|
|
|
|
type: "uint256",
|
|
|
|
},
|
|
|
|
],
|
|
|
|
name: "mint",
|
|
|
|
outputs: [],
|
|
|
|
stateMutability: "nonpayable",
|
|
|
|
type: "function",
|
|
|
|
},
|
2023-07-17 16:59:00 +00:00
|
|
|
];
|
|
|
|
|
2023-10-06 16:52:40 +00:00
|
|
|
const setup = async () => {
|
|
|
|
const [l1Signer, l2Signer] = await getSigners();
|
|
|
|
ourAddr = l1Signer.address;
|
2023-07-17 16:59:00 +00:00
|
|
|
crossChainMessenger = new optimismSDK.CrossChainMessenger({
|
2023-10-06 16:52:40 +00:00
|
|
|
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);
|
|
|
|
};
|
2023-07-17 16:59:00 +00:00
|
|
|
|
|
|
|
const reportERC20Balances = async () => {
|
2023-10-06 16:52:40 +00:00
|
|
|
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}`);
|
2023-07-17 16:59:00 +00:00
|
|
|
|
|
|
|
if (l1Balance != 0) {
|
2023-10-06 16:52:40 +00:00
|
|
|
return;
|
2023-07-17 16:59:00 +00:00
|
|
|
}
|
|
|
|
|
2023-10-06 16:52:40 +00:00
|
|
|
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}`);
|
|
|
|
};
|
2023-07-17 16:59:00 +00:00
|
|
|
|
2023-10-06 16:52:40 +00:00
|
|
|
const oneToken = BigInt(1e18);
|
2023-07-17 16:59:00 +00:00
|
|
|
|
|
|
|
const depositERC20 = async () => {
|
2023-10-06 16:52:40 +00:00
|
|
|
console.log("Deposit ERC20");
|
|
|
|
await reportERC20Balances();
|
|
|
|
const start = new Date();
|
2023-07-17 16:59:00 +00:00
|
|
|
|
|
|
|
// Need the l2 address to know which bridge is responsible
|
2023-10-06 16:52:40 +00:00
|
|
|
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()
|
2023-07-17 16:59:00 +00:00
|
|
|
|
|
|
|
const withdrawERC20 = async () => {
|
2023-10-06 16:52:40 +00:00
|
|
|
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()
|
2023-07-17 16:59:00 +00:00
|
|
|
|
|
|
|
const main = async () => {
|
2023-10-06 16:52:40 +00:00
|
|
|
await setup();
|
|
|
|
await depositERC20();
|
|
|
|
await withdrawERC20();
|
|
|
|
}; // main
|
2023-07-17 16:59:00 +00:00
|
|
|
|
2023-10-06 16:52:40 +00:00
|
|
|
main()
|
|
|
|
.then(() => process.exit(0))
|
2023-07-17 16:59:00 +00:00
|
|
|
.catch((error) => {
|
2023-10-06 16:52:40 +00:00
|
|
|
console.error(error);
|
|
|
|
process.exit(1);
|
|
|
|
});
|