Skip to content

Commit

Permalink
Sync with upstream repo (#84)
Browse files Browse the repository at this point in the history
Merge latest changes from upstream repo
  • Loading branch information
sameersubudhi authored Jan 14, 2025
2 parents 823bd96 + 80d5f8c commit e12234e
Show file tree
Hide file tree
Showing 22 changed files with 333 additions and 365 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
"node": ">=20"
},
"dependencies": {
"@across-protocol/constants": "^3.1.25",
"@across-protocol/contracts": "^3.0.19",
"@across-protocol/sdk": "^3.3.32",
"@across-protocol/constants": "^3.1.27",
"@across-protocol/contracts": "^3.0.20",
"@across-protocol/sdk": "^3.4.9",
"@arbitrum/sdk": "^4.0.2",
"@aws-sdk/client-kms": "^3.592.0",
"@aws-sdk/client-s3": "^3.592.0",
Expand Down
2 changes: 1 addition & 1 deletion scripts/zkSyncDemo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export async function run(): Promise<void> {
connectedSigner
);
const l2PubdataByteLimit = zksync.utils.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT;
const l1GasPriceData = await gasPriceOracle.getGasPriceEstimate(l1Provider, l1ChainId);
const l1GasPriceData = await gasPriceOracle.getGasPriceEstimate(l1Provider, { chainId: l1ChainId });
const estimatedL1GasPrice = l1GasPriceData.maxPriorityFeePerGas.add(l1GasPriceData.maxFeePerGas);
// The ZkSync Mailbox contract checks that the msg.value of the transaction is enough to cover the transaction base
// cost. The transaction base cost can be queried from the Mailbox by passing in an L1 "executed" gas price,
Expand Down
68 changes: 0 additions & 68 deletions src/adapter/AdapterManager.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/adapter/bridges/ArbitrumOrbitBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import { CONTRACT_ADDRESSES, CUSTOM_ARBITRUM_GATEWAYS, DEFAULT_ARBITRUM_GATEWAY } from "../../common";
import { BridgeTransactionDetails, BaseBridgeAdapter, BridgeEvents } from "./BaseBridgeAdapter";
import { processEvent } from "../utils";
import { PRODUCTION_NETWORKS } from "@across-protocol/constants";
import { PUBLIC_NETWORKS } from "@across-protocol/constants";

const bridgeSubmitValue: { [chainId: number]: BigNumber } = {
[CHAIN_IDs.ARBITRUM]: toWei(0.013),
Expand Down Expand Up @@ -53,7 +53,7 @@ export class ArbitrumOrbitBridge extends BaseBridgeAdapter {

super(l2chainId, hubChainId, l1Signer, l2SignerOrProvider, [l1Address]);

const nativeToken = PRODUCTION_NETWORKS[l2chainId].nativeToken;
const nativeToken = PUBLIC_NETWORKS[l2chainId].nativeToken;
// Only set nonstandard gas tokens.
if (nativeToken !== "ETH") {
this.gasToken = TOKEN_SYMBOLS_MAP[nativeToken].addresses[hubChainId];
Expand Down
30 changes: 15 additions & 15 deletions src/clients/MultiCallerClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export interface TryMulticallTransaction {
export class MultiCallerClient {
protected txnClient: TransactionClient;
protected txns: { [chainId: number]: AugmentedTransaction[] } = {};
protected valueTxns: { [chainId: number]: AugmentedTransaction[] } = {};
protected nonMulticallTxns: { [chainId: number]: AugmentedTransaction[] } = {};
constructor(
readonly logger: winston.Logger,
readonly chunkSize: { [chainId: number]: number } = {},
Expand All @@ -90,8 +90,8 @@ export class MultiCallerClient {

getQueuedTransactions(chainId: number): AugmentedTransaction[] {
const allTxns = [];
if (this.valueTxns?.[chainId]) {
allTxns.push(...this.valueTxns[chainId]);
if (this.nonMulticallTxns?.[chainId]) {
allTxns.push(...this.nonMulticallTxns[chainId]);
}
if (this.txns?.[chainId]) {
allTxns.push(...this.txns[chainId]);
Expand All @@ -101,8 +101,8 @@ export class MultiCallerClient {

// Adds all information associated with a transaction to the transaction queue.
enqueueTransaction(txn: AugmentedTransaction): void {
// Value transactions are sorted immediately because the UMA multicall implementation rejects them.
const txnQueue = txn.value && txn.value.gt(0) ? this.valueTxns : this.txns;
// We do not attempt to batch together transactions that have value or are explicitly nonMulticall.
const txnQueue = (txn.value && txn.value.gt(0)) || txn.nonMulticall ? this.nonMulticallTxns : this.txns;
if (txnQueue[txn.chainId] === undefined) {
txnQueue[txn.chainId] = [];
}
Expand All @@ -111,25 +111,25 @@ export class MultiCallerClient {

transactionCount(): number {
return Object.values(this.txns)
.concat(Object.values(this.valueTxns))
.concat(Object.values(this.nonMulticallTxns))
.reduce((count, txnQueue) => (count += txnQueue.length), 0);
}

clearTransactionQueue(chainId: number | null = null): void {
if (chainId !== null) {
this.txns[chainId] = [];
this.valueTxns[chainId] = [];
this.nonMulticallTxns[chainId] = [];
} else {
this.txns = {};
this.valueTxns = {};
this.nonMulticallTxns = {};
}
}

// For each chain, collate the enqueued transactions and process them in parallel.
async executeTxnQueues(simulate = false, chainIds: number[] = []): Promise<Record<number, string[]>> {
if (chainIds.length === 0) {
chainIds = sdkUtils.dedupArray([
...Object.keys(this.valueTxns).map(Number),
...Object.keys(this.nonMulticallTxns).map(Number),
...Object.keys(this.txns).map(Number),
]);
}
Expand Down Expand Up @@ -174,9 +174,9 @@ export class MultiCallerClient {
// For a single chain, take any enqueued transactions and attempt to execute them.
async executeTxnQueue(chainId: number, simulate = false): Promise<TransactionResponse[]> {
const txns: AugmentedTransaction[] | undefined = this.txns[chainId];
const valueTxns: AugmentedTransaction[] | undefined = this.valueTxns[chainId];
const nonMulticallTxns: AugmentedTransaction[] | undefined = this.nonMulticallTxns[chainId];
this.clearTransactionQueue(chainId);
return this._executeTxnQueue(chainId, txns, valueTxns, simulate);
return this._executeTxnQueue(chainId, txns, nonMulticallTxns, simulate);
}

// For a single chain, simulate all potential multicall txns and group the ones that pass into multicall bundles.
Expand All @@ -185,10 +185,10 @@ export class MultiCallerClient {
protected async _executeTxnQueue(
chainId: number,
txns: AugmentedTransaction[] = [],
valueTxns: AugmentedTransaction[] = [],
nonMulticallTxns: AugmentedTransaction[] = [],
simulate = false
): Promise<TransactionResponse[]> {
const nTxns = txns.length + valueTxns.length;
const nTxns = txns.length + nonMulticallTxns.length;
if (nTxns === 0) {
return [];
}
Expand All @@ -204,7 +204,7 @@ export class MultiCallerClient {
// First try to simulate the transaction as a batch. If the full batch succeeded, then we don't
// need to simulate transactions individually. If the batch failed, then we need to
// simulate the transactions individually and pick out the successful ones.
const batchTxns: AugmentedTransaction[] = valueTxns.concat(
const batchTxns: AugmentedTransaction[] = nonMulticallTxns.concat(
await this.buildMultiCallBundles(txns, this.chunkSize[chainId])
);
const batchSimResults = await this.txnClient.simulate(batchTxns);
Expand All @@ -227,7 +227,7 @@ export class MultiCallerClient {
} else {
const individualTxnSimResults = await Promise.allSettled([
this.simulateTransactionQueue(txns),
this.simulateTransactionQueue(valueTxns),
this.simulateTransactionQueue(nonMulticallTxns),
]);
const [_txns, _valueTxns] = individualTxnSimResults.map((result): AugmentedTransaction[] => {
return isPromiseFulfilled(result) ? result.value : [];
Expand Down
69 changes: 53 additions & 16 deletions src/clients/ProfitClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
TOKEN_EQUIVALENCE_REMAPPING,
ZERO_ADDRESS,
formatGwei,
fixedPointAdjustment,
} from "../utils";
import { Deposit, DepositWithBlock, L1Token, SpokePoolClientsByChain } from "../interfaces";
import { getAcrossHost } from "./AcrossAPIClient";
Expand Down Expand Up @@ -213,7 +214,7 @@ export class ProfitClient {
message: "Failed to simulate fill for deposit.",
reason,
deposit,
notificationPath: "across-unprofitable-fills",
notificationPath: "across-warn",
});
return { nativeGasCost: uint256Max, tokenGasCost: uint256Max, gasPrice: uint256Max };
}
Expand Down Expand Up @@ -543,7 +544,12 @@ export class ProfitClient {
.filter(({ symbol }) => isDefined(TOKEN_SYMBOLS_MAP[symbol]))
.map(({ symbol }) => {
const { addresses } = TOKEN_SYMBOLS_MAP[symbol];
const address = addresses[CHAIN_IDs.MAINNET];
let address = addresses[CHAIN_IDs.MAINNET];
// For testnet only, if we cannot resolve the token address, revert to ETH. On mainnet, if `address` is undefined,
// we will throw an error instead.
if (this.hubPoolClient.chainId === CHAIN_IDs.SEPOLIA && !isDefined(address)) {
address = TOKEN_SYMBOLS_MAP.ETH.addresses[CHAIN_IDs.MAINNET];
}
return [symbol, address];
})
);
Expand All @@ -566,7 +572,12 @@ export class ProfitClient {
// Also ensure all gas tokens are included in the lookup.
this.enabledChainIds.forEach((chainId) => {
const symbol = getNativeTokenSymbol(chainId);
tokens[symbol] ??= TOKEN_SYMBOLS_MAP[symbol].addresses[CHAIN_IDs.MAINNET];
let nativeTokenAddress = TOKEN_SYMBOLS_MAP[symbol].addresses[CHAIN_IDs.MAINNET];
// For testnet only, if the custom gas token has no mainnet address, use ETH.
if (this.hubPoolClient.chainId === CHAIN_IDs.SEPOLIA && !isDefined(nativeTokenAddress)) {
nativeTokenAddress = TOKEN_SYMBOLS_MAP["ETH"].addresses[CHAIN_IDs.MAINNET];
}
tokens[symbol] ??= nativeTokenAddress;
});

this.logger.debug({ at: "ProfitClient", message: "Updating Profit client", tokens });
Expand Down Expand Up @@ -609,6 +620,7 @@ export class ProfitClient {
[CHAIN_IDs.REDSTONE]: "WETH", // Redstone only supports WETH.
[CHAIN_IDs.WORLD_CHAIN]: "WETH", // USDC deferred on World Chain.
[CHAIN_IDs.INK]: "WETH", // USDC deferred on Ink.
[CHAIN_IDs.LENS_SEPOLIA]: "WETH", // No USD token on Lens Sepolia
};
const prodRelayer = process.env.RELAYER_FILL_SIMULATION_ADDRESS ?? PROD_RELAYER;
const [defaultTestSymbol, relayer] =
Expand Down Expand Up @@ -636,24 +648,49 @@ export class ProfitClient {
};

// Pre-fetch total gas costs for relays on enabled chains.
await sdkUtils.mapAsync(enabledChainIds, async (destinationChainId) => {
const symbol = testSymbols[destinationChainId] ?? defaultTestSymbol;
const hubToken = TOKEN_SYMBOLS_MAP[symbol].addresses[this.hubPoolClient.chainId];
const outputToken =
destinationChainId === hubPoolClient.chainId
? hubToken
: hubPoolClient.getL2TokenForL1TokenAtBlock(hubToken, destinationChainId);
assert(isDefined(outputToken), `Chain ${destinationChainId} SpokePool is not configured for ${symbol}`);

const deposit = { ...sampleDeposit, destinationChainId, outputToken };
this.totalGasCosts[destinationChainId] = await this._getTotalGasCost(deposit, relayer);
});
const totalGasCostsToLog = Object.fromEntries(
await sdkUtils.mapAsync(enabledChainIds, async (destinationChainId) => {
const symbol = testSymbols[destinationChainId] ?? defaultTestSymbol;
const hubToken = TOKEN_SYMBOLS_MAP[symbol].addresses[this.hubPoolClient.chainId];
const outputToken =
destinationChainId === hubPoolClient.chainId
? hubToken
: hubPoolClient.getL2TokenForL1TokenAtBlock(hubToken, destinationChainId);
assert(isDefined(outputToken), `Chain ${destinationChainId} SpokePool is not configured for ${symbol}`);

const deposit = { ...sampleDeposit, destinationChainId, outputToken };
const gasCosts = await this._getTotalGasCost(deposit, relayer);
// The scaledNativeGasCost is approximately what the relayer will set as the `gasLimit` when submitting
// fills on the destination chain.
const scaledNativeGasCost = gasCosts.nativeGasCost.mul(this.gasPadding).div(fixedPointAdjustment);
// The scaledTokenGasCost is the estimated gas cost of submitting a fill on the destination chain and is used
// in the this.estimateFillCost function to determine whether a deposit is profitable to fill. Therefore,
// the scaledTokenGasCost should be safely lower than the quote API's tokenGasCosts in order for the relayer
// to consider a deposit is profitable.
const scaledTokenGasCost = gasCosts.tokenGasCost
.mul(this.gasPadding)
.div(fixedPointAdjustment)
.mul(this.gasMultiplier)
.div(fixedPointAdjustment);
this.totalGasCosts[destinationChainId] = gasCosts;
return [
destinationChainId,
{
...gasCosts,
scaledNativeGasCost,
scaledTokenGasCost,
gasPadding: formatEther(this.gasPadding),
gasMultiplier: formatEther(this.gasMultiplier),
},
];
})
);

this.logger.debug({
at: "ProfitClient",
message: "Updated gas cost",
enabledChainIds: this.enabledChainIds,
totalGasCosts: this.totalGasCosts,
totalGasCosts: totalGasCostsToLog,
});
}

Expand Down
3 changes: 3 additions & 0 deletions src/clients/TransactionClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export interface AugmentedTransaction {
canFailInSimulation?: boolean;
// Optional batch ID to use to group transactions
groupId?: string;
// If true, the transaction is being sent to a non Multicall contract so we can't batch it together
// with other transactions.
nonMulticall?: boolean;
}

const { fixedPointAdjustment: fixedPoint } = sdkUtils;
Expand Down
Loading

0 comments on commit e12234e

Please sign in to comment.