Skip to content

Commit 8fefa99

Browse files
authored
feat: sync methods (#4)
1 parent 80cf422 commit 8fefa99

9 files changed

Lines changed: 178 additions & 5 deletions

File tree

src/account/actions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './getFeeQuote.js';
22
export * from './sendTransaction.js';
3+
export * from './sendTransactionSync.js';
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import type { SmartAccount } from 'viem/account-abstraction';
2+
import type {
3+
CapabilitiesByChain,
4+
GelatoEvmRelayerClient,
5+
TerminalStatus
6+
} from '../../relayer/index.js';
7+
import { PaymentType } from '../../types/index.js';
8+
import { appendPayment } from '../../utils/index.js';
9+
import type { GelatoSmartAccountImplementation } from '../adapters/types/index.js';
10+
import { getFeeQuote } from './getFeeQuote.js';
11+
import type { SendTransactionParameters } from './sendTransaction.js';
12+
13+
export type SendTransactionSyncParameters = SendTransactionParameters & {
14+
timeout: number;
15+
};
16+
17+
export const sendTransactionSync = async (
18+
client: GelatoEvmRelayerClient,
19+
account: SmartAccount<GelatoSmartAccountImplementation>,
20+
capabilities: CapabilitiesByChain,
21+
parameters: SendTransactionSyncParameters
22+
): Promise<TerminalStatus> => {
23+
const { payment, timeout } = parameters;
24+
25+
const [quote, nonce, deployed] = await Promise.all([
26+
payment.type === PaymentType.Token
27+
? (parameters.quote ?? (await getFeeQuote(client, account, capabilities, parameters)))
28+
: undefined,
29+
parameters.nonce ?? account.getNonce({ key: parameters.nonceKey }),
30+
account.isDeployed()
31+
]);
32+
33+
const calls = quote
34+
? appendPayment(parameters.calls, quote.token.address, capabilities.feeCollector, quote.fee)
35+
: parameters.calls;
36+
37+
const [data, authorizationList] = await Promise.all([
38+
account.encodeCallData({ calls, nonce }),
39+
deployed ? undefined : account.signAuthorization().then((x) => [x])
40+
]);
41+
42+
return await client.sendTransactionSync({
43+
authorizationList,
44+
chainId: account.chain.id,
45+
context: quote?.context,
46+
data,
47+
payment,
48+
timeout,
49+
to: account.address
50+
});
51+
};

src/account/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ import type { SmartAccount } from 'viem/account-abstraction';
33
import {
44
createGelatoEvmRelayerClient,
55
type FeeQuote,
6-
type GelatoEvmRelayerClient
6+
type GelatoEvmRelayerClient,
7+
type TerminalStatus
78
} from '../relayer/index.js';
89
import {
910
type GetFeeQuoteParameters,
1011
getFeeQuote,
1112
type SendTransactionParameters,
12-
sendTransaction
13+
type SendTransactionSyncParameters,
14+
sendTransaction,
15+
sendTransactionSync
1316
} from './actions/index.js';
1417
import type { GelatoSmartAccountImplementation } from './adapters/types/index.js';
1518

@@ -20,6 +23,7 @@ export type GelatoSmartAccountClient = Pick<
2023
'getCapabilities' | 'getStatus' | 'waitForStatus'
2124
> & {
2225
sendTransaction: (parameters: SendTransactionParameters) => Promise<Hex>;
26+
sendTransactionSync: (parameters: SendTransactionSyncParameters) => Promise<TerminalStatus>;
2327
getFeeQuote: (parameters: GetFeeQuoteParameters) => Promise<FeeQuote>;
2428
};
2529

@@ -49,6 +53,8 @@ export const createGelatoSmartAccountClient = async (
4953
getFeeQuote: (parameters) => getFeeQuote(client, account, capabilities, parameters),
5054
getStatus: (parameters) => client.getStatus(parameters),
5155
sendTransaction: (parameters) => sendTransaction(client, account, capabilities, parameters),
56+
sendTransactionSync: (parameters) =>
57+
sendTransactionSync(client, account, capabilities, parameters),
5258
waitForStatus: (parameters) => client.waitForStatus(parameters)
5359
};
5460
};

src/bundler/actions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from './getUserOperationGasPrice.js';
33
export * from './getUserOperationQuote.js';
44
export * from './prepareUserOperation.js';
55
export * from './sendUserOperation.js';
6+
export * from './sendUserOperationSync.js';
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import type { BaseError, Chain, Client, Transport } from 'viem';
2+
import {
3+
formatUserOperationReceipt,
4+
formatUserOperationRequest,
5+
getUserOperationError,
6+
type PrepareUserOperationParameters,
7+
type SendUserOperationParameters,
8+
type SmartAccount,
9+
type UserOperation,
10+
type UserOperationReceipt
11+
} from 'viem/account-abstraction';
12+
import { parseAccount } from 'viem/accounts';
13+
import type { CapabilitiesByChain } from '../../relayer/evm/actions/index.js';
14+
import { AccountNotFoundError, type Payment } from '../../types/index.js';
15+
import { prepareUserOperation } from './prepareUserOperation.js';
16+
17+
export type SendUserOperationSyncParameters = SendUserOperationParameters & {
18+
timeout: number;
19+
};
20+
21+
export const sendUserOperationSync = async <account extends SmartAccount | undefined>(
22+
client: Client<Transport, Chain | undefined, account>,
23+
parameters: SendUserOperationSyncParameters,
24+
capabilities: CapabilitiesByChain,
25+
payment?: Payment
26+
): Promise<UserOperationReceipt> => {
27+
const { account: account_ = client.account, entryPointAddress, timeout } = parameters;
28+
29+
if (!account_ && !parameters.sender) throw new AccountNotFoundError();
30+
const account = account_ ? parseAccount(account_) : undefined;
31+
32+
const request = account
33+
? await prepareUserOperation(
34+
client,
35+
parameters as unknown as PrepareUserOperationParameters,
36+
capabilities,
37+
payment,
38+
true
39+
)
40+
: parameters;
41+
42+
// biome-ignore lint/style/noNonNullAssertion: copied from viem
43+
const signature = (parameters.signature ||
44+
(await account?.signUserOperation?.(request as UserOperation)))!;
45+
46+
const rpcParameters = formatUserOperationRequest({
47+
...request,
48+
signature
49+
} as UserOperation);
50+
51+
try {
52+
const receipt = await client.request(
53+
{
54+
method: 'eth_sendUserOperationSync',
55+
// biome-ignore lint/style/noNonNullAssertion: copied from viem
56+
params: [rpcParameters, (entryPointAddress ?? account?.entryPoint?.address)!, { timeout }]
57+
} as never,
58+
{ retryCount: 0 }
59+
);
60+
61+
return formatUserOperationReceipt(receipt);
62+
} catch (error) {
63+
// biome-ignore lint/suspicious/noExplicitAny: copied from viem
64+
const calls = (parameters as any).calls;
65+
throw getUserOperationError(error as BaseError, {
66+
...(request as UserOperation),
67+
...(calls ? { calls } : {}),
68+
signature
69+
});
70+
}
71+
};

src/bundler/index.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {
33
type BundlerActions,
44
type BundlerClient,
55
type BundlerClientConfig,
6-
createBundlerClient
6+
createBundlerClient,
7+
type UserOperationReceipt
78
} from 'viem/account-abstraction';
89
import { GELATO_PROD_API, GELATO_STAGING_API } from '../relayer/constants/index.js';
910
import { getCapabilities } from '../relayer/evm/actions/index.js';
@@ -16,12 +17,17 @@ import {
1617
getUserOperationGasPrice,
1718
getUserOperationQuote,
1819
prepareUserOperation,
19-
sendUserOperation
20+
type SendUserOperationSyncParameters,
21+
sendUserOperation,
22+
sendUserOperationSync
2023
} from './actions/index.js';
2124

2225
export * from './actions/index.js';
2326

2427
export type GelatoBundlerActions = Partial<BundlerActions> & {
28+
sendUserOperationSync: (
29+
parameters: SendUserOperationSyncParameters
30+
) => Promise<UserOperationReceipt>;
2531
getUserOperationGasPrice: () => Promise<GetUserOperationGasPriceReturnType>;
2632
getUserOperationQuote: (
2733
parameters: GetUserOperationQuoteParameters
@@ -84,7 +90,9 @@ export const createGelatoBundlerClient = async (
8490
prepareUserOperation: (parameters) =>
8591
prepareUserOperation(client, parameters, capabilities, payment),
8692
sendUserOperation: (parameters) =>
87-
sendUserOperation(client, parameters, capabilities, payment)
93+
sendUserOperation(client, parameters, capabilities, payment),
94+
sendUserOperationSync: (parameters) =>
95+
sendUserOperationSync(client, parameters, capabilities, payment)
8896
}) as GelatoBundlerActions
8997
) as unknown as GelatoBundlerClient;
9098
};

src/relayer/evm/actions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export * from './getFeeData.js';
33
export * from './getFeeQuote.js';
44
export * from './getStatus.js';
55
export * from './sendTransaction.js';
6+
export * from './sendTransactionSync.js';
67
export * from './waitForStatus.js';
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import type { Transport } from 'viem';
2+
import { formatAuthorization } from '../../../utils/index.js';
3+
import { type TerminalStatus, terminalStatusSchema } from './getStatus.js';
4+
import type { SendTransactionParameters } from './sendTransaction.js';
5+
6+
export type SendTransactionSyncParameters = SendTransactionParameters & {
7+
timeout: number;
8+
};
9+
10+
export const sendTransactionSync = async (
11+
client: ReturnType<Transport>,
12+
parameters: SendTransactionSyncParameters
13+
): Promise<TerminalStatus> => {
14+
const { chainId, data, to, payment, context, authorizationList, timeout } = parameters;
15+
16+
const result = await client.request({
17+
method: 'relayer_sendTransactionSync',
18+
params: {
19+
authorizationList: authorizationList ? authorizationList.map(formatAuthorization) : undefined,
20+
chainId: chainId.toString(),
21+
context,
22+
data,
23+
payment,
24+
timeout,
25+
to
26+
}
27+
});
28+
29+
return terminalStatusSchema.parse(result);
30+
};

src/relayer/evm/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import {
1212
getFeeQuote,
1313
getStatus,
1414
type SendTransactionParameters,
15+
type SendTransactionSyncParameters,
1516
type Status,
1617
sendTransaction,
18+
sendTransactionSync,
1719
type TerminalStatus,
1820
waitForStatus
1921
} from './actions/index.js';
@@ -27,6 +29,7 @@ export type GelatoEvmRelayerClient = {
2729
getStatus: (parameters: GetStatusParameters) => Promise<Status>;
2830
waitForStatus: (parameters: GetStatusParameters) => Promise<TerminalStatus>;
2931
sendTransaction: (parameters: SendTransactionParameters) => Promise<Hex>;
32+
sendTransactionSync: (parameters: SendTransactionSyncParameters) => Promise<TerminalStatus>;
3033
};
3134

3235
export type GelatoEvmRelayerClientConfig = {
@@ -59,6 +62,7 @@ export const createGelatoEvmRelayerClient = (
5962
getFeeQuote: (parameters) => getFeeQuote(client, parameters),
6063
getStatus: (parameters) => getStatus(client, parameters),
6164
sendTransaction: (parameters) => sendTransaction(client, parameters),
65+
sendTransactionSync: (parameters) => sendTransactionSync(client, parameters),
6266
waitForStatus: (parameters) => waitForStatus(client, parameters)
6367
};
6468
};

0 commit comments

Comments
 (0)