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

Jade/wip/tracing sdk #1424

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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
9 changes: 6 additions & 3 deletions aa-sdk/core/src/actions/smartAccount/buildUserOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import type {
BuildUserOperationParameters,
UserOperationContext,
} from "./types";
import { clientHeaderTrack } from "../../client/updateHeaders.js";

const USER_OPERATION_METHOD = "buildUserOperation";
/**
* Builds a user operation using the provided client and operation parameters. Ensures that the account exists and the client is compatible.
*
Expand All @@ -33,7 +35,7 @@ import type {
* });
* ```
*
* @param {Client<TTransport, TChain, TAccount>} client the client instance used to build the user operation
* @param {Client<TTransport, TChain, TAccount>} client_ the client instance used to build the user operation
* @param {BuildUserOperationParameters<TAccount, TContext, TEntryPointVersion>} args the parameters required to build the user operation, including account, overrides, and context
* @returns {Promise<UserOperationStruct<TEntryPointVersion>>} a promise that resolves to a `UserOperationStruct` object containing the built user operation details
*/
Expand All @@ -48,9 +50,10 @@ export async function buildUserOperation<
| undefined,
TEntryPointVersion extends GetEntryPointFromAccount<TAccount> = GetEntryPointFromAccount<TAccount>
>(
client: Client<TTransport, TChain, TAccount>,
client_: Client<TTransport, TChain, TAccount>,
args: BuildUserOperationParameters<TAccount, TContext, TEntryPointVersion>
): Promise<UserOperationStruct<TEntryPointVersion>> {
const client = clientHeaderTrack(client_, USER_OPERATION_METHOD);
const { account = client.account, overrides, context } = args;
if (!account) {
throw new AccountNotFoundError();
Expand All @@ -59,7 +62,7 @@ export async function buildUserOperation<
if (!isBaseSmartAccountClient(client)) {
throw new IncompatibleClientError(
"BaseSmartAccountClient",
"buildUserOperation",
USER_OPERATION_METHOD,
client
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
} from "../../types.js";
import { buildUserOperation } from "./buildUserOperation.js";
import type { UserOperationContext } from "./types.js";
import { clientHeaderTrack } from "../../index.js";

/**
* Performs `buildUserOperationFromTx` in batch and builds into a single, yet to be signed `UserOperation` (UO) struct. The output user operation struct will be filled with all gas fields (and paymaster data if a paymaster is used) based on the transactions data (`to`, `data`, `value`, `maxFeePerGas`, `maxPriorityFeePerGas`) computed using the configured `ClientMiddlewares` on the `SmartAccountClient`
Expand Down Expand Up @@ -52,7 +53,7 @@ import type { UserOperationContext } from "./types.js";
* const uoHash = await smartAccountClient.sendRawUserOperation({ request, entryPoint: entryPointAddress });
* ```
*
* @param {Client<Transport, TChain, TAccount>} client the smart account client to use for RPC requests
* @param {Client<Transport, TChain, TAccount>} client_ the smart account client to use for RPC requests
* @param {SendTransactionParameters} args the send tx parameters
* @param {UserOperationOverrides} overrides optional overrides to use for any of the fields
* @param {TContext} context if the smart account client requires additinoal context for building UOs
Expand All @@ -69,11 +70,12 @@ export async function buildUserOperationFromTx<
| undefined,
TEntryPointVersion extends GetEntryPointFromAccount<TAccount> = GetEntryPointFromAccount<TAccount>
>(
client: Client<Transport, TChain, TAccount>,
client_: Client<Transport, TChain, TAccount>,
args: SendTransactionParameters<TChain, TAccount, TChainOverride>,
overrides?: UserOperationOverrides<TEntryPointVersion>,
context?: TContext
): Promise<UserOperationStruct<TEntryPointVersion>> {
const client = clientHeaderTrack(client_, "buildUserOperationFromTx");
const { account = client.account, ...request } = args;
if (!account || typeof account === "string") {
throw new AccountNotFoundError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
BuildUserOperationFromTransactionsResult,
UserOperationContext,
} from "./types";
import { clientHeaderTrack } from "../../index.js";

/**
* Performs `buildUserOperationFromTx` in batch and builds into a single,
Expand Down Expand Up @@ -66,7 +67,7 @@ import type {
* });
* ```
*
* @param {Client<TTransport, TChain, TAccount>} client the smart account client to use to make RPC calls
* @param {Client<TTransport, TChain, TAccount>} client_ the smart account client to use to make RPC calls
* @param {BuildTransactionParameters} args an object containing the requests to build as well as, the account if not hoisted, the context, the overrides, and optionally a flag to enable signing of the UO via the underlying middleware
* @returns {Promise<BuildUserOperationFromTransactionsResult<TEntryPointVersion>>} a Promise containing the built user operation
*/
Expand All @@ -81,9 +82,10 @@ export async function buildUserOperationFromTxs<
| UserOperationContext
| undefined
>(
client: Client<TTransport, TChain, TAccount>,
client_: Client<TTransport, TChain, TAccount>,
args: BuildTransactionParameters<TAccount, TContext, TEntryPointVersion>
): Promise<BuildUserOperationFromTransactionsResult<TEntryPointVersion>> {
const client = clientHeaderTrack(client_, "buildUserOperationFromTxs");
const { account = client.account, requests, overrides, context } = args;
if (!account) {
throw new AccountNotFoundError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
SendUserOperationParameters,
UserOperationContext,
} from "./types";
import { clientHeaderTrack } from "../../index.js";

export type CheckGasSponsorshipEligibilityResult<
TAccount extends SmartContractAccount | undefined =
Expand Down Expand Up @@ -47,7 +48,7 @@ export type CheckGasSponsorshipEligibilityResult<
* );
* ```
*
* @param {Client<TTransport, TChain, TAccount>} client the smart account client to use for making RPC calls
* @param {Client<TTransport, TChain, TAccount>} client_ the smart account client to use for making RPC calls
* @param {SendUserOperationParameters} args containing the user operation, account, context, and overrides
* @returns {Promise<CheckGasSponsorshipEligibilityResult<TAccount>>} a Promise containing a boolean indicating if the account is elgibile for sponsorship and the sponsored UO
*/
Expand All @@ -61,9 +62,10 @@ export function checkGasSponsorshipEligibility<
| UserOperationContext
| undefined
>(
client: Client<TTransport, TChain, TAccount>,
client_: Client<TTransport, TChain, TAccount>,
args: SendUserOperationParameters<TAccount, TContext>
): Promise<CheckGasSponsorshipEligibilityResult<TAccount>> {
const client = clientHeaderTrack(client_, "checkGasSponsorshipEligibility");
const { account = client.account, overrides, context } = args;

if (!account) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type {
DropAndReplaceUserOperationParameters,
UserOperationContext,
} from "./types";
import { clientHeaderTrack } from "../../index.js";

/**
* Drops an existing user operation and replaces it with a new one while ensuring the appropriate fees and overrides are applied.
Expand All @@ -42,7 +43,7 @@ import type {
* });
* ```
*
* @param {Client<TTransport, TChain, TAccount>} client The client instance with the transport, chain, and account information
* @param {Client<TTransport, TChain, TAccount>} client_ The client instance with the transport, chain, and account information
* @param {DropAndReplaceUserOperationParameters<TAccount, TContext>} args The parameters required for dropping and replacing the user operation including the account, operation to drop, overrides, and context
* @returns {Promise<SendUserOperationResult<TEntryPointVersion>>} A promise that resolves to the result of sending the new user operation
*/
Expand All @@ -57,9 +58,10 @@ export async function dropAndReplaceUserOperation<
| undefined,
TEntryPointVersion extends GetEntryPointFromAccount<TAccount> = GetEntryPointFromAccount<TAccount>
>(
client: Client<TTransport, TChain, TAccount>,
client_: Client<TTransport, TChain, TAccount>,
args: DropAndReplaceUserOperationParameters<TAccount, TContext>
): Promise<SendUserOperationResult<TEntryPointVersion>> {
const client = clientHeaderTrack(client_, "dropAndReplaceUserOperation");
const { account = client.account, uoToDrop, overrides, context } = args;
if (!account) {
throw new AccountNotFoundError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
SendUserOperationParameters,
UserOperationContext,
} from "./types.js";
import { clientHeaderTrack } from "../../index.js";

/**
* Description SmartAccountClientAction for estimating the gas cost of a user operation
Expand All @@ -23,7 +24,7 @@ import type {
* @template {SmartContractAccount | undefined} TAccount
* @template {UserOperationContext | undefined} TContext
* @template {GetEntryPointFromAccount<TAccount>} TEntryPointVersion
* @param {Client<TTransport, TChain, TAccount>} client smart account client
* @param {Client<TTransport, TChain, TAccount>} client_ smart account client
* @param {SendUserOperationParameters<TAccount, TContext>} args send user operation parameters
* @returns {Promise<UserOperationEstimateGasResponse<TEntryPointVersion>>}user operation gas estimate response
*/
Expand All @@ -38,9 +39,10 @@ export async function estimateUserOperationGas<
| undefined,
TEntryPointVersion extends GetEntryPointFromAccount<TAccount> = GetEntryPointFromAccount<TAccount>
>(
client: Client<TTransport, TChain, TAccount>,
client_: Client<TTransport, TChain, TAccount>,
args: SendUserOperationParameters<TAccount, TContext>
): Promise<UserOperationEstimateGasResponse<TEntryPointVersion>> {
const client = clientHeaderTrack(client_, "estimateUserOperationGas");
const { account = client.account, overrides } = args;
if (!account) {
throw new AccountNotFoundError();
Expand Down
6 changes: 4 additions & 2 deletions aa-sdk/core/src/actions/smartAccount/sendTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { buildUserOperationFromTx } from "./buildUserOperationFromTx.js";
import { _sendUserOperation } from "./internal/sendUserOperation.js";
import type { UserOperationContext } from "./types.js";
import { waitForUserOperationTransaction } from "./waitForUserOperationTransacation.js";
import { clientHeaderTrack } from "../../index.js";

/**
* Sends a transaction using the provided client, arguments, optional overrides, and context.
Expand All @@ -38,7 +39,7 @@ import { waitForUserOperationTransaction } from "./waitForUserOperationTransacat
* });
* ```
*
* @param {Client<Transport, TChain, TAccount>} client The client to send the transaction through
* @param {Client<Transport, TChain, TAccount>} client_ The client to send the transaction through
* @param {SendTransactionParameters<TChain, TAccount, TChainOverride>} args The parameters required to send the transaction
* @param {UserOperationOverrides<TEntryPointVersion>} [overrides] Optional overrides for the user operation
* @param {UserOperationContext} [context] Optional context for the user operation
Expand All @@ -55,11 +56,12 @@ export async function sendTransaction<
| undefined,
TEntryPointVersion extends GetEntryPointFromAccount<TAccount> = GetEntryPointFromAccount<TAccount>
>(
client: Client<Transport, TChain, TAccount>,
client_: Client<Transport, TChain, TAccount>,
args: SendTransactionParameters<TChain, TAccount, TChainOverride>,
overrides?: UserOperationOverrides<TEntryPointVersion>,
context?: TContext
): Promise<Hex> {
const client = clientHeaderTrack(client_, "estimateUserOperationGas");
const { account = client.account } = args;
if (!account || typeof account === "string") {
throw new AccountNotFoundError();
Expand Down
6 changes: 4 additions & 2 deletions aa-sdk/core/src/actions/smartAccount/sendTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { buildUserOperationFromTxs } from "./buildUserOperationFromTxs.js";
import { _sendUserOperation } from "./internal/sendUserOperation.js";
import type { SendTransactionsParameters, UserOperationContext } from "./types";
import { waitForUserOperationTransaction } from "./waitForUserOperationTransacation.js";
import { clientHeaderTrack } from "../../index.js";

/**
* Sends transactions using the provided client and transaction parameters. This function builds user operations from the transactions, sends them, and waits for the transaction to be mined.
Expand All @@ -28,7 +29,7 @@ import { waitForUserOperationTransaction } from "./waitForUserOperationTransacat
* });
* ```
*
* @param {Client<TTransport, TChain, TAccount>} client The client used to send the transactions
* @param {Client<TTransport, TChain, TAccount>} client_ The client used to send the transactions
* @param {SendTransactionsParameters<TAccount, TContext>} args The parameters for sending the transactions, including requests, overrides, account, and context
* @returns {Promise<Hex>} A promise that resolves to the transaction hash of the sent transactions
*/
Expand All @@ -40,9 +41,10 @@ export async function sendTransactions<
| undefined,
TContext extends UserOperationContext | undefined = UserOperationContext
>(
client: Client<TTransport, TChain, TAccount>,
client_: Client<TTransport, TChain, TAccount>,
args: SendTransactionsParameters<TAccount, TContext>
): Promise<Hex> {
const client = clientHeaderTrack(client_, "estimateUserOperationGas");
const { requests, overrides, account = client.account, context } = args;
if (!account) {
throw new AccountNotFoundError();
Expand Down
6 changes: 4 additions & 2 deletions aa-sdk/core/src/actions/smartAccount/sendUserOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
SendUserOperationParameters,
UserOperationContext,
} from "./types.js";
import { clientHeaderTrack } from "../../index.js";

/**
* Sends a user operation or batch of user operations using the connected account. Before executing, sendUserOperation will run the user operation through the middleware pipeline.
Expand All @@ -31,7 +32,7 @@ import type {
* });
* ```
*
* @param {Client<TTransport, TChain, TAccount>} client the smart account client to use for RPC requests
* @param {Client<TTransport, TChain, TAccount>} client_ the smart account client to use for RPC requests
* @param {SendUserOperationParameters<TAccount, TContext>} args contains the UO or batch to send, context, overrides, and account if not hoisted on the client
* @returns {Promise<SendUserOperationResult<TEntryPointVersion>>} a Promise containing the result of the user operation
*/
Expand All @@ -46,9 +47,10 @@ export async function sendUserOperation<
| undefined,
TEntryPointVersion extends GetEntryPointFromAccount<TAccount> = GetEntryPointFromAccount<TAccount>
>(
client: Client<TTransport, TChain, TAccount>,
client_: Client<TTransport, TChain, TAccount>,
args: SendUserOperationParameters<TAccount, TContext>
): Promise<SendUserOperationResult<TEntryPointVersion>> {
const client = clientHeaderTrack(client_, "sendUserOperation");
const { account = client.account, context, overrides } = args;

if (!account) {
Expand Down
4 changes: 3 additions & 1 deletion aa-sdk/core/src/actions/smartAccount/upgradeAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { IncompatibleClientError } from "../../errors/client.js";
import { sendUserOperation } from "./sendUserOperation.js";
import type { UpgradeAccountParams, UserOperationContext } from "./types.js";
import { waitForUserOperationTransaction } from "./waitForUserOperationTransacation.js";
import { clientHeaderTrack } from "../../index.js";

export const upgradeAccount: <
TTransport extends Transport = Transport,
Expand All @@ -19,7 +20,8 @@ export const upgradeAccount: <
>(
client: Client<TTransport, TChain, TAccount>,
args: UpgradeAccountParams<TAccount, TContext>
) => Promise<Hash> = async (client, args) => {
) => Promise<Hash> = async (client_, args) => {
const client = clientHeaderTrack(client_, "upgradeAccount");
const {
account = client.account,
upgradeTo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IncompatibleClientError } from "../../errors/client.js";
import { FailedToFindTransactionError } from "../../errors/transaction.js";
import { Logger } from "../../logger.js";
import type { WaitForUserOperationTxParameters } from "./types.js";
import { clientHeaderTrack } from "../../index.js";

/**
* Waits for a user operation transaction to be confirmed by checking the receipt periodically until it is found or a maximum number of retries is reached.
Expand All @@ -20,7 +21,7 @@ import type { WaitForUserOperationTxParameters } from "./types.js";
* });
* ```
*
* @param {Client<TTransport, TChain, any>} client The client instance used to interact with the blockchain
* @param {Client<TTransport, TChain, any>} client_ The client instance used to interact with the blockchain
* @param {WaitForUserOperationTxParameters} args The parameters for the transaction to wait for
* @param {Hex} args.hash The transaction hash to wait for
* @param {WaitForUserOperationTxParameters["retries"]} [args.retries] Optional retry parameters
Expand All @@ -35,7 +36,8 @@ export const waitForUserOperationTransaction: <
>(
client: Client<TTransport, TChain, any>,
args: WaitForUserOperationTxParameters
) => Promise<Hex> = async (client, args) => {
) => Promise<Hex> = async (client_, args) => {
const client = clientHeaderTrack(client_, "waitForUserOperationTransaction");
if (!isBaseSmartAccountClient(client)) {
throw new IncompatibleClientError(
"BaseSmartAccountClient",
Expand Down
41 changes: 41 additions & 0 deletions aa-sdk/core/src/client/updateHeaders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export const UPDATE_HEADER = Symbol("updateHeader");
export type UpdateHeaderFn = (
previous: Record<string, string>
) => Record<string, string>;

export type UpdateHeader<T> = {
[UPDATE_HEADER]<This extends T>(this: This, update: UpdateHeaderFn): This;
};

export const TRACKER_HEADER = "X-Alchemy-Trace-Id";
export const TRACKER_BREADCRUMB = "X-Alchemy-Trace-Breadcrumb";

function addCrumb(previous: string | undefined, crumb: string): string {
return previous ? `${previous} - ${crumb}` : crumb;
}

function hasUpdateHeader<A extends {}>(a: A): a is A & UpdateHeader<A> {
return UPDATE_HEADER in a;
}

function maybeUpdateHeader<A extends {}>(
a: A,
updateHeader: UpdateHeaderFn
): A {
if (hasUpdateHeader(a)) {
return a[UPDATE_HEADER](updateHeader);
}
return a;
}

export function clientHeaderTrack<X extends {}>(client: X, crumb: string): X {
return maybeUpdateHeader(client, headersUpdate(crumb));
}
export function headersUpdate(crumb: string): UpdateHeaderFn {
const headerUpdate_ = (x: Record<string, string>) => ({
[TRACKER_HEADER]: Math.random().toString(36).substring(10),
...x,
[TRACKER_BREADCRUMB]: addCrumb(x[TRACKER_BREADCRUMB], crumb),
});
return headerUpdate_;
}
5 changes: 5 additions & 0 deletions aa-sdk/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export {
InvalidUserOperationError,
WaitForUserOperationError,
} from "./errors/useroperation.js";
export * from "./client/updateHeaders.js";
export { LogLevel, Logger } from "./logger.js";
export { middlewareActions } from "./middleware/actions.js";
export { default7702UserOpSigner } from "./middleware/defaults/7702signer.js";
Expand All @@ -112,6 +113,10 @@ export type {
export { wrapSignatureWith6492 } from "./signer/utils.js";
export { WalletClientSigner } from "./signer/wallet-client.js";
export { split, type SplitTransportParams } from "./transport/split.js";
export {
tracingHeader,
type TracingHeadersParams,
} from "./transport/tracingHeader.js";
export type * from "./types.js";
export type * from "./utils/index.js";
export {
Expand Down
Loading
Loading