Skip to content

Commit

Permalink
fix: mini app communication (#514)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
dalechyn authored Nov 6, 2024
1 parent 0ced4f7 commit f99498d
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/tender-radios-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"frog": patch
---

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.
6 changes: 3 additions & 3 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export function ButtonLink({
}

export type ButtonMiniAppProps = ButtonProps & {
href: string
action: string
prompt?: boolean
}

Expand All @@ -101,7 +101,7 @@ export function ButtonMiniApp({
children,
// @ts-ignore - private
index = 1,
href,
action,
prompt,
}: ButtonMiniAppProps) {
return [
Expand All @@ -113,7 +113,7 @@ export function ButtonMiniApp({
<meta property={`fc:frame:button:${index}:action`} content="link" />,
<meta
property={`fc:frame:button:${index}:target`}
content={`https://warpcast.com/~/composer-action?url=${encodeURIComponent(href)}${prompt ? '&view=prompt' : ''}`}
content={`https://warpcast.com/~/composer-action?url=${encodeURIComponent(action)}${prompt ? '&view=prompt' : ''}`}
/>,
] as unknown as HtmlEscapedString
}
Expand Down
3 changes: 3 additions & 0 deletions src/frog-base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,9 @@ export class FrogBase<
return this
}

miniApp: HandlerInterface<env, 'composerAction', schema, basePath> =
this.composerAction

route<
subPath extends string,
subSchema extends Schema,
Expand Down
7 changes: 5 additions & 2 deletions src/utils/getSignatureContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,11 @@ export async function getSignatureContext<
domain,
types,
primaryType,
// @TODO: fix typing
message: message!,
message: JSON.parse(
JSON.stringify(message, (_, v) =>
typeof v === 'bigint' ? v.toString() : v,
),
),
},
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ export function listenForJsonRpcResponseMessage<resultType>(
JsonRpcResponseSuccess<resultType> | JsonRpcResponseFailure
>,
) => {
if (event.data.id !== requestId) return

if (
event.data.id !== requestId ||
!('result' in event.data || 'error' in event.data)
)
return
handler(event.data)
}

window.parent.addEventListener('message', listener)
window.addEventListener('message', listener)

return () => window.parent.removeEventListener('message', listener)
return () => window.removeEventListener('message', listener)
}
32 changes: 23 additions & 9 deletions src/web/actions/internal/jsonRpc/postJsonRpcRequestMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,28 @@ export function postJsonRpcRequestMessage(
)

const requestId = requestIdOverride ?? crypto.randomUUID()
window.parent.postMessage(
{
jsonrpc: '2.0',
id: requestId,
method,
params: parameters,
},
'*',
)
const message = {
jsonrpc: '2.0',
id: requestId,
method,
params: parameters,
}

// ref: https://github.com/react-native-webview/react-native-webview/blob/master/docs/Guide.md#the-windowreactnativewebviewpostmessage-method-and-onmessage-prop
if (
(
window as {
ReactNativeWebView?: any
}
).ReactNativeWebView
) {
;(
window as {
ReactNativeWebView?: { postMessage: (msg: string) => void }
}
).ReactNativeWebView?.postMessage(JSON.stringify(message))
} else {
window.parent.postMessage(message, '*')
}
return requestId
}
25 changes: 23 additions & 2 deletions src/web/actions/internal/postSendTransactionRequestMessage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type { SendTransactionParameters } from '../../../types/transaction.js'
import type {
EthSendTransactionParameters,
SendTransactionParameters,
} from '../../../types/transaction.js'
import {
type PostJsonRpcRequestMessageReturnType,
postJsonRpcRequestMessage,
Expand All @@ -12,9 +15,27 @@ export function postSendTransactionRequestMessage(
parameters: SendTransactionRequestMessageParameters,
requestIdOverride?: string,
) {
const { chainId, attribution, abi, data, gas, to, value } = parameters

const sendTransactionParams: EthSendTransactionParameters<string> = {
abi,
data,
to,
}

if (gas) sendTransactionParams.gas = gas.toString()
if (value) sendTransactionParams.value = value.toString()

return postJsonRpcRequestMessage(
'fc_requestWalletAction',
parameters,
{
action: {
method: 'eth_sendTransaction',
attribution,
chainId,
params: sendTransactionParams,
},
},
requestIdOverride,
)
}
18 changes: 17 additions & 1 deletion src/web/actions/internal/postSignTypedDataRequestMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,25 @@ export function postSignTypedDataRequestMessage<
parameters: SignTypedDataRequestMessageParameters<typedData, primaryType>,
requestIdOverride?: string,
) {
const { chainId, domain, message, types, primaryType } = parameters
return postJsonRpcRequestMessage(
'fc_requestWalletAction',
parameters,
{
action: {
method: 'eth_signTypedData_v4',
chainId,
params: {
domain,
message: JSON.parse(
JSON.stringify(message, (_, v) =>
typeof v === 'bigint' ? v.toString() : v,
),
),
types,
primaryType,
},
},
},
requestIdOverride,
)
}

0 comments on commit f99498d

Please sign in to comment.