Skip to content

Commit

Permalink
improve: Use base fee multiplier option in SDK to resolve gas fees (a…
Browse files Browse the repository at this point in the history
…cross-protocol#1969)

* improve(TransactionUtils): Use base fee multiplier

Builds on across-protocol/sdk#801 and applies relayer's base fee multiplier to new SDK parameter to scale the base fee

* Update TransactionUtils.ts

* Add unsignedTx to getGasPriceEstimate call in TransactionUtils `runTransaction` method

* Add warning

* Use baseFeeMultiplier in ProfitClient

* Remove relayer specific gas padding, add unit test about relayer fee calculator call

* Fix test

* Revert changes to ProfitClient

* Update TransactionUtils.ts

* import sdk

* 3.4.1

* 3.4.2

* 3.4.3

* Update logs

* Update ProfitClient.ts

* Update TransactionUtils.ts

* Update package.json

* Update yarn.lock

* Update TransactionUtils.ts

* Update TransactionUtils.ts

* Update package.json

* 3.4.5-beta.1

* 3.4.5
  • Loading branch information
nicholaspai authored Jan 7, 2025
1 parent a70df06 commit 03e990d
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 43 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"dependencies": {
"@across-protocol/constants": "^3.1.25",
"@across-protocol/contracts": "^3.0.19",
"@across-protocol/sdk": "^3.3.32",
"@across-protocol/sdk": "^3.4.5",
"@arbitrum/sdk": "^4.0.2",
"@consensys/linea-sdk": "^0.2.1",
"@defi-wonderland/smock": "^2.3.5",
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
52 changes: 39 additions & 13 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 @@ -636,24 +637,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
48 changes: 24 additions & 24 deletions src/utils/TransactionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
BigNumber,
bnZero,
Contract,
fixedPointAdjustment as fixedPoint,
isDefined,
TransactionResponse,
ethers,
Expand Down Expand Up @@ -82,7 +81,12 @@ export async function runTransaction(
Number(process.env[`MAX_FEE_PER_GAS_SCALER_${chainId}`] || process.env.MAX_FEE_PER_GAS_SCALER) ||
DEFAULT_GAS_FEE_SCALERS[chainId]?.maxFeePerGasScaler;

const gas = await getGasPrice(provider, priorityFeeScaler, maxFeePerGasScaler);
const gas = await getGasPrice(
provider,
priorityFeeScaler,
maxFeePerGasScaler,
await contract.populateTransaction[method](...(args as Array<unknown>), { value })
);

logger.debug({
at: "TxUtil",
Expand Down Expand Up @@ -154,30 +158,30 @@ export async function runTransaction(
}
}

// TODO: add in gasPrice when the SDK has this for the given chainId. TODO: improve how we fetch prices.
// For now this method will extract the provider's Fee data from the associated network and scale it by a priority
// scaler. This works on both mainnet and L2's by the utility switching the response structure accordingly.
export async function getGasPrice(
provider: ethers.providers.Provider,
priorityScaler = 1.2,
maxFeePerGasScaler = 3
maxFeePerGasScaler = 3,
transactionObject?: ethers.PopulatedTransaction
): Promise<Partial<FeeData>> {
// Floor scalers at 1.0 as we'll rarely want to submit too low of a gas price. We mostly
// just want to submit with as close to prevailing fees as possible.
maxFeePerGasScaler = Math.max(1, maxFeePerGasScaler);
priorityScaler = Math.max(1, priorityScaler);
const { chainId } = await provider.getNetwork();
const feeData = await gasPriceOracle.getGasPriceEstimate(provider, chainId);

if (feeData.maxPriorityFeePerGas.gt(feeData.maxFeePerGas)) {
feeData.maxFeePerGas = scaleByNumber(feeData.maxPriorityFeePerGas, 1.5);
}

// Handle chains with legacy pricing.
if (feeData.maxPriorityFeePerGas.eq(bnZero)) {
return { gasPrice: scaleByNumber(feeData.maxFeePerGas, priorityScaler) };
}

// Default to EIP-1559 (type 2) pricing.
// Pass in unsignedTx here for better Linea gas price estimations via the Linea Viem provider.
const feeData = await gasPriceOracle.getGasPriceEstimate(provider, {
chainId,
baseFeeMultiplier: toBNWei(maxFeePerGasScaler),
priorityFeeMultiplier: toBNWei(priorityScaler),
unsignedTx: transactionObject,
});

// Default to EIP-1559 (type 2) pricing. If gasPriceOracle is using a legacy adapter for this chain then
// the priority fee will be 0.
return {
maxFeePerGas: scaleByNumber(feeData.maxFeePerGas, Math.max(priorityScaler * maxFeePerGasScaler, 1)),
maxPriorityFeePerGas: scaleByNumber(feeData.maxPriorityFeePerGas, priorityScaler),
maxFeePerGas: feeData.maxFeePerGas,
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
};
}

Expand Down Expand Up @@ -231,7 +235,3 @@ export function getTarget(targetAddress: string):
return { targetAddress };
}
}

function scaleByNumber(amount: BigNumber, scaling: number) {
return amount.mul(toBNWei(scaling)).div(fixedPoint);
}
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@
yargs "^17.7.2"
zksync-web3 "^0.14.3"

"@across-protocol/sdk@^3.3.32":
version "3.3.32"
resolved "https://registry.yarnpkg.com/@across-protocol/sdk/-/sdk-3.3.32.tgz#fa2428df5f9b6cb0392c46f742f11265efa4abb3"
integrity sha512-ADyZQeWxjGAreLoeVQYNiJN4zMmmJ7h6ItgbSjP2+JvZENPaH9t23xCegPIyI0oiVqLrOHOGCJ/yEdX6X3HqpQ==
"@across-protocol/sdk@^3.4.5":
version "3.4.5"
resolved "https://registry.yarnpkg.com/@across-protocol/sdk/-/sdk-3.4.5.tgz#343f53be92e92afd2fd4dbea16f180533093ea26"
integrity sha512-o1DovRfSriL0GTa304rd2KcBDwWYbK2SHT8mElyCLg6beX5RnJKT0YiMUMuCMfZ7MZJscdGzV023e5BhbyeP5A==
dependencies:
"@across-protocol/across-token" "^1.0.0"
"@across-protocol/constants" "^3.1.25"
Expand Down

0 comments on commit 03e990d

Please sign in to comment.