Skip to content

Commit

Permalink
Merge branch 'master' into bz/atomicWethAdapters
Browse files Browse the repository at this point in the history
  • Loading branch information
james-a-morris authored Dec 19, 2024
2 parents 2b4f3be + 96adc9d commit 8dc6384
Show file tree
Hide file tree
Showing 78 changed files with 5,154 additions and 1,741 deletions.
17 changes: 13 additions & 4 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import minimist from "minimist";
import { config, delay, exit, retrieveSignerFromCLIArgs, help, Logger, usage, waitForLogger } from "./src/utils";
import {
config,
delay,
exit,
retrieveSignerFromCLIArgs,
help,
Logger,
usage,
waitForLogger,
stringifyThrownValue,
} from "./src/utils";
import { runRelayer } from "./src/relayer";
import { runDataworker } from "./src/dataworker";
import { runMonitor } from "./src/monitor";
Expand Down Expand Up @@ -61,12 +71,11 @@ if (require.main === module) {
run(args)
.catch(async (error) => {
exitCode = 1;
const stringifiedError = stringifyThrownValue(error);
logger.error({
at: cmd ?? "unknown process",
message: "There was an execution error!",
reason: error,
e: error,
error,
error: stringifiedError,
args,
notificationPath: "across-error",
});
Expand Down
18 changes: 14 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
"node": ">=20"
},
"dependencies": {
"@across-protocol/constants": "^3.1.16",
"@across-protocol/contracts": "^3.0.11",
"@across-protocol/sdk": "^3.2.7",
"@arbitrum/sdk": "^3.1.3",
"@across-protocol/constants": "^3.1.22",
"@across-protocol/contracts": "^3.0.18",
"@across-protocol/sdk": "^3.3.26",
"@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 Expand Up @@ -112,5 +112,15 @@
"publishConfig": {
"registry": "https://registry.npmjs.com/",
"access": "public"
},
"resolutions": {
"secp256k1": "4.0.4",
"**/secp256k1": "4.0.4",
"eccrypto/secp256k1": "3.8.1"
},
"overrides": {
"[email protected]": "3.8.1",
"[email protected]": "4.0.4",
"[email protected]": "5.0.1"
}
}
18 changes: 10 additions & 8 deletions scripts/spokepool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import { groupBy } from "lodash";
import { config } from "dotenv";
import { Contract, ethers, Signer } from "ethers";
import { LogDescription } from "@ethersproject/abi";
import { CHAIN_IDs } from "@across-protocol/constants";
import { constants as sdkConsts, utils as sdkUtils } from "@across-protocol/sdk";
import { ExpandedERC20__factory as ERC20 } from "@across-protocol/contracts";
import { RelayData } from "../src/interfaces";
import { getAcrossHost } from "../src/clients";
import {
BigNumber,
formatFeePct,
getDeploymentBlockNumber,
getNetworkName,
getProvider,
getSigner,
isDefined,
resolveTokenSymbols,
Expand All @@ -32,8 +35,6 @@ type RelayerFeeQuery = {
timestamp?: number;
};

const { ACROSS_API_HOST = "across.to" } = process.env;

const { NODE_SUCCESS, NODE_INPUT_ERR, NODE_APP_ERR } = utils;
const { fixedPointAdjustment: fixedPoint } = sdkUtils;
const { AddressZero } = ethers.constants;
Expand Down Expand Up @@ -86,8 +87,9 @@ function printFill(destinationChainId: number, log: LogDescription): void {
}

async function getSuggestedFees(params: RelayerFeeQuery, timeout: number) {
const hubChainId = sdkUtils.chainIsProd(params.originChainId) ? CHAIN_IDs.MAINNET : CHAIN_IDs.SEPOLIA;
const path = "api/suggested-fees";
const url = `https://${ACROSS_API_HOST}/${path}`;
const url = `https://${getAcrossHost(hubChainId)}/${path}`;

try {
const quote = await axios.get(url, { timeout, params });
Expand Down Expand Up @@ -194,7 +196,7 @@ async function deposit(args: Record<string, number | string>, signer: Signer): P
const tokenSymbol = token.symbol.toUpperCase();
const amount = ethers.utils.parseUnits(baseAmount.toString(), args.decimals ? 0 : token.decimals);

const provider = new ethers.providers.StaticJsonRpcProvider(utils.getProviderUrl(fromChainId));
const provider = await getProvider(fromChainId);
signer = signer.connect(provider);
const spokePool = (await utils.getSpokePoolContract(fromChainId)).connect(signer);

Expand Down Expand Up @@ -246,7 +248,7 @@ async function fillDeposit(args: Record<string, number | string | boolean>, sign
throw new Error(`Missing or malformed transaction hash: ${txnHash}`);
}

const originProvider = new ethers.providers.StaticJsonRpcProvider(utils.getProviderUrl(originChainId));
const originProvider = await getProvider(originChainId);
const originSpokePool = await utils.getSpokePoolContract(originChainId);
const spokePools: { [chainId: number]: Contract } = {};

Expand Down Expand Up @@ -321,7 +323,7 @@ async function fillDeposit(args: Record<string, number | string | boolean>, sign
}

const sender = await signer.getAddress();
const destProvider = new ethers.providers.StaticJsonRpcProvider(utils.getProviderUrl(destinationChainId));
const destProvider = await getProvider(destinationChainId);
const destSigner = signer.connect(destProvider);

const erc20 = new Contract(outputToken, ERC20.abi, destSigner);
Expand All @@ -348,7 +350,7 @@ async function dumpConfig(args: Record<string, number | string>, _signer: Signer
const _spokePool = await utils.getSpokePoolContract(chainId);

const hubChainId = utils.resolveHubChainId(chainId);
const spokeProvider = new ethers.providers.StaticJsonRpcProvider(utils.getProviderUrl(chainId));
const spokeProvider = await getProvider(chainId);
const spokePool = _spokePool.connect(spokeProvider);

const [spokePoolChainId, hubPool, crossDomainAdmin, weth, _currentTime] = await Promise.all([
Expand Down Expand Up @@ -436,7 +438,7 @@ async function fetchTxn(args: Record<string, number | string>, _signer: Signer):
return false;
}

const provider = new ethers.providers.StaticJsonRpcProvider(utils.getProviderUrl(chainId));
const provider = await getProvider(chainId);
const spokePool = (await utils.getSpokePoolContract(chainId)).connect(provider);

let deposits: Log[] = [];
Expand Down
25 changes: 3 additions & 22 deletions scripts/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import assert from "assert";
import { Contract, ethers, utils as ethersUtils, Signer } from "ethers";
import { Contract, utils as ethersUtils, Signer } from "ethers";
import readline from "readline";
import * as contracts from "@across-protocol/contracts";
import { utils as sdkUtils } from "@across-protocol/sdk";
import { getDeployedContract, getNodeUrlList, CHAIN_IDs } from "../src/utils";
import { getDeployedContract, getProvider, CHAIN_IDs } from "../src/utils";

// https://nodejs.org/api/process.html#exit-codes
export const NODE_SUCCESS = 0;
Expand All @@ -16,12 +16,6 @@ export type ERC20 = {
symbol: string;
};

// Public RPC endpoints to be used if preferred providers are not defined in the environment.
const fallbackProviders: { [chainId: number]: string } = {
[CHAIN_IDs.MAINNET]: "https://eth.llamarpc.com",
[CHAIN_IDs.SEPOLIA]: "https://sepolia.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161",
};

async function askQuestion(query: string) {
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });

Expand Down Expand Up @@ -81,19 +75,6 @@ export function validateChainIds(chainIds: number[]): boolean {
);
}

/**
* @description Resolve a default provider URL.
* @param chainId Chain ID for the provider to select.
* @returns URL of the provider endpoint.
*/
export function getProviderUrl(chainId: number): string {
try {
return getNodeUrlList(chainId, 1)[0];
} catch {
return fallbackProviders[chainId];
}
}

/**
* @description For a SpokePool chain ID, resolve its corresponding HubPool chain ID.
* @param spokeChainId Chain ID of the SpokePool.
Expand All @@ -116,7 +97,7 @@ export function resolveHubChainId(spokeChainId: number): number {
*/
export async function getContract(chainId: number, contractName: string): Promise<Contract> {
const contract = getDeployedContract(contractName, chainId);
const provider = new ethers.providers.StaticJsonRpcProvider(getProviderUrl(chainId));
const provider = await getProvider(chainId);
return contract.connect(provider);
}

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);
});
}
Loading

0 comments on commit 8dc6384

Please sign in to comment.