Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into feat/performance-tr…
Browse files Browse the repository at this point in the history
…acking
  • Loading branch information
pxrl committed Nov 22, 2024
2 parents 669707a + f4043b7 commit c4e406a
Show file tree
Hide file tree
Showing 13 changed files with 591 additions and 51 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"dependencies": {
"@across-protocol/constants": "^3.1.19",
"@across-protocol/contracts": "^3.0.16",
"@across-protocol/sdk": "^3.2.15",
"@arbitrum/sdk": "^3.1.3",
"@across-protocol/sdk": "^3.3.18",
"@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
2 changes: 2 additions & 0 deletions src/common/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,8 @@ export const RELAYER_DEFAULT_SPOKEPOOL_INDEXER = "./dist/src/libexec/RelayerSpok

export const DEFAULT_ARWEAVE_GATEWAY = { url: "arweave.net", port: 443, protocol: "https" };

export const ARWEAVE_TAG_BYTE_LIMIT = 2048;

// Chains with slow (> 2 day liveness) canonical L2-->L1 bridges that we prioritize taking repayment on.
// This does not include all 7-day withdrawal chains because we don't necessarily prefer being repaid on some of these 7-day chains, like Mode.
// This list should generally exclude Lite chains because the relayer ignores HubPool liquidity in that case which could cause the
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"
}
]
30 changes: 25 additions & 5 deletions src/dataworker/Dataworker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
FillStatus,
} from "../interfaces";
import { DataworkerClients } from "./DataworkerClientHelper";
import { SpokePoolClient, BalanceAllocator } from "../clients";
import { SpokePoolClient, BalanceAllocator, BundleDataClient } from "../clients";
import * as PoolRebalanceUtils from "./PoolRebalanceUtils";
import {
blockRangesAreInvalidForSpokeClients,
Expand Down Expand Up @@ -619,16 +619,33 @@ export class Dataworker {
// Root bundle is valid, attempt to persist the raw bundle data and the merkle leaf data to DA layer
// if not already there.
if (persistBundleData && isDefined(bundleData)) {
const chainIds = this.clients.configStoreClient.getChainIdIndicesForBlock(nextBundleMainnetStartBlock);
// Store the bundle block ranges on Arweave as a map of chainId to block range to aid users in querying.
const bundleBlockRangeMap = Object.fromEntries(
bundleData.bundleBlockRanges.map((range, i) => {
const chainIdForRange = chainIds[i];
return [chainIdForRange, range];
})
);
// As a unique key for this bundle, use the next bundle mainnet start block, which should
// never be duplicated between bundles as long as the mainnet end block in the bundle block range
// always progresses forwards, which I think is a safe assumption. Other chains might pause
// but mainnet should never pause.
const partialArweaveDataKey = BundleDataClient.getArweaveClientKey(bundleData.bundleBlockRanges);
await Promise.all([
persistDataToArweave(
this.clients.arweaveClient,
bundleData,
{
...bundleData,
bundleBlockRanges: bundleBlockRangeMap,
},
this.logger,
`bundles-${bundleData.bundleBlockRanges}`
`bundles-${partialArweaveDataKey}`
),
persistDataToArweave(
this.clients.arweaveClient,
{
bundleBlockRanges: bundleBlockRangeMap,
poolRebalanceLeaves: expectedTrees.poolRebalanceTree.leaves.map((leaf) => {
return {
...leaf,
Expand All @@ -652,7 +669,7 @@ export class Dataworker {
slowRelayRoot: expectedTrees.slowRelayTree.tree.getHexRoot(),
},
this.logger,
`merkletree-${bundleData.bundleBlockRanges}`
`merkletree-${partialArweaveDataKey}`
),
]);
}
Expand Down Expand Up @@ -2297,7 +2314,10 @@ export class Dataworker {
at: "Dataworker#_getPoolRebalanceRoot",
message: "Constructed new pool rebalance root",
key,
root: this.rootCache[key],
root: {
...this.rootCache[key],
tree: this.rootCache[key].tree.getHexRoot(),
},
});

return _.cloneDeep(this.rootCache[key]);
Expand Down
Loading

0 comments on commit c4e406a

Please sign in to comment.