Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XMTP Frame Post Validation #123

Merged
merged 13 commits into from
Feb 20, 2024
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,8 @@
},
"default": "./lib/index.js"
}
},
"dependencies": {
"@xmtp/frames-validator": "^0.4.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where can I read this code?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also not sure if this should be a dependencies or peerDependencies 🤔

Our leaning is to be the second

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's a peerDependency then we're closer to the approach in #116 where we would want the caller to pass in some instance of the validator

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The developer experience is a little smoother if you only need to depend on onchainkit, but both are fine

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think is about choice, on what API to use.

OnchainKit contains some code might need React, and other it doesn't. Some code it needs Viem, and other it doesn't.

That's why we referred that as peerDependency.

In the documentation we will create a section called XMTP, where we will write that all those function need

yarn add @xmtp/frames-validator

to be used.

And then after that folks can do

import { getXmtpFrameMessage }  from '@coinbae/onchainkit/xmtp'

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our goal is to make sure that folks will need the PROTO dependencies https://bundlephobia.com/package/@xmtp/frames-validator@0.4.0 only when using XMTP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. You've sold me on a peer dependency approach. That seems fine as long as it's well documented.

Then we can add something like import { getOpenFramesMessage } from '@coinbase/onchainkit/open-frames' as soon as there is a 1.0 version of that spec. It can call into this code for the XMTP implementation of the spec. But no need to wait on that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love that

}
}
10 changes: 8 additions & 2 deletions src/core/getFrameMessage.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { FrameRequest, FrameValidationResponse } from './types';
import { FrameRequest, FrameValidationResponse, XmtpFrameValidationResponse } from './types';
import {
NEYNAR_DEFAULT_API_KEY,
neynarFrameValidation,
} from '../utils/neynar/frame/neynarFrameFunctions';
import { xmtpFrameValidation } from '../utils/xmtp/validateRequest';
import { XmtpOpenFramesRequest } from '@xmtp/frames-validator';

type FrameMessageOptions =
| {
Expand Down Expand Up @@ -44,4 +46,8 @@ async function getFrameMessage(
}
}

export { getFrameMessage };
function getXmtpFrameMessage(body: XmtpOpenFramesRequest): XmtpFrameValidationResponse {
return xmtpFrameValidation(body);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have his one file for getXmtpFrameMessage, so we keep things clean.

}

