Skip to content

Commit

Permalink
feat(alchemy): use rundler_getLocalRequiredFees for fee estimate
Browse files Browse the repository at this point in the history
  • Loading branch information
dancoombs committed Aug 8, 2023
1 parent 1561d7f commit dfda704
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,6 @@ import {
metaForStepIdentifier,
} from "./OnboardingDataModels";

export enum GasFeeStrategy {
DEFAULT = "DEFAULT",
FIXED = "FIXED",
BASE_FEE_PERCENTAGE = "BASE_FEE_PERCENTAGE",
PRIORITY_FEE_PERCENTAGE = "PRIORITY_FEE_PERCENTAGE",
}

export interface GasFeeMode {
strategy: GasFeeStrategy;
value: bigint;
}

async function pollForLambdaForComplete(
lambda: () => Promise<boolean>,
txnMaxDurationSeconds: number = 20
Expand Down
54 changes: 0 additions & 54 deletions packages/alchemy/src/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
polygonMumbai,
sepolia,
} from "viem/chains";
import { GasFeeStrategy, type GasFeeMode } from "./middleware/gas-fees.js";

export const SupportedChains = new Map<number, Chain>([
[polygonMumbai.id, polygonMumbai],
Expand All @@ -23,56 +22,3 @@ export const SupportedChains = new Map<number, Chain>([
[optimism.id, optimism],
[optimismGoerli.id, optimismGoerli],
]);

const defineChainStrategy = (
chainId: number,
strategy: GasFeeStrategy,
value: GasFeeMode["value"]
): [number, GasFeeMode] => {
return [chainId, { strategy, value }];
};

export const ChainFeeStrategies: Map<number, GasFeeMode> = new Map<
number,
GasFeeMode
>([
// testnets
defineChainStrategy(
goerli.id,
GasFeeStrategy.PRIORITY_FEE_INCREASE_PERCENT,
0n
),
defineChainStrategy(
sepolia.id,
GasFeeStrategy.PRIORITY_FEE_INCREASE_PERCENT,
0n
),
defineChainStrategy(
polygonMumbai.id,
GasFeeStrategy.PRIORITY_FEE_INCREASE_PERCENT,
0n
),
defineChainStrategy(
optimismGoerli.id,
GasFeeStrategy.PERCENT_OF_BASE_FEE,
0n
),
defineChainStrategy(
arbitrumGoerli.id,
GasFeeStrategy.PERCENT_OF_BASE_FEE,
0n
),
// mainnets
defineChainStrategy(
mainnet.id,
GasFeeStrategy.PRIORITY_FEE_INCREASE_PERCENT,
57n
),
defineChainStrategy(
polygon.id,
GasFeeStrategy.PRIORITY_FEE_INCREASE_PERCENT,
25n
),
defineChainStrategy(optimism.id, GasFeeStrategy.PERCENT_OF_BASE_FEE, 5n),
defineChainStrategy(arbitrum.id, GasFeeStrategy.PERCENT_OF_BASE_FEE, 5n),
]);
6 changes: 1 addition & 5 deletions packages/alchemy/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
export {
GasFeeStrategy,
withAlchemyGasFeeEstimator,
} from "./middleware/gas-fees.js";
export type { GasFeeMode } from "./middleware/gas-fees.js";
export { withAlchemyGasFeeEstimator } from "./middleware/gas-fees.js";

export {
withAlchemyGasManager,
Expand Down
56 changes: 56 additions & 0 deletions packages/alchemy/src/middleware/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
type PublicErc4337Client,
type UserOperationRequest,
} from "@alchemy/aa-core";
import type { Address, Hex } from "viem";

export type ClientWithAlchemyMethods = PublicErc4337Client & {
request: PublicErc4337Client["request"] &
{
request(args: {
method: "alchemy_requestPaymasterAndData";
params: [
{
policyId: string;
entryPoint: Address;
userOperation: UserOperationRequest;
}
];
}): Promise<{ paymasterAndData: Hex }>;

request(args: {
method: "alchemy_requestGasAndPaymasterAndData";
params: [
{
policyId: string;
entryPoint: Address;
userOperation: UserOperationRequest;
dummySignature: Hex;
}
];
}): Promise<{
paymasterAndData: Hex;
callGasLimit: Hex;
verificationGasLimit: Hex;
preVerificationGas: Hex;
maxFeePerGas: Hex;
maxPriorityFeePerGas: Hex;
}>;

request(args: {
method: "rundler_getLocalRequiredFees";
params: [];
}): Promise<{
blockNumber: Hex;
baseFeePerGas: Hex;
minimum: {
maxFeePerGas: Hex;
maxPriorityFeePerGas: Hex;
};
recommended: {
maxFeePerGas: Hex;
maxPriorityFeePerGas: Hex;
};
}>;
}["request"];
};
56 changes: 9 additions & 47 deletions packages/alchemy/src/middleware/gas-fees.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,17 @@
import type { AlchemyProvider } from "../provider.js";

export enum GasFeeStrategy {
DEFAULT = "DEFAULT",
PERCENT_OF_BASE_FEE = "PERCENT_OF_BASE_FEE",
PRIORITY_FEE_INCREASE_PERCENT = "PRIORITY_FEE_INCREASE_PERCENT",
}

export interface GasFeeMode {
strategy: GasFeeStrategy;
value: bigint;
}
import type { ClientWithAlchemyMethods } from "./client.js";

export const withAlchemyGasFeeEstimator = (
provider: AlchemyProvider,
feeMode: GasFeeMode,
maxPriorityFeeBufferPercent: bigint
provider: AlchemyProvider
): AlchemyProvider => {
if (feeMode.strategy === GasFeeStrategy.DEFAULT) {
return provider;
}

provider.withFeeDataGetter(async () => {
const block = await provider.rpcClient.getBlock({ blockTag: "latest" });
const baseFeePerGas = block.baseFeePerGas;
if (baseFeePerGas == null) {
throw new Error("baseFeePerGas is null");
}
// add a buffer here to account for potential spikes in priority fee
const maxPriorityFeePerGas =
(BigInt(await provider.rpcClient.getMaxPriorityFeePerGas()) *
(100n + maxPriorityFeeBufferPercent)) /
100n;
// add 25% overhead to ensure mine
const baseFeeScaled = (baseFeePerGas * 5n) / 4n;

const prioFee = ((): bigint => {
switch (feeMode.strategy) {
case GasFeeStrategy.PERCENT_OF_BASE_FEE:
return (baseFeeScaled * feeMode.value) / 100n;
case GasFeeStrategy.PRIORITY_FEE_INCREASE_PERCENT:
// add 10% to required priority fee to ensure mine
return (maxPriorityFeePerGas * (100n + feeMode.value)) / 100n;
default:
throw new Error("fee mode not supported");
}
})();

return {
maxPriorityFeePerGas: prioFee,
maxFeePerGas: baseFeeScaled + prioFee,
};
const result = await (
provider.rpcClient as ClientWithAlchemyMethods
).request({
method: "rundler_getLocalRequiredFees",
params: [],
});
return result.recommended;
});
return provider;
};
38 changes: 2 additions & 36 deletions packages/alchemy/src/middleware/gas-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,9 @@ import {
resolveProperties,
type ConnectedSmartAccountProvider,
type PublicErc4337Client,
type UserOperationRequest,
} from "@alchemy/aa-core";
import type { Address, Hex, Transport } from "viem";

type ClientWithAlchemyMethods = PublicErc4337Client & {
request: PublicErc4337Client["request"] &
{
request(args: {
method: "alchemy_requestPaymasterAndData";
params: [
{
policyId: string;
entryPoint: Address;
userOperation: UserOperationRequest;
}
];
}): Promise<{ paymasterAndData: Hex }>;
request(args: {
method: "alchemy_requestGasAndPaymasterAndData";
params: [
{
policyId: string;
entryPoint: Address;
userOperation: UserOperationRequest;
dummySignature: Hex;
}
];
}): Promise<{
paymasterAndData: Hex;
callGasLimit: Hex;
verificationGasLimit: Hex;
preVerificationGas: Hex;
maxFeePerGas: Hex;
maxPriorityFeePerGas: Hex;
}>;
}["request"];
};
import type { Address, Transport } from "viem";
import type { ClientWithAlchemyMethods } from "./client.js";

export interface AlchemyGasManagerConfig {
policyId: string;
Expand Down
16 changes: 3 additions & 13 deletions packages/alchemy/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,12 @@ import {
optimism,
optimismGoerli,
} from "viem/chains";
import { ChainFeeStrategies, SupportedChains } from "./chains.js";
import {
GasFeeStrategy,
withAlchemyGasFeeEstimator,
} from "./middleware/gas-fees.js";
import { SupportedChains } from "./chains.js";
import {
withAlchemyGasManager,
type AlchemyGasManagerConfig,
} from "./middleware/gas-manager.js";
import { withAlchemyGasFeeEstimator } from "./middleware/gas-fees.js";

type ConnectionConfig =
| {
Expand Down Expand Up @@ -63,14 +60,7 @@ export class AlchemyProvider extends SmartAccountProvider<HttpTransport> {

super(rpcUrl, entryPointAddress, _chain, account, opts);

withAlchemyGasFeeEstimator(
this,
ChainFeeStrategies.get(_chain.id) ?? {
strategy: GasFeeStrategy.DEFAULT,
value: 0n,
},
feeOpts?.maxPriorityFeeBufferPercent ?? 5n
);
withAlchemyGasFeeEstimator(this);
}

gasEstimator: AccountMiddlewareFn = async (struct) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/provider/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ export class SmartAccountProvider<
const initCode = await this.account.getInitCode();
const uoStruct = await asyncPipe(
this.dummyPaymasterDataMiddleware,
this.gasEstimator,
this.feeDataGetter,
this.gasEstimator,
this.paymasterDataMiddleware,
this.customMiddleware ?? noOpMiddleware,
// This applies the overrides if they've been passed in
Expand Down

0 comments on commit dfda704

Please sign in to comment.