diff --git a/actionbody.go b/actionbody.go new file mode 100644 index 0000000..c211bb8 --- /dev/null +++ b/actionbody.go @@ -0,0 +1,45 @@ +package frameproto + +import ( + "sourcecode.social/reiver/go-opt" +) + +// ActionBody represents the data sent to a Frame-Protocol's (i.e., Farcaster Frame's) application when it is POSTed to. +// +// Example usage: +// +// p, err := io.ReadAll(request.Body) +// if nil != err { +// return err +// } +// +// var actionBody frameproto.ActionBody +// +// err := json.Unmarshal(p, &actionBody) +// if nil != err { +// return err +// } +type ActionBody struct { + UntrustedData ActionBodyUntrustedData `json:"untrustedData"` + TrustedData ActionBodyTrustedData `json:"trustedData"` +} + +type ActionBodyUntrustedData struct { + FID opt.Optional[uint64] `json:"fid"` + URL opt.Optional[string] `json:"url"` + MessageHash opt.Optional[string] `json:"messageHash"` + Timestamp opt.Optional[int64] `json:"timestamp"` + Network opt.Optional[uint64] `json:"network"` + ButtonIndex opt.Optional[uint64] `json:"buttonIndex"` + InputText opt.Optional[string] `json:"inputText"` + CastID ActionBodyCastID `json:"castId"` +} + +type ActionBodyTrustedData struct { + MessageBytes opt.Optional[string] +} + +type ActionBodyCastID struct { + FID opt.Optional[uint64] `json:"fid"` + Hash opt.Optional[string] `json:"hash"` +} diff --git a/actionbody_test.go b/actionbody_test.go new file mode 100644 index 0000000..8286ed4 --- /dev/null +++ b/actionbody_test.go @@ -0,0 +1,87 @@ +package frameproto + +import ( + "testing" + + "encoding/json" + + "sourcecode.social/reiver/go-opt" +) + +func TestActionBody(t *testing.T) { + + tests := []struct{ + JSON string + Expected ActionBody + }{ + { + JSON: +` +{ + "untrustedData": { + "fid": 2, + "url": "https://fcpolls.com/polls/1", + "messageHash": "0xd2b1ddc6c88e865a33cb1a565e0058d757042974", + "timestamp": 1706243218, + "network": 1, + "buttonIndex": 2, + "inputText": "hello world", + "castId": { + "fid": 226, + "hash": "0xa48dd46161d8e57725f5e26e34ec19c13ff7f3b9" + } + }, + "trustedData": { + "messageBytes": "d2b1ddc6c88e865a33cb1a565e0058d757042974..." + } +} +`, + Expected: ActionBody{ + ActionBodyUntrustedData{ + FID: opt.Something(uint64(2)), + URL: opt.Something("https://fcpolls.com/polls/1"), + MessageHash: opt.Something("0xd2b1ddc6c88e865a33cb1a565e0058d757042974"), + Timestamp: opt.Something(int64(1706243218)), + Network: opt.Something(uint64(1)), + ButtonIndex: opt.Something(uint64(2)), + InputText: opt.Something("hello world"), + CastID: ActionBodyCastID{ + FID: opt.Something(uint64(226)), + Hash: opt.Something("0xa48dd46161d8e57725f5e26e34ec19c13ff7f3b9"), + }, + }, + ActionBodyTrustedData{ + MessageBytes: opt.Something("d2b1ddc6c88e865a33cb1a565e0058d757042974..."), + }, + }, + }, + } + + for testNumber, test := range tests { + + var p []byte = []byte(test.JSON) + + var actual ActionBody + + err := json.Unmarshal(p, &actual) + + if nil != err { + t.Errorf("For test #%d, did not expect to get an error but actually got one.", testNumber) + t.Logf("ERROR: (%T) %s", err, err) + t.Logf("JSON:\n%s", test.JSON) + continue + } + + { + expected := test.Expected + + if expected != actual { + t.Errorf("For test #%d, the actual value is not what wa expected.", testNumber) + t.Logf("EXPECTED: %#v", expected) + t.Logf("ACTUAL: %#v", actual) + t.Logf("JSON:\n%s", test.JSON) + continue + } + } + } +}