export { getFrameMessage, getXmtpFrameMessage };
3 changes: 3 additions & 0 deletions src/core/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NeynarFrameValidationInternalModel } from '../utils/neynar/frame/types';
import { Address } from 'viem';
import { xmtpFrameValidation } from '../utils/xmtp/validateRequest';
/**
* Frame Data
*
Expand Down Expand Up @@ -68,6 +69,8 @@ export function convertToFrame(json: any) {
};
}

export type XmtpFrameValidationResponse = ReturnType<typeof xmtpFrameValidation>;

/**
* Frame Request
*
Expand Down
27 changes: 27 additions & 0 deletions src/utils/xmtp/validateRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { validateFramesPost, XmtpOpenFramesRequest } from '@xmtp/frames-validator';

export async function xmtpFrameValidation(payload: XmtpOpenFramesRequest) {
if (!payload.clientProtocol || !payload.clientProtocol.startsWith('xmtp@')) {
return {
isValid: false,
message: undefined,
};
}

try {
const { actionBody, verifiedWalletAddress } = await validateFramesPost(payload);
return {
isValid: true,
message: {
...actionBody,
verifiedWalletAddress,
},
};
} catch (e) {
console.error(`Error validating frames post: ${e}`);
return {
isValid: false,
message: undefined,
};
}
}
199 changes: 197 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2008,11 +2008,13 @@ __metadata:
dependencies:
"@changesets/changelog-github": "npm:^0.4.8"
"@changesets/cli": "npm:^2.26.2"
"@open-frames/types": "npm:^0.0.6"
"@testing-library/jest-dom": "npm:^6.4.0"
"@testing-library/react": "npm:^14.2.0"
"@types/jest": "npm:^29.5.12"
"@types/react": "npm:^18"
"@types/react-dom": "npm:^18"
"@xmtp/frames-validator": "npm:^0.4.0"
jest: "npm:^29.7.0"
jest-environment-jsdom: "npm:^29.7.0"
jest-extended: "npm:^4.0.2"
Expand All @@ -2033,6 +2035,13 @@ __metadata:
languageName: unknown
linkType: soft

"@fastify/busboy@npm:^2.0.0":
version: 2.1.0
resolution: "@fastify/busboy@npm:2.1.0"
checksum: 7bb641080aac7cf01d88749ad331af10ba9ec3713ec07cabbe833908c75df21bd56249bb6173bdec07f5a41896b21e3689316f86684c06635da45f91ff4565a2
languageName: node
linkType: hard

"@isaacs/cliui@npm:^8.0.2":
version: 8.0.2
resolution: "@isaacs/cliui@npm:8.0.2"
Expand Down Expand Up @@ -2381,13 +2390,20 @@ __metadata:
languageName: node
linkType: hard

"@noble/hashes@npm:~1.3.0, @noble/hashes@npm:~1.3.2":
"@noble/hashes@npm:^1.3.3, @noble/hashes@npm:~1.3.0, @noble/hashes@npm:~1.3.2":
version: 1.3.3
resolution: "@noble/hashes@npm:1.3.3"
checksum: 23c020b33da4172c988e44100e33cd9f8f6250b68b43c467d3551f82070ebd9716e0d9d2347427aa3774c85934a35fa9ee6f026fca2117e3fa12db7bedae7668
languageName: node
linkType: hard

"@noble/secp256k1@npm:^2.0.0":
version: 2.0.0
resolution: "@noble/secp256k1@npm:2.0.0"
checksum: ab1f1e2bb09460e5c5962978954c6b835c2f16f4811da013f82c534c05b5f82dd3f215d038d2c90982c035a10806756ba0703255e15a0b26c709bab33f5a71ed
languageName: node
linkType: hard

"@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5"
Expand Down Expand Up @@ -2437,13 +2453,93 @@ __metadata:
languageName: node
linkType: hard

"@open-frames/types@npm:^0.0.6":
version: 0.0.6
resolution: "@open-frames/types@npm:0.0.6"
checksum: 83c6a73da51c993495673d9e3987428d91b5f526818dc1caa60085ec8702f8b2a76f52f010949212bbf5833f07b52e58c9c36cb1e1b28f770d7c79fd7215f2f7
languageName: node
linkType: hard

"@pkgjs/parseargs@npm:^0.11.0":
version: 0.11.0
resolution: "@pkgjs/parseargs@npm:0.11.0"
checksum: 5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd
languageName: node
linkType: hard

"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2":
version: 1.1.2
resolution: "@protobufjs/aspromise@npm:1.1.2"
checksum: a83343a468ff5b5ec6bff36fd788a64c839e48a07ff9f4f813564f58caf44d011cd6504ed2147bf34835bd7a7dd2107052af755961c6b098fd8902b4f6500d0f
languageName: node
linkType: hard

"@protobufjs/base64@npm:^1.1.2":
version: 1.1.2
resolution: "@protobufjs/base64@npm:1.1.2"
checksum: eec925e681081af190b8ee231f9bad3101e189abbc182ff279da6b531e7dbd2a56f1f306f37a80b1be9e00aa2d271690d08dcc5f326f71c9eed8546675c8caf6
languageName: node
linkType: hard

"@protobufjs/codegen@npm:^2.0.4":
version: 2.0.4
resolution: "@protobufjs/codegen@npm:2.0.4"
checksum: 26ae337c5659e41f091606d16465bbcc1df1f37cc1ed462438b1f67be0c1e28dfb2ca9f294f39100c52161aef82edf758c95d6d75650a1ddf31f7ddee1440b43
languageName: node
linkType: hard

"@protobufjs/eventemitter@npm:^1.1.0":
version: 1.1.0
resolution: "@protobufjs/eventemitter@npm:1.1.0"
checksum: 1eb0a75180e5206d1033e4138212a8c7089a3d418c6dfa5a6ce42e593a4ae2e5892c4ef7421f38092badba4040ea6a45f0928869989411001d8c1018ea9a6e70
languageName: node
linkType: hard

"@protobufjs/fetch@npm:^1.1.0":
version: 1.1.0
resolution: "@protobufjs/fetch@npm:1.1.0"
dependencies:
"@protobufjs/aspromise": "npm:^1.1.1"
"@protobufjs/inquire": "npm:^1.1.0"
checksum: cda6a3dc2d50a182c5865b160f72077aac197046600091dbb005dd0a66db9cce3c5eaed6d470ac8ed49d7bcbeef6ee5f0bc288db5ff9a70cbd003e5909065233
languageName: node
linkType: hard

"@protobufjs/float@npm:^1.0.2":
version: 1.0.2
resolution: "@protobufjs/float@npm:1.0.2"
checksum: 18f2bdede76ffcf0170708af15c9c9db6259b771e6b84c51b06df34a9c339dbbeec267d14ce0bddd20acc142b1d980d983d31434398df7f98eb0c94a0eb79069
languageName: node
linkType: hard

"@protobufjs/inquire@npm:^1.1.0":
version: 1.1.0
resolution: "@protobufjs/inquire@npm:1.1.0"
checksum: 64372482efcba1fb4d166a2664a6395fa978b557803857c9c03500e0ac1013eb4b1aacc9ed851dd5fc22f81583670b4f4431bae186f3373fedcfde863ef5921a
languageName: node
linkType: hard

"@protobufjs/path@npm:^1.1.2":
version: 1.1.2
resolution: "@protobufjs/path@npm:1.1.2"
checksum: cece0a938e7f5dfd2fa03f8c14f2f1cf8b0d6e13ac7326ff4c96ea311effd5fb7ae0bba754fbf505312af2e38500250c90e68506b97c02360a43793d88a0d8b4
languageName: node
linkType: hard

"@protobufjs/pool@npm:^1.1.0":
version: 1.1.0
resolution: "@protobufjs/pool@npm:1.1.0"
checksum: eda2718b7f222ac6e6ad36f758a92ef90d26526026a19f4f17f668f45e0306a5bd734def3f48f51f8134ae0978b6262a5c517c08b115a551756d1a3aadfcf038
languageName: node
linkType: hard

"@protobufjs/utf8@npm:^1.1.0":
version: 1.1.0
resolution: "@protobufjs/utf8@npm:1.1.0"
checksum: a3fe31fe3fa29aa3349e2e04ee13dc170cc6af7c23d92ad49e3eeaf79b9766264544d3da824dba93b7855bd6a2982fb40032ef40693da98a136d835752beb487
languageName: node
linkType: hard

"@rollup/plugin-babel@npm:^6.0.4":
version: 6.0.4
resolution: "@rollup/plugin-babel@npm:6.0.4"
Expand Down Expand Up @@ -3042,6 +3138,15 @@ __metadata:
languageName: node
linkType: hard

"@types/node@npm:>=13.7.0":
version: 20.11.17
resolution: "@types/node@npm:20.11.17"
dependencies:
undici-types: "npm:~5.26.4"
checksum: 1f30dae80b416cbf38f133a619ffb0e9fb9e7bc58f82d900bf73816ae5781740c4640892bf5971dd9c12570d5d05241646be3e7540bb4e059322ec6af4e51e15
languageName: node
linkType: hard

"@types/node@npm:^12.7.1":
version: 12.20.55
resolution: "@types/node@npm:12.20.55"
Expand Down Expand Up @@ -3141,6 +3246,30 @@ __metadata:
languageName: node
linkType: hard

"@xmtp/frames-validator@npm:^0.4.0":
version: 0.4.0
resolution: "@xmtp/frames-validator@npm:0.4.0"
dependencies:
"@noble/hashes": "npm:^1.3.3"
"@noble/secp256k1": "npm:^2.0.0"
"@xmtp/proto": "npm:3.41.0-beta.6"
viem: "npm:^2.7.8"
checksum: 0a315a80ac2ba87dc35a4f2d3217439cd7c7411b2d461baec3bbc4bb134ed5e3196a2171288613454794ff8f9caeee0d80c7686eab137df56f76961619cf1c72
languageName: node
linkType: hard

"@xmtp/proto@npm:3.41.0-beta.6":
version: 3.41.0-beta.6
resolution: "@xmtp/proto@npm:3.41.0-beta.6"
dependencies:
long: "npm:^5.2.0"
protobufjs: "npm:^7.0.0"
rxjs: "npm:^7.8.0"
undici: "npm:^5.8.1"
checksum: f612729e05390f75db12fbb9c56257b4a4a2ff3138a55b1ffbe488c634a367f4b200c38371fe882c0254e1a15edcf1f1697a02d9e9a3ee3e1b6380c533a57a96
languageName: node
linkType: hard

"abab@npm:^2.0.6":
version: 2.0.6
resolution: "abab@npm:2.0.6"
Expand Down Expand Up @@ -6458,6 +6587,13 @@ __metadata:
languageName: node
linkType: hard

"long@npm:^5.0.0, long@npm:^5.2.0":
version: 5.2.3
resolution: "long@npm:5.2.3"
checksum: 6a0da658f5ef683b90330b1af76f06790c623e148222da9d75b60e266bbf88f803232dd21464575681638894a84091616e7f89557aa087fd14116c0f4e0e43d9
languageName: node
linkType: hard

"loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0":
version: 1.4.0
resolution: "loose-envify@npm:1.4.0"
Expand Down Expand Up @@ -7429,6 +7565,26 @@ __metadata:
languageName: node
linkType: hard

"protobufjs@npm:^7.0.0":
version: 7.2.6
resolution: "protobufjs@npm:7.2.6"
dependencies:
"@protobufjs/aspromise": "npm:^1.1.2"
"@protobufjs/base64": "npm:^1.1.2"
"@protobufjs/codegen": "npm:^2.0.4"
"@protobufjs/eventemitter": "npm:^1.1.0"
"@protobufjs/fetch": "npm:^1.1.0"
"@protobufjs/float": "npm:^1.0.2"
"@protobufjs/inquire": "npm:^1.1.0"
"@protobufjs/path": "npm:^1.1.2"
"@protobufjs/pool": "npm:^1.1.0"
"@protobufjs/utf8": "npm:^1.1.0"
"@types/node": "npm:>=13.7.0"
long: "npm:^5.0.0"
checksum: e164855536a43aa7941c7d95a2342e466f599d2e033ed89c5f5582fb0e3affeec702810091b850f3b700bfd646260b07bb4d8bb94c107cddcecd92de4d1d62fd
languageName: node
linkType: hard

"pseudomap@npm:^1.0.2":
version: 1.0.2
resolution: "pseudomap@npm:1.0.2"
Expand Down Expand Up @@ -7854,6 +8010,15 @@ __metadata:
languageName: node
linkType: hard

"rxjs@npm:^7.8.0":
version: 7.8.1
resolution: "rxjs@npm:7.8.1"
dependencies:
tslib: "npm:^2.1.0"
checksum: 3c49c1ecd66170b175c9cacf5cef67f8914dcbc7cd0162855538d365c83fea631167cacb644b3ce533b2ea0e9a4d0b12175186985f89d75abe73dbd8f7f06f68
languageName: node
linkType: hard

"safe-array-concat@npm:^1.0.1":
version: 1.1.0
resolution: "safe-array-concat@npm:1.1.0"
Expand Down Expand Up @@ -8557,7 +8722,7 @@ __metadata:
languageName: node
linkType: hard

"tslib@npm:^2.4.0":
"tslib@npm:^2.1.0, tslib@npm:^2.4.0":
version: 2.6.2
resolution: "tslib@npm:2.6.2"
checksum: e03a8a4271152c8b26604ed45535954c0a45296e32445b4b87f8a5abdb2421f40b59b4ca437c4346af0f28179780d604094eb64546bee2019d903d01c6c19bdb
Expand Down Expand Up @@ -8709,6 +8874,15 @@ __metadata:
languageName: node
linkType: hard

"undici@npm:^5.8.1":
version: 5.28.3
resolution: "undici@npm:5.28.3"
dependencies:
"@fastify/busboy": "npm:^2.0.0"
checksum: 3c559ae50ef3104b7085251445dda6f4de871553b9e290845649d2f80b06c0c9cfcdf741b0029c6b20d36c82e6a74dc815b139fa9a26757d70728074ca6d6f5c
languageName: node
linkType: hard

"unicode-canonical-property-names-ecmascript@npm:^2.0.0":
version: 2.0.0
resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0"
Expand Down Expand Up @@ -8852,6 +9026,27 @@ __metadata:
languageName: node
linkType: hard

"viem@npm:^2.7.8":
version: 2.7.9
resolution: "viem@npm:2.7.9"
dependencies:
"@adraffy/ens-normalize": "npm:1.10.0"
"@noble/curves": "npm:1.2.0"
"@noble/hashes": "npm:1.3.2"
"@scure/bip32": "npm:1.3.2"
"@scure/bip39": "npm:1.2.1"
abitype: "npm:1.0.0"
isows: "npm:1.0.3"
ws: "npm:8.13.0"
peerDependencies:
typescript: ">=5.0.4"
peerDependenciesMeta:
typescript:
optional: true
checksum: 7715bff7e1a4d5dea40c7c9cea419e3a5efe77011d03b9498b45e471e642c89fff80a2d3fd375d5e471e222cb40a0ed001c04769a0c65b1924df01175d4fb1be
languageName: node
linkType: hard

"w3c-xmlserializer@npm:^4.0.0":
version: 4.0.0
resolution: "w3c-xmlserializer@npm:4.0.0"
Expand Down
Loading