Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow usage of cached gasUsage + SpeedProvider #717

Merged
merged 6 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}
}
7 changes: 5 additions & 2 deletions src/relayFeeCalculator/chain-queries/baseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,15 @@ export class QueryBase implements QueryInterface {
* @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
gasLimit?: BigNumberish,
gasUnits?: BigNumberish
): Promise<TransactionCostEstimate> {
const tx = await populateV3Relay(this.spokePool, deposit, relayer);
return estimateTotalGasRequiredByUnsignedTransaction(
Expand All @@ -75,7 +77,8 @@ export class QueryBase implements QueryInterface {
this.provider,
this.gasMarkup,
gasPrice,
gasLimit
gasLimit,
gasUnits
);
}

Expand Down
16 changes: 10 additions & 6 deletions src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ export type TransactionCostEstimate = {
* @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 +252,8 @@ export async function estimateTotalGasRequiredByUnsignedTransaction(
provider: providers.Provider | L2Provider<providers.Provider>,
gasMarkup: number,
gasPrice?: BigNumberish,
gasLimit?: BigNumberish
gasLimit?: BigNumberish,
gasUnits?: BigNumberish
): Promise<TransactionCostEstimate> {
assert(
gasMarkup > -1 && gasMarkup <= 4,
Expand All @@ -262,11 +264,13 @@ 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,
gasLimit,
});
dohaki marked this conversation as resolved.
Show resolved Hide resolved
let tokenGasCost: BigNumber;

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