Skip to content

Commit 6d5c8c8

Browse files
authored
Fix Universal Wallet Gas Sponsorship (#610)
* Pass project access key in Account sendTransactions and prepareTransactions so that sponsored transactions will return the correct fee options and allow sending * Adjust prompter method interfaces to accept origin * Pass project access key with each request
1 parent 9c1355c commit 6d5c8c8

9 files changed

Lines changed: 98 additions & 45 deletions

File tree

packages/account/src/account.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -880,18 +880,19 @@ export class Account {
880880
chainId: ethers.BigNumberish,
881881
quote?: FeeQuote,
882882
pstatus?: AccountStatus,
883-
callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void
883+
callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void,
884+
projectAccessKey?: string
884885
): Promise<ethers.TransactionResponse> {
885886
if (!Array.isArray(signedBundle)) {
886-
return this.sendSignedTransactions([signedBundle], chainId, quote, pstatus, callback)
887+
return this.sendSignedTransactions([signedBundle], chainId, quote, pstatus, callback, projectAccessKey)
887888
}
888889
const status = pstatus || (await this.status(chainId))
889890
this.mustBeFullyMigrated(status)
890891

891892
const decoratedBundle = await this.decorateTransactions(signedBundle, status, chainId)
892893
callback?.(decoratedBundle)
893894

894-
return this.relayer(chainId).relay(decoratedBundle, quote)
895+
return this.relayer(chainId).relay(decoratedBundle, quote, undefined, projectAccessKey)
895896
}
896897

897898
async fillGasLimits(
@@ -910,6 +911,7 @@ export class Account {
910911
status?: AccountStatus,
911912
options?: {
912913
simulate?: boolean
914+
projectAccessKey?: string
913915
}
914916
): Promise<{
915917
options: FeeOption[]
@@ -952,12 +954,14 @@ export class Account {
952954
chainId: ethers.BigNumberish
953955
stubSignatureOverrides: Map<string, string>
954956
simulateForFeeOptions?: boolean
957+
projectAccessKey?: string
955958
}): Promise<PreparedTransactions> {
956959
const status = await this.status(args.chainId)
957960

958961
const transactions = await this.fillGasLimits(args.txs, args.chainId, status)
959962
const gasRefundQuote = await this.gasRefundQuotes(transactions, args.chainId, args.stubSignatureOverrides, status, {
960-
simulate: args.simulateForFeeOptions
963+
simulate: args.simulateForFeeOptions,
964+
projectAccessKey: args.projectAccessKey
961965
})
962966
const flatDecorated = commons.transaction.unwind(this.address, gasRefundQuote.decorated.transactions)
963967

@@ -978,6 +982,7 @@ export class Account {
978982
options?: {
979983
nonceSpace?: ethers.BigNumberish
980984
serial?: boolean
985+
projectAccessKey?: string
981986
}
982987
): Promise<ethers.TransactionResponse | undefined> {
983988
const status = await this.status(chainId)
@@ -994,7 +999,7 @@ export class Account {
994999
}
9951000
bundles.push(...childBundles.filter(b => b.transactions.length > 0))
9961001

997-
return this.sendSignedTransactions(bundles, chainId, quote, undefined, callback)
1002+
return this.sendSignedTransactions(bundles, chainId, quote, undefined, callback, options?.projectAccessKey)
9981003
}
9991004

10001005
async signTypedData(

packages/provider/src/transports/base-provider-transport.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,14 @@ export abstract class BaseProviderTransport implements ProviderTransport {
4646
protected _init: InitState
4747
protected _registered: boolean
4848

49-
constructor() {
49+
readonly projectAccessKey?: string
50+
51+
constructor(projectAccessKey?: string) {
5052
this.state = OpenState.CLOSED
5153
this._registered = false
5254
this._init = InitState.NIL
55+
56+
this.projectAccessKey = projectAccessKey
5357
}
5458

5559
get registered(): boolean {
@@ -113,7 +117,8 @@ export abstract class BaseProviderTransport implements ProviderTransport {
113117
type: EventType.MESSAGE,
114118
data: request,
115119
chainId: request.chainId,
116-
clientVersion: VERSION
120+
clientVersion: VERSION,
121+
projectAccessKey: this.projectAccessKey
117122
})
118123

119124
return response.data

packages/provider/src/transports/mux-transport/mux-message-provider.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,19 @@ export function isMuxTransportTemplate(obj: any): obj is MuxTransportTemplate {
6161
export class MuxMessageProvider implements ProviderTransport {
6262
private messageProviders: ProviderTransport[]
6363
private provider: ProviderTransport | undefined
64+
private projectAccessKey?: string
6465

65-
constructor(...messageProviders: ProviderTransport[]) {
66+
constructor(messageProviders: ProviderTransport[] = [], projectAccessKey?: string) {
6667
this.messageProviders = messageProviders
6768
this.provider = undefined
69+
this.projectAccessKey = projectAccessKey
6870
}
6971

70-
static new(template: MuxTransportTemplate): MuxMessageProvider {
72+
static new(template: MuxTransportTemplate, projectAccessKey?: string): MuxMessageProvider {
7173
const muxMessageProvider = new MuxMessageProvider()
7274

7375
if (template.windowTransport?.enabled && typeof window === 'object' && template.walletAppURL) {
74-
const windowMessageProvider = new WindowMessageProvider(template.walletAppURL)
76+
const windowMessageProvider = new WindowMessageProvider(template.walletAppURL, projectAccessKey)
7577
muxMessageProvider.add(windowMessageProvider)
7678
}
7779

packages/provider/src/transports/wallet-request-handler.ts

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,9 @@ export class WalletRequestHandler implements EIP1193Provider, ProviderMessageReq
226226
const result = await this.request({
227227
method: message.data.method,
228228
params: message.data.params,
229-
chainId: message.chainId
229+
chainId: message.chainId,
230+
origin: message.origin,
231+
projectAccessKey: message.projectAccessKey
230232
})
231233

232234
return {
@@ -241,7 +243,13 @@ export class WalletRequestHandler implements EIP1193Provider, ProviderMessageReq
241243
}
242244
}
243245

244-
async request(request: { method: string; params?: any[]; chainId?: number }): Promise<any> {
246+
async request(request: {
247+
method: string
248+
params?: any[]
249+
chainId?: number
250+
origin?: string
251+
projectAccessKey?: string
252+
}): Promise<any> {
245253
await this.getAccount()
246254

247255
try {
@@ -344,7 +352,8 @@ export class WalletRequestHandler implements EIP1193Provider, ProviderMessageReq
344352
message: ethers.getBytes(prefixedMessage),
345353
eip6492: sequenceVerified
346354
},
347-
this.connectOptions
355+
request.origin,
356+
request.projectAccessKey
348357
)
349358
}
350359

@@ -397,7 +406,8 @@ export class WalletRequestHandler implements EIP1193Provider, ProviderMessageReq
397406
typedData: typedData,
398407
eip6492: sequenceVerified
399408
},
400-
this.connectOptions
409+
request.origin,
410+
request.projectAccessKey
401411
)
402412
}
403413

@@ -431,7 +441,12 @@ export class WalletRequestHandler implements EIP1193Provider, ProviderMessageReq
431441
txnHash = txnResponse?.hash ?? ''
432442
} else {
433443
// prompt user to provide the response
434-
txnHash = await this.prompter.promptSendTransaction(transactionParams, request.chainId, this.connectOptions)
444+
txnHash = await this.prompter.promptSendTransaction(
445+
transactionParams,
446+
request.chainId,
447+
request.origin,
448+
request.projectAccessKey
449+
)
435450
}
436451

437452
if (txnHash) {
@@ -461,7 +476,12 @@ export class WalletRequestHandler implements EIP1193Provider, ProviderMessageReq
461476
// we will want to resolveProperties the big number values to hex strings
462477
return await account.signTransactions(transaction, request.chainId ?? this.defaultChainId())
463478
} else {
464-
return await this.prompter.promptSignTransaction(transaction, request.chainId, this.connectOptions)
479+
return await this.prompter.promptSignTransaction(
480+
transaction,
481+
request.chainId,
482+
request.origin,
483+
request.projectAccessKey
484+
)
465485
}
466486
}
467487

@@ -800,7 +820,8 @@ export class WalletRequestHandler implements EIP1193Provider, ProviderMessageReq
800820
prompter: WalletUserPrompter,
801821
account: Account,
802822
sequenceVerified: boolean,
803-
chainId?: number
823+
chainId?: number,
824+
origin?: string
804825
): Promise<boolean> {
805826
// check if wallet is deployed and up to date, if not, prompt user to deploy
806827
// if no chainId is provided, we'll assume the wallet is auth chain wallet and is up to date
@@ -817,7 +838,7 @@ export class WalletRequestHandler implements EIP1193Provider, ProviderMessageReq
817838
return true
818839
}
819840

820-
const promptResult = await prompter.promptConfirmWalletDeploy(chainId, this.connectOptions)
841+
const promptResult = await prompter.promptConfirmWalletDeploy(chainId, origin)
821842

822843
// if client returned true, check again to make sure wallet is deployed and up to date
823844
if (promptResult) {
@@ -837,15 +858,22 @@ export class WalletRequestHandler implements EIP1193Provider, ProviderMessageReq
837858

838859
export interface WalletUserPrompter {
839860
getDefaultChainId(): number
840-
841-
promptConnect(options?: ConnectOptions): Promise<PromptConnectDetails>
842-
promptSignInConnect(options?: ConnectOptions): Promise<PromptConnectDetails>
843-
844-
promptSignMessage(message: MessageToSign, options?: ConnectOptions): Promise<string>
845-
promptSignTransaction(txn: commons.transaction.Transactionish, chainId?: number, options?: ConnectOptions): Promise<string>
846-
promptSendTransaction(txn: commons.transaction.Transactionish, chainId?: number, options?: ConnectOptions): Promise<string>
847-
promptConfirmWalletDeploy(chainId: number, options?: ConnectOptions): Promise<boolean>
848-
861+
promptConnect(connectOptions?: ConnectOptions): Promise<PromptConnectDetails>
862+
promptSignInConnect(connectOptions?: ConnectOptions): Promise<PromptConnectDetails>
863+
promptSignMessage(message: MessageToSign, origin?: string, projectAccessKey?: string): Promise<string>
864+
promptSignTransaction(
865+
txn: commons.transaction.Transactionish,
866+
chainId?: number,
867+
origin?: string,
868+
projectAccessKey?: string
869+
): Promise<string>
870+
promptSendTransaction(
871+
txn: commons.transaction.Transactionish,
872+
chainId?: number,
873+
origin?: string,
874+
projectAccessKey?: string
875+
): Promise<string>
876+
promptConfirmWalletDeploy(chainId: number, origin?: string): Promise<boolean>
849877
promptChangeNetwork(chainId: number): Promise<boolean>
850878
}
851879

packages/provider/src/transports/window-transport/window-message-handler.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ export class WindowMessageHandler extends BaseWalletTransport {
9999
return
100100
}
101101

102+
// Set the origin on the request
103+
request.origin ??= event.origin
104+
102105
logger.debug('RECEIVED MESSAGE', request)
103106

104107
// Record event origin for valid init ack

packages/provider/src/transports/window-transport/window-message-provider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export class WindowMessageProvider extends BaseProviderTransport {
1010
private walletURL: URL
1111
private walletWindow: Window | null
1212

13-
constructor(walletAppURL: string) {
14-
super()
13+
constructor(walletAppURL: string, projectAccessKey?: string) {
14+
super(projectAccessKey)
1515
this.walletURL = new URL(walletAppURL)
1616
}
1717

packages/provider/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export interface ProviderMessage<T> {
6262
chainId?: number // chain id which the message is intended
6363
origin?: string // origin of the message
6464
clientVersion: string // client version of the message
65+
projectAccessKey?: string // project access key
6566
}
6667

6768
export type ProviderMessageRequest = ProviderMessage<JsonRpcRequest>

packages/relayer/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ export interface Relayer {
4040
relay(
4141
signedTxs: commons.transaction.IntendedTransactionBundle,
4242
quote?: FeeQuote,
43-
waitForReceipt?: boolean
43+
waitForReceipt?: boolean,
44+
projectAccessKey?: string
4445
): Promise<commons.transaction.TransactionResponse>
4546

4647
// wait for transaction confirmation

packages/relayer/src/rpc-relayer/index.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export class RpcRelayer implements Relayer {
6161
}
6262

6363
// before the request is made
64-
init!.headers = { ...init!.headers, ...headers }
64+
init!.headers = { ...headers, ...init!.headers }
6565

6666
return fetch(input, init)
6767
}
@@ -160,14 +160,18 @@ export class RpcRelayer implements Relayer {
160160
data: ethers.BytesLike,
161161
options?: {
162162
simulate?: boolean
163+
projectAccessKey?: string
163164
}
164165
): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
165-
const { options: feeOptions, quote } = await this.service.feeOptions({
166-
wallet: entrypoint,
167-
to: entrypoint,
168-
data: ethers.hexlify(data),
169-
simulate: options?.simulate
170-
})
166+
const { options: feeOptions, quote } = await this.service.feeOptions(
167+
{
168+
wallet: entrypoint,
169+
to: entrypoint,
170+
data: ethers.hexlify(data),
171+
simulate: options?.simulate
172+
},
173+
{ ...(options?.projectAccessKey ? { 'X-Access-Key': options.projectAccessKey } : undefined) }
174+
)
171175

172176
return { options: feeOptions, quote: { _tag: 'FeeQuote', _quote: quote } }
173177
}
@@ -190,7 +194,8 @@ export class RpcRelayer implements Relayer {
190194
async relay(
191195
signedTxs: commons.transaction.IntendedTransactionBundle,
192196
quote?: FeeQuote,
193-
waitForReceipt: boolean = true
197+
waitForReceipt: boolean = true,
198+
projectAccessKey?: string
194199
): Promise<commons.transaction.TransactionResponse<RelayerTxReceipt>> {
195200
logger.info(
196201
`[rpc-relayer/relay] relaying signed meta-transactions ${JSON.stringify(signedTxs, bigintReplacer)} with quote ${JSON.stringify(quote, bigintReplacer)}`
@@ -211,14 +216,17 @@ export class RpcRelayer implements Relayer {
211216
}
212217

213218
const data = commons.transaction.encodeBundleExecData(signedTxs)
214-
const metaTxn = await this.service.sendMetaTxn({
215-
call: {
216-
walletAddress: signedTxs.intent.wallet,
217-
contract: signedTxs.entrypoint,
218-
input: data
219+
const metaTxn = await this.service.sendMetaTxn(
220+
{
221+
call: {
222+
walletAddress: signedTxs.intent.wallet,
223+
contract: signedTxs.entrypoint,
224+
input: data
225+
},
226+
quote: typecheckedQuote
219227
},
220-
quote: typecheckedQuote
221-
})
228+
{ ...(projectAccessKey ? { 'X-Access-Key': projectAccessKey } : undefined) }
229+
)
222230

223231
logger.info(`[rpc-relayer/relay] got relay result ${JSON.stringify(metaTxn, bigintReplacer)}`)
224232

0 commit comments

Comments
 (0)