Skip to content

Commit

Permalink
feat(AlephZero): Add manual withdrawal script and automate finalizati…
Browse files Browse the repository at this point in the history
…ons (#1909)

* feat(AlephZero): Add manual withdrawal script and automate finalizations

Similar to #1866 for OpStack but for Arbitrum Orbit.

Replaces original PR #1898 with smaller commit history. I essentially took the core changes and copied and pasted here, to avoid rebase hell

* WIP

* WIP

* wip

* Update ContractAddresses.ts

* Update arbStack.ts

* Update arbStack.ts

* Update arbStack.ts

* fix
  • Loading branch information
nicholaspai authored Nov 21, 2024
1 parent ff30e83 commit e4f5e39
Show file tree
Hide file tree
Showing 8 changed files with 489 additions and 34 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@across-protocol/constants": "^3.1.19",
"@across-protocol/contracts": "^3.0.16",
"@across-protocol/sdk": "^3.2.16",
"@arbitrum/sdk": "^3.1.3",
"@arbitrum/sdk": "^4.0.2",
"@consensys/linea-sdk": "^0.2.1",
"@defi-wonderland/smock": "^2.3.5",
"@eth-optimism/sdk": "^3.3.2",
Expand Down
117 changes: 117 additions & 0 deletions scripts/withdrawFromArbitrumOrbit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Submits a bridge from Arbitrum Orbit L2 to L1.
// For now, this script only supports WETH withdrawals on AlephZero.

import {
ethers,
retrieveSignerFromCLIArgs,
getProvider,
ERC20,
TOKEN_SYMBOLS_MAP,
assert,
getL1TokenInfo,
Contract,
fromWei,
blockExplorerLink,
getNativeTokenSymbol,
} from "../src/utils";
import { CONTRACT_ADDRESSES } from "../src/common";
import { askYesNoQuestion } from "./utils";

import minimist from "minimist";

const cliArgs = ["amount", "chainId", "token"];
const args = minimist(process.argv.slice(2), {
string: cliArgs,
});

// Example run:
// ts-node ./scripts/withdrawFromArbitrumOrbit.ts
// \ --amount 3000000000000000000
// \ --chainId 41455
// \ --token WETH
// \ --wallet gckms
// \ --keys bot1

export async function run(): Promise<void> {
assert(
cliArgs.every((cliArg) => Object.keys(args).includes(cliArg)),
`Missing cliArg, expected: ${cliArgs}`
);
const baseSigner = await retrieveSignerFromCLIArgs();
const signerAddr = await baseSigner.getAddress();
const chainId = parseInt(args.chainId);
const connectedSigner = baseSigner.connect(await getProvider(chainId));
const l2Token = TOKEN_SYMBOLS_MAP[args.token]?.addresses[chainId];
assert(l2Token, `${args.token} not found on chain ${chainId} in TOKEN_SYMBOLS_MAP`);
const l1TokenInfo = getL1TokenInfo(l2Token, chainId);
console.log("Fetched L1 token info:", l1TokenInfo);
const amount = args.amount;
const amountFromWei = ethers.utils.formatUnits(amount, l1TokenInfo.decimals);
console.log(`Amount to bridge from chain ${chainId}: ${amountFromWei} ${l2Token}`);

const erc20 = new Contract(l2Token, ERC20.abi, connectedSigner);
const currentBalance = await erc20.balanceOf(signerAddr);
const nativeTokenSymbol = getNativeTokenSymbol(chainId);
const currentNativeBalance = await connectedSigner.getBalance();
console.log(
`Current ${l1TokenInfo.symbol} balance for account ${signerAddr}: ${fromWei(
currentBalance,
l1TokenInfo.decimals
)} ${l2Token}`
);
console.log(
`Current native ${nativeTokenSymbol} token balance for account ${signerAddr}: ${fromWei(currentNativeBalance, 18)}`
);

// Now, submit a withdrawal:
let contract: Contract, functionName: string, functionArgs: any[];
if (l1TokenInfo.symbol !== nativeTokenSymbol) {
const arbErc20GatewayObj = CONTRACT_ADDRESSES[chainId].erc20Gateway;
contract = new Contract(arbErc20GatewayObj.address, arbErc20GatewayObj.abi, connectedSigner);
functionName = "outboundTransfer";
functionArgs = [
l1TokenInfo.address, // l1Token
signerAddr, // to
amount, // amount
"0x", // data
];

console.log(
`Submitting ${functionName} on the Arbitrum ERC20 gateway router @ ${contract.address} with the following args: `,
...functionArgs
);
} else {
const arbSys = CONTRACT_ADDRESSES[chainId].arbSys;
contract = new Contract(arbSys.address, arbSys.abi, connectedSigner);
functionName = "withdrawEth";
functionArgs = [
signerAddr, // to
{ value: amount },
];
console.log(
`Submitting ${functionName} on the ArbSys contract @ ${contract.address} with the following args: `,
...functionArgs
);
}

if (!(await askYesNoQuestion("\nDo you want to proceed?"))) {
return;
}
const withdrawal = await contract[functionName](...functionArgs);
console.log(`Submitted withdrawal: ${blockExplorerLink(withdrawal.hash, chainId)}.`);
const receipt = await withdrawal.wait();
console.log("Receipt", receipt);
}

if (require.main === module) {
run()
.then(async () => {
// eslint-disable-next-line no-process-exit
process.exit(0);
})
.catch(async (error) => {
console.error("Process exited with", error);
// eslint-disable-next-line no-process-exit
process.exit(1);
});
}
2 changes: 1 addition & 1 deletion scripts/withdrawFromOpStack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export async function run(): Promise<void> {
l1TokenInfo.decimals
)} ${l2Token}`
);
console.log(`Current ETH balance for account ${signerAddr}: ${fromWei(currentEthBalance, l1TokenInfo.decimals)}`);
console.log(`Current ETH balance for account ${signerAddr}: ${fromWei(currentEthBalance)}`);

// First offer user option to unwrap WETH into ETH
if (l1TokenInfo.symbol === "ETH") {
Expand Down
10 changes: 10 additions & 0 deletions src/common/ContractAddresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import ARBITRUM_ERC20_GATEWAY_ROUTER_L1_ABI from "./abi/ArbitrumErc20GatewayRout
import ARBITRUM_ERC20_GATEWAY_L1_ABI from "./abi/ArbitrumErc20GatewayL1.json";
import ARBITRUM_ERC20_GATEWAY_L2_ABI from "./abi/ArbitrumErc20GatewayL2.json";
import ARBITRUM_OUTBOX_ABI from "./abi/ArbitrumOutbox.json";
import ARBSYS_L2_ABI from "./abi/ArbSysL2.json";
import LINEA_MESSAGE_SERVICE_ABI from "./abi/LineaMessageService.json";
import LINEA_TOKEN_BRIDGE_ABI from "./abi/LineaTokenBridge.json";
import LINEA_USDC_BRIDGE_ABI from "./abi/LineaUsdcBridge.json";
Expand Down Expand Up @@ -132,6 +133,10 @@ export const CONTRACT_ADDRESSES: {
address: "0x0B9857ae2D4A3DBe74ffE1d7DF045bb7F96E4840",
abi: ARBITRUM_OUTBOX_ABI,
},
orbitOutbox_41455: {
address: "0x73bb50c32a3BD6A1032aa5cFeA048fBDA3D6aF6e",
abi: ARBITRUM_OUTBOX_ABI,
},
orbitErc20GatewayRouter_42161: {
address: "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef",
abi: ARBITRUM_ERC20_GATEWAY_ROUTER_L1_ABI,
Expand Down Expand Up @@ -334,8 +339,13 @@ export const CONTRACT_ADDRESSES: {
},
41455: {
erc20Gateway: {
address: "0x2A5a79061b723BBF453ef7E07c583C750AFb9BD6",
abi: ARBITRUM_ERC20_GATEWAY_L2_ABI,
},
arbSys: {
address: "0x0000000000000000000000000000000000000064",
abi: ARBSYS_L2_ABI,
},
},
59144: {
l2MessageService: {
Expand Down
82 changes: 82 additions & 0 deletions src/common/abi/ArbSysL2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
[
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "caller",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "destination",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "hash",
"type": "uint256"
},
{
"indexed": true,
"internalType": "uint256",
"name": "position",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "arbBlockNum",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "ethBlockNum",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "callvalue",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "L2ToL1Tx",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "destination",
"type": "address"
}
],
"name": "withdrawEth",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
}
]
55 changes: 55 additions & 0 deletions src/common/abi/ArbitrumErc20GatewayL2.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,60 @@
],
"name": "DepositFinalized",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "l1Token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "_from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "_l2ToL1Id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "_exitNum",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "WithdrawalInitiated",
"type": "event"
},
{
"inputs": [
{ "internalType": "address", "name": "_token", "type": "address" },
{ "internalType": "address", "name": "_to", "type": "address" },
{ "internalType": "uint256", "name": "_amount", "type": "uint256" },
{ "internalType": "bytes", "name": "_data", "type": "bytes" }
],
"name": "outboundTransfer",
"outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
"stateMutability": "payable",
"type": "function"
}
]
Loading

0 comments on commit e4f5e39

Please sign in to comment.