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