Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.

Commit f99498d

Browse files
authored
fix: mini app communication (#514)
* fix: mini-app communications Had a bug where I've constructed posted messages incorrectly, listened to the window.parent instead of the iframe itself, and didn't post messages via window.ReactNativeWebView in case if it's loaded in a react native webview. * chore: changesets * fix: send tx params to convert bigints to strings * nit: listener fix * fix: postjsonrpc * fix: bigint typings * nit: Button.MiniApp to use action prop * nit: lint * nit: add miniApp alias
1 parent 0ced4f7 commit f99498d

File tree

8 files changed

+86
-21
lines changed

8 files changed

+86
-21
lines changed

.changeset/tender-radios-mate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"frog": patch
3+
---
4+
5+
Fixed an issue with incorrect JSON-RPC parameters sent for `sendTransaction` and `signTypedDate` for mini-apps. Also fixed and improved communication between the mini-app and the parent.

src/components/Button.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export function ButtonLink({
9292
}
9393

9494
export type ButtonMiniAppProps = ButtonProps & {
95-
href: string
95+
action: string
9696
prompt?: boolean
9797
}
9898

@@ -101,7 +101,7 @@ export function ButtonMiniApp({
101101
children,
102102
// @ts-ignore - private
103103
index = 1,
104-
href,
104+
action,
105105
prompt,
106106
}: ButtonMiniAppProps) {
107107
return [
@@ -113,7 +113,7 @@ export function ButtonMiniApp({
113113
<meta property={`fc:frame:button:${index}:action`} content="link" />,
114114
<meta
115115
property={`fc:frame:button:${index}:target`}
116-
content={`https://warpcast.com/~/composer-action?url=${encodeURIComponent(href)}${prompt ? '&view=prompt' : ''}`}
116+
content={`https://warpcast.com/~/composer-action?url=${encodeURIComponent(action)}${prompt ? '&view=prompt' : ''}`}
117117
/>,
118118
] as unknown as HtmlEscapedString
119119
}

src/frog-base.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,9 @@ export class FrogBase<
11291129
return this
11301130
}
11311131

1132+
miniApp: HandlerInterface<env, 'composerAction', schema, basePath> =
1133+
this.composerAction
1134+
11321135
route<
11331136
subPath extends string,
11341137
subSchema extends Schema,

src/utils/getSignatureContext.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,11 @@ export async function getSignatureContext<
9292
domain,
9393
types,
9494
primaryType,
95-
// @TODO: fix typing
96-
message: message!,
95+
message: JSON.parse(
96+
JSON.stringify(message, (_, v) =>
97+
typeof v === 'bigint' ? v.toString() : v,
98+
),
99+
),
97100
},
98101
}
99102

src/web/actions/internal/jsonRpc/listenForJsonRpcResponseMessage.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@ export function listenForJsonRpcResponseMessage<resultType>(
1616
JsonRpcResponseSuccess<resultType> | JsonRpcResponseFailure
1717
>,
1818
) => {
19-
if (event.data.id !== requestId) return
20-
19+
if (
20+
event.data.id !== requestId ||
21+
!('result' in event.data || 'error' in event.data)
22+
)
23+
return
2124
handler(event.data)
2225
}
2326

24-
window.parent.addEventListener('message', listener)
27+
window.addEventListener('message', listener)
2528

26-
return () => window.parent.removeEventListener('message', listener)
29+
return () => window.removeEventListener('message', listener)
2730
}

src/web/actions/internal/jsonRpc/postJsonRpcRequestMessage.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,28 @@ export function postJsonRpcRequestMessage(
1313
)
1414

1515
const requestId = requestIdOverride ?? crypto.randomUUID()
16-
window.parent.postMessage(
17-
{
18-
jsonrpc: '2.0',
19-
id: requestId,
20-
method,
21-
params: parameters,
22-
},
23-
'*',
24-
)
16+
const message = {
17+
jsonrpc: '2.0',
18+
id: requestId,
19+
method,
20+
params: parameters,
21+
}
22+
23+
// ref: https://github.com/react-native-webview/react-native-webview/blob/master/docs/Guide.md#the-windowreactnativewebviewpostmessage-method-and-onmessage-prop
24+
if (
25+
(
26+
window as {
27+
ReactNativeWebView?: any
28+
}
29+
).ReactNativeWebView
30+
) {
31+
;(
32+
window as {
33+
ReactNativeWebView?: { postMessage: (msg: string) => void }
34+
}
35+
).ReactNativeWebView?.postMessage(JSON.stringify(message))
36+
} else {
37+
window.parent.postMessage(message, '*')
38+
}
2539
return requestId
2640
}

src/web/actions/internal/postSendTransactionRequestMessage.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import type { SendTransactionParameters } from '../../../types/transaction.js'
1+
import type {
2+
EthSendTransactionParameters,
3+
SendTransactionParameters,
4+
} from '../../../types/transaction.js'
25
import {
36
type PostJsonRpcRequestMessageReturnType,
47
postJsonRpcRequestMessage,
@@ -12,9 +15,27 @@ export function postSendTransactionRequestMessage(
1215
parameters: SendTransactionRequestMessageParameters,
1316
requestIdOverride?: string,
1417
) {
18+
const { chainId, attribution, abi, data, gas, to, value } = parameters
19+
20+
const sendTransactionParams: EthSendTransactionParameters<string> = {
21+
abi,
22+
data,
23+
to,
24+
}
25+
26+
if (gas) sendTransactionParams.gas = gas.toString()
27+
if (value) sendTransactionParams.value = value.toString()
28+
1529
return postJsonRpcRequestMessage(
1630
'fc_requestWalletAction',
17-
parameters,
31+
{
32+
action: {
33+
method: 'eth_sendTransaction',
34+
attribution,
35+
chainId,
36+
params: sendTransactionParams,
37+
},
38+
},
1839
requestIdOverride,
1940
)
2041
}

src/web/actions/internal/postSignTypedDataRequestMessage.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,25 @@ export function postSignTypedDataRequestMessage<
1919
parameters: SignTypedDataRequestMessageParameters<typedData, primaryType>,
2020
requestIdOverride?: string,
2121
) {
22+
const { chainId, domain, message, types, primaryType } = parameters
2223
return postJsonRpcRequestMessage(
2324
'fc_requestWalletAction',
24-
parameters,
25+
{
26+
action: {
27+
method: 'eth_signTypedData_v4',
28+
chainId,
29+
params: {
30+
domain,
31+
message: JSON.parse(
32+
JSON.stringify(message, (_, v) =>
33+
typeof v === 'bigint' ? v.toString() : v,
34+
),
35+
),
36+
types,
37+
primaryType,
38+
},
39+
},
40+
},
2541
requestIdOverride,
2642
)
2743
}

0 commit comments

Comments
 (0)