Skip to content

Commit c307f09

Browse files
committed
Add local relayer with pk
1 parent a2b2b6b commit c307f09

File tree

4 files changed

+94
-2
lines changed

4 files changed

+94
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './relayer'
22
export * as Local from './local'
3+
export * as Pk from './pk-relayer'

packages/wallet/core/src/relayer/local.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { Constants, Payload } from '@0xsequence/wallet-primitives'
12
import { AbiFunction, Address, Bytes, Hex } from 'ox'
23
import { FeeOption, FeeQuote, OperationStatus, Relayer } from './relayer'
3-
import { Constants, Payload } from '@0xsequence/wallet-primitives'
44

55
export interface GenericProvider {
66
sendTransaction(args: { to: string; data: string }): Promise<string>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { Payload } from '@0xsequence/wallet-primitives'
2+
import { Address, Hex, Provider, Secp256k1, TransactionEnvelopeEip1559 } from 'ox'
3+
import { LocalRelayer } from './local'
4+
import { FeeOption, FeeQuote, OperationStatus, Relayer } from './relayer'
5+
6+
export class PkRelayer implements Relayer {
7+
public readonly id = 'pk'
8+
private readonly relayer: LocalRelayer
9+
10+
constructor(
11+
privateKey: Hex.Hex,
12+
private readonly provider: Provider.Provider,
13+
) {
14+
const relayerAddress = Address.fromPublicKey(Secp256k1.getPublicKey({ privateKey }))
15+
this.relayer = new LocalRelayer({
16+
sendTransaction: async (args) => {
17+
const oxArgs = { ...args, to: args.to as `0x${string}`, data: args.data as `0x${string}` }
18+
// Estimate gas with a safety buffer
19+
const estimatedGas = BigInt(await this.provider.request({ method: 'eth_estimateGas', params: [oxArgs] }))
20+
const safeGasLimit = estimatedGas > 21000n ? (estimatedGas * 12n) / 10n : 50000n
21+
22+
// Get base fee and priority fee
23+
const baseFee = BigInt(await this.provider.request({ method: 'eth_gasPrice' }))
24+
const priorityFee = 100000000n // 0.1 gwei priority fee
25+
const maxFeePerGas = baseFee + priorityFee
26+
27+
// Check sender have enough balance
28+
const senderBalance = BigInt(
29+
await this.provider.request({ method: 'eth_getBalance', params: [relayerAddress, 'latest'] }),
30+
)
31+
if (senderBalance < maxFeePerGas * safeGasLimit) {
32+
console.log('Sender balance:', senderBalance.toString(), 'wei')
33+
throw new Error('Sender has insufficient balance to pay for gas')
34+
}
35+
const nonce = BigInt(
36+
await this.provider.request({
37+
method: 'eth_getTransactionCount',
38+
params: [relayerAddress, 'latest'],
39+
}),
40+
)
41+
42+
// Build the relay envelope
43+
const chainId = BigInt(await this.provider.request({ method: 'eth_chainId' }))
44+
const relayEnvelope = TransactionEnvelopeEip1559.from({
45+
chainId: Number(chainId),
46+
type: 'eip1559',
47+
from: relayerAddress,
48+
to: oxArgs.to,
49+
data: oxArgs.data,
50+
gas: safeGasLimit,
51+
maxFeePerGas: maxFeePerGas,
52+
maxPriorityFeePerGas: priorityFee,
53+
nonce: nonce,
54+
value: 0n,
55+
})
56+
const relayerSignature = Secp256k1.sign({
57+
payload: TransactionEnvelopeEip1559.getSignPayload(relayEnvelope),
58+
privateKey: privateKey,
59+
})
60+
const signedRelayEnvelope = TransactionEnvelopeEip1559.from(relayEnvelope, {
61+
signature: relayerSignature,
62+
})
63+
const tx = await this.provider.request({
64+
method: 'eth_sendRawTransaction',
65+
params: [TransactionEnvelopeEip1559.serialize(signedRelayEnvelope)],
66+
})
67+
return tx
68+
},
69+
})
70+
}
71+
72+
feeOptions(
73+
wallet: Address.Address,
74+
chainId: bigint,
75+
calls: Payload.Call[],
76+
): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
77+
return this.relayer.feeOptions(wallet, chainId, calls)
78+
}
79+
80+
async relay(to: Address.Address, data: Hex.Hex, chainId: bigint, _?: FeeQuote): Promise<{ opHash: Hex.Hex }> {
81+
const providerChainId = BigInt(await this.provider.request({ method: 'eth_chainId' }))
82+
if (providerChainId !== chainId) {
83+
throw new Error('Provider chain id does not match relayer chain id')
84+
}
85+
return this.relayer.relay(to, data, chainId)
86+
}
87+
88+
status(opHash: Hex.Hex, chainId: bigint): Promise<OperationStatus> {
89+
return this.relayer.status(opHash, chainId)
90+
}
91+
}

packages/wallet/core/src/relayer/relayer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Payload } from '@0xsequence/wallet-primitives'
2-
import { Address, Bytes, Hex } from 'ox'
2+
import { Address, Hex } from 'ox'
33

44
export interface FeeOption {
55
token: Address.Address

0 commit comments

Comments
 (0)