Skip to content

Commit

Permalink
feat: allow usage of cached gasUsage + SpeedProvider (#717)
Browse files Browse the repository at this point in the history
  • Loading branch information
dohaki authored Sep 6, 2024
1 parent 53547a6 commit 39894ed
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 13 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@across-protocol/sdk",
"author": "UMA Team",
"version": "3.1.31",
"version": "3.1.32",
"license": "AGPL-3.0",
"homepage": "https://docs.across.to/reference/sdk",
"files": [
Expand Down
1 change: 1 addition & 0 deletions src/providers/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./rateLimitedProvider";
export * from "./cachedProvider";
export * from "./retryProvider";
export * from "./speedProvider";
export * from "./constants";
export * from "./types";
export * from "./utils";
63 changes: 63 additions & 0 deletions src/providers/speedProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { ethers } from "ethers";
import { CachingMechanismInterface } from "../interfaces";
import { CacheProvider } from "./cachedProvider";
import { formatProviderError } from "./utils";
import { PROVIDER_CACHE_TTL } from "./constants";
import { Logger } from "winston";

/**
* RPC provider that sends requests to multiple providers in parallel and returns the fastest response.
*/
export class SpeedProvider extends ethers.providers.StaticJsonRpcProvider {
readonly providers: ethers.providers.StaticJsonRpcProvider[];

constructor(
params: ConstructorParameters<typeof ethers.providers.StaticJsonRpcProvider>[],
chainId: number,
readonly maxConcurrencySpeed: number,
readonly maxConcurrencyRateLimit: number,
providerCacheNamespace: string,
pctRpcCallsLogged: number,
redisClient?: CachingMechanismInterface,
standardTtlBlockDistance?: number,
noTtlBlockDistance?: number,
providerCacheTtl = PROVIDER_CACHE_TTL,
logger?: Logger
) {
// Initialize the super just with the chainId, which stops it from trying to immediately send out a .send before
// this derived class is initialized.
super(undefined, chainId);
this.providers = params.map(
(inputs) =>
new CacheProvider(
providerCacheNamespace,
redisClient,
standardTtlBlockDistance,
noTtlBlockDistance,
providerCacheTtl,
maxConcurrencyRateLimit,
pctRpcCallsLogged,
logger,
...inputs
)
);
}

override async send(method: string, params: Array<unknown>): Promise<unknown> {
try {
const providersToUse = this.providers.slice(0, this.maxConcurrencySpeed);
const result = await Promise.any(providersToUse.map((provider) => provider.send(method, params)));
return result;
} catch (error) {
// Only thrown if all providers failed to respond
if (error instanceof AggregateError) {
const errors = error.errors.map((error, index) => {
const provider = this.providers[index];
return formatProviderError(provider, error.message);
});
throw new Error("All providers errored:\n" + errors.join("\n"));
}
throw error;
}
}
}
6 changes: 3 additions & 3 deletions src/relayFeeCalculator/chain-queries/baseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ export class QueryBase implements QueryInterface {
* @param deposit V3 deposit instance.
* @param relayerAddress Relayer address to simulate with.
* @param gasPrice Optional gas price to use for the simulation.
* @param gasLimit Optional gas limit to use for the simulation.
* @param gasUnits Optional gas units to use for the simulation.
* @returns The gas estimate for this function call (multiplied with the optional buffer).
*/
async getGasCosts(
deposit: Deposit,
relayer = DEFAULT_SIMULATED_RELAYER_ADDRESS,
gasPrice = this.fixedGasPrice,
gasLimit?: BigNumberish
gasUnits?: BigNumberish
): Promise<TransactionCostEstimate> {
const tx = await populateV3Relay(this.spokePool, deposit, relayer);
return estimateTotalGasRequiredByUnsignedTransaction(
Expand All @@ -75,7 +75,7 @@ export class QueryBase implements QueryInterface {
this.provider,
this.gasMarkup,
gasPrice,
gasLimit
gasUnits
);
}

Expand Down
6 changes: 4 additions & 2 deletions src/relayFeeCalculator/relayFeeCalculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ export class RelayFeeCalculator {
* the relayer.
* @param relayerAddress The relayer that will be used for the gas cost simulation
* @param _tokenPrice The token price for normalizing fees
* @param gasPrice Optional gas price to use for the simulation
* @param gasUnits Optional gas units to use for the simulation
* @returns A resulting `RelayerFeeDetails` object
*/
async relayerFeeDetails(
Expand All @@ -351,7 +353,7 @@ export class RelayFeeCalculator {
relayerAddress = DEFAULT_SIMULATED_RELAYER_ADDRESS,
_tokenPrice?: number,
gasPrice?: BigNumberish,
gasLimit?: BigNumberish
gasUnits?: BigNumberish
): Promise<RelayerFeeDetails> {
// If the amount to relay is not provided, then we
// should use the full deposit amount.
Expand All @@ -370,7 +372,7 @@ export class RelayFeeCalculator {
_tokenPrice,
undefined,
gasPrice,
gasLimit
gasUnits
);
const gasFeeTotal = gasFeePercent.mul(amountToRelay).div(fixedPointAdjustment);
const capitalFeePercent = this.capitalFeePercent(
Expand Down
15 changes: 8 additions & 7 deletions src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ export type TransactionCostEstimate = {
* @param provider A valid ethers provider - will be used to reason the gas price.
* @param gasMarkup Markup on the estimated gas cost. For example, 0.2 will increase this resulting value 1.2x.
* @param gasPrice A manually provided gas price - if set, this function will not resolve the current gas price.
* @param gasLimit A manually provided gas limit - if set, this function will not estimate the gas limit.
* @param gasUnits A manually provided gas units - if set, this function will not estimate the gas units.
* @returns Estimated cost in units of gas and the underlying gas token (gasPrice * estimatedGasUnits).
*/
export async function estimateTotalGasRequiredByUnsignedTransaction(
Expand All @@ -251,7 +251,7 @@ export async function estimateTotalGasRequiredByUnsignedTransaction(
provider: providers.Provider | L2Provider<providers.Provider>,
gasMarkup: number,
gasPrice?: BigNumberish,
gasLimit?: BigNumberish
gasUnits?: BigNumberish
): Promise<TransactionCostEstimate> {
assert(
gasMarkup > -1 && gasMarkup <= 4,
Expand All @@ -262,11 +262,12 @@ export async function estimateTotalGasRequiredByUnsignedTransaction(
const voidSigner = new VoidSigner(senderAddress, provider);

// Estimate the Gas units required to submit this transaction.
let nativeGasCost = await voidSigner.estimateGas({
...unsignedTx,
gasPrice,
gasLimit,
});
let nativeGasCost = gasUnits
? BigNumber.from(gasUnits)
: await voidSigner.estimateGas({
...unsignedTx,
gasPrice,
});
let tokenGasCost: BigNumber;

// OP stack is a special case; gas cost is computed by the SDK, without having to query price.
Expand Down

0 comments on commit 39894ed

Please sign in to comment.