@@ -48,6 +48,9 @@ var specialLogFile *os.File
48
48
// Temp variable to allow testing
49
49
var useOldTipAmountChecks bool
50
50
51
+ // Not sure where to put this
52
+ var wUsdcPid = "7zH9dlMNoxprab9loshv3Y7WG45DOny_Vrq9KrXObdQ"
53
+
51
54
func init () {
52
55
var err error
53
56
specialLogFile , err = os .OpenFile ("special.log" , os .O_APPEND | os .O_CREATE | os .O_WRONLY , 0644 )
@@ -89,22 +92,25 @@ func create(_ *http.Request, args *commentapi.CreateArgs, reply *commentapi.Crea
89
92
useOldTipAmountChecks = args .Amount == nil
90
93
91
94
var frequencyCheck = checkFrequency
92
- if args .SupportTxID != nil || args .PaymentIntentID != nil || args . Currency != nil {
95
+ if args .SupportTxID != nil || args .PaymentIntentID != nil {
93
96
if args .DryRun {
94
97
if args .Amount != nil {
95
98
if args .PaymentIntentID != nil {
96
99
cents := uint64 (* args .Amount * 100 )
97
100
request .comment .Amount .SetValid (cents )
98
- } else if args .SupportTxID != nil {
99
- lbc , err := btcutil .NewAmount (* args .Amount )
100
- if err != nil {
101
- return errors .Err (err )
101
+ } else if args .SupportTxID != nil && args .Currency != nil {
102
+ switch * args .Currency {
103
+ case "USDC" :
104
+ cents := uint64 (* args .Amount * 100 )
105
+ request .comment .Amount .SetValid (cents )
106
+ request .comment .Currency .SetValid (* args .Currency )
107
+ case "LBC" :
108
+ lbc , err := btcutil .NewAmount (* args .Amount )
109
+ if err != nil {
110
+ return errors .Err (err )
111
+ }
112
+ request .comment .Amount .SetValid (uint64 (lbc .ToUnit (btcutil .AmountSatoshi )))
102
113
}
103
- request .comment .Amount .SetValid (uint64 (lbc .ToUnit (btcutil .AmountSatoshi )))
104
- } else if * args .Currency == "USDC" {
105
- cents := uint64 (* args .Amount * 100 )
106
- request .comment .Amount .SetValid (cents )
107
- request .comment .Currency .SetValid (* args .Currency )
108
114
}
109
115
}
110
116
} else {
@@ -633,7 +639,7 @@ func checkSettings(settings *m.CreatorSetting, request *createRequest) error {
633
639
}
634
640
} else {
635
641
if ! request .comment .Amount .IsZero () {
636
- if request .args .PaymentIntentID == nil && request .args .Currency == nil {
642
+ if request .args .PaymentIntentID == nil && ( request .args .Currency == nil || * request . args . Currency != "USDC" ) {
637
643
err = checkMinTipAmountSuperChat (settings , request )
638
644
} else {
639
645
err = checkMinUsdcTipAmountSuperChat (settings , request )
@@ -646,7 +652,7 @@ func checkSettings(settings *m.CreatorSetting, request *createRequest) error {
646
652
if request .comment .Amount .IsZero () {
647
653
return api.StatusError {Err : errors .Err ("you must include tip in order to comment as required by creator" ), Status : http .StatusBadRequest }
648
654
}
649
- if request .args .PaymentIntentID == nil && request .args .Currency == nil {
655
+ if request .args .PaymentIntentID == nil && ( request .args .Currency == nil || * request . args . Currency != "USDC" ) {
650
656
err = checkMinTipAmountComment (settings , request )
651
657
} else {
652
658
err = checkMinUsdcTipAmountComment (settings , request )
@@ -751,7 +757,85 @@ func getCounter(key string, expiration time.Duration) (*counter.Counter, error)
751
757
return creatorCounter , nil
752
758
}
753
759
754
- func handleUsdcTip (request * createRequest ) {
760
+ type tag struct {
761
+ Name string `json:"name"`
762
+ Value string `json:"value"`
763
+ }
764
+
765
+ type cuResultResponse struct {
766
+ Messages []struct {
767
+ Data string `json:"Data"`
768
+ Target string `json:"Target "`
769
+ Anchor string `json:"Anchor "`
770
+ Tags []tag `json:"Tags"`
771
+ Sags []tag `json:"Sags"`
772
+ } `json:"Messages"`
773
+ Assignments []struct {} `json:"Assignments"`
774
+ Spawns []struct {} `json:"Spawns"`
775
+ Output []struct {} `json:"Output"`
776
+ GasUsed int `json:"GasUsed"`
777
+ }
778
+
779
+ func getResultFromCu (txID , pID string , timeout int ) (cuResultResponse , error ) {
780
+ cuEndPoint := fmt .Sprintf (`https://cu.ao-testnet.xyz/result/%s?process-id=%s` , txID , pID )
781
+ var cuResp cuResultResponse
782
+
783
+ client := & http.Client {
784
+ Timeout : time .Duration (timeout ) * time .Second ,
785
+ }
786
+ resp , err := client .Get (cuEndPoint )
787
+ if err != nil {
788
+ return cuResp , errors .Err ("request failed: %w" , err )
789
+ }
790
+
791
+ defer helper .CloseBody (resp .Body )
792
+
793
+ if resp .StatusCode != http .StatusOK {
794
+ return cuResp , errors .Err ("Request failed with status %s" , resp .Status )
795
+ }
796
+
797
+ if err := json .NewDecoder (resp .Body ).Decode (& cuResp ); err != nil {
798
+ return cuResp , errors .Err ("failed to decode response: %w" , err )
799
+ }
800
+
801
+ return cuResp , nil
802
+ }
803
+
804
+ func checkCuResult (result cuResultResponse ) error {
805
+ tagFound := false
806
+ if len (result .Messages ) == 0 {
807
+ return errors .Err ("No result messages" )
808
+ }
809
+ message := result .Messages [0 ]
810
+ for _ , v := range message .Tags {
811
+ if v .Value == "Debit-Notice" || v .Value == "Credit-Notice" {
812
+ tagFound = true
813
+ break
814
+ }
815
+ }
816
+ if ! tagFound {
817
+ return errors .Err ("Credit-Notice or Depit-Notice tag not found in first result message" )
818
+ }
819
+
820
+ return nil
821
+ }
822
+
823
+ type graphQLRespData struct {
824
+ Transactions struct {
825
+ Edges []struct {
826
+ Node struct {
827
+ ID string `json:"id"`
828
+ Recipient string `json:"recipient"`
829
+ Owner struct {
830
+ Address string `json:"address"`
831
+ } `json:"owner"`
832
+ Tags []tag `json:"Tags"`
833
+ } `json:"node"`
834
+ } `json:"edges"`
835
+ } `json:"transactions"`
836
+ }
837
+
838
+ func getSupportTxFromGraphQL (request * createRequest ) (graphQLRespData , error ) {
755
839
client := graphql .NewClient ("https://arweave.net/graphql" )
756
840
757
841
query := `
@@ -776,40 +860,16 @@ func handleUsdcTip(request *createRequest) {
776
860
}
777
861
`
778
862
779
- req := graphql .NewRequest (query )
780
-
781
- if request .args .SupportTxID == nil {
782
- logrus .Error (fmt .Sprintf ("Can't verify the tip, support txid not given. CommentID: %s" , request .comment .CommentID ))
783
- return
784
- }
785
- defaultErrorInfo := fmt .Sprintf ("TxID: %s CommentID: %s" , * request .args .SupportTxID , request .comment .CommentID )
863
+ var respData graphQLRespData
786
864
787
865
err := checkForDuplicateTxID (* request .args .SupportTxID )
788
866
if err != nil {
789
- logrus . Error ( fmt . Sprintf ( "%v %s " , err .Error (), defaultErrorInfo ))
867
+ return respData , errors . Err ( "%v" , err .Error ())
790
868
}
791
869
870
+ req := graphql .NewRequest (query )
792
871
req .Var ("ids" , []string {* request .args .SupportTxID })
793
872
794
- var respData struct {
795
- Transactions struct {
796
- Edges []struct {
797
- Node struct {
798
- ID string `json:"id"`
799
- Recipient string `json:"recipient"`
800
- Owner struct {
801
- Address string `json:"address"`
802
- } `json:"owner"`
803
- Tags []struct {
804
- Name string `json:"name"`
805
- Value string `json:"value"`
806
- } `json:"Tags"`
807
- } `json:"node"`
808
- } `json:"edges"`
809
- } `json:"transactions"`
810
- }
811
-
812
- amount := request .comment .Amount .Uint64
813
873
triesLeft := 2
814
874
for triesLeft > 0 {
815
875
triesLeft --
@@ -822,30 +882,32 @@ func handleUsdcTip(request *createRequest) {
822
882
if len (respData .Transactions .Edges ) == 0 {
823
883
logrus .Error (fmt .Sprintf ("Tx for id %s not found" , * request .args .SupportTxID ))
824
884
}
825
- // If tx can't be found let it pass (assume a delay with gateway indexing)
826
- request .comment .Amount .SetValid (amount )
827
- request .comment .Currency .SetValid (* request .args .Currency )
828
- return
885
+ return respData , nil
829
886
}
830
887
time .Sleep (3 * time .Second )
831
888
}
832
889
890
+ return respData , nil
891
+ }
892
+
893
+ func checkSupportTxAndGetAmount (request * createRequest , respData * graphQLRespData ) (uint64 , error ) {
894
+ amount := request .comment .Amount .Uint64
895
+
833
896
if len (respData .Transactions .Edges [0 ].Node .Tags ) == 0 {
834
- logrus . Error ( fmt . Sprintf ( "No tags found. %s" , defaultErrorInfo ) )
897
+ return amount , errors . Err ( "No tags found. %s" )
835
898
}
836
899
837
- wUsdcPid := "7zH9dlMNoxprab9loshv3Y7WG45DOny_Vrq9KrXObdQ"
838
900
if respData .Transactions .Edges [0 ].Node .Recipient != wUsdcPid {
839
- logrus . Error ( fmt . Sprintf ( "Expected recipient %s, got %s. %s" , wUsdcPid , respData .Transactions .Edges [0 ].Node .Recipient , defaultErrorInfo ) )
901
+ return amount , errors . Err ( "Expected recipient %s, got %s. %s" , wUsdcPid , respData .Transactions .Edges [0 ].Node .Recipient )
840
902
}
841
903
842
904
if request .args .Owner != nil {
843
905
foundOwner := respData .Transactions .Edges [0 ].Node .Owner .Address
844
906
if foundOwner != * request .args .Owner {
845
- logrus . Error ( fmt . Sprintf ( "Expected Owner %s, got %s. %s" , * request .args .Owner , foundOwner , defaultErrorInfo ) )
907
+ return amount , errors . Err ( "Expected Owner %s, got %s. %s" , * request .args .Owner , foundOwner )
846
908
}
847
909
} else {
848
- logrus . Error ( fmt . Sprintf ( "Given nil Owner. %s" , defaultErrorInfo ) )
910
+ return amount , errors . Err ( "Given nil Owner. %s" )
849
911
}
850
912
851
913
tagsLeftToCheck := []string {"Action" , "Quantity" , "Recipient" , "TimeStamp" , "Signature" , "SignatureTS" }
@@ -856,36 +918,36 @@ func handleUsdcTip(request *createRequest) {
856
918
switch tag .Name {
857
919
case "Action" :
858
920
if tag .Value != "Transfer" {
859
- logrus . Error ( fmt . Sprintf ( "Action not Transfer. %s" , defaultErrorInfo ) )
921
+ return amount , errors . Err ( "Action not Transfer. %s" )
860
922
}
861
923
case "Quantity" :
862
924
quantity , err := strconv .Atoi (tag .Value )
863
925
if err != nil {
864
- logrus . Error ( fmt . Sprintf ( "Failed to parse Quantity %v. %s" , err .Error (), defaultErrorInfo ))
926
+ return amount , errors . Err ( "Failed to parse Quantity %v. %s" , err .Error ())
865
927
}
866
928
quantityCents := uint64 (quantity / 10000 )
867
929
amount = quantityCents
868
930
if quantityCents != request .comment .Amount .Uint64 {
869
- logrus . Error ( fmt . Sprintf ( "Quantity amount mismatch. Expected %d, got %d. %s" , request .comment .Amount .Uint64 , quantityCents , defaultErrorInfo ) )
931
+ return amount , errors . Err ( "Quantity amount mismatch. Expected %d, got %d. %s" , request .comment .Amount .Uint64 , quantityCents )
870
932
}
871
933
case "Recipient" :
872
934
if request .args .Recipient != nil {
873
935
if tag .Value != * request .args .Recipient {
874
- logrus . Error ( fmt . Sprintf ( "Transfer recipient mismatch. Expected %s, got %s. %s" , * request .args .Recipient , tag .Value , defaultErrorInfo ) )
936
+ return amount , errors . Err ( "Transfer recipient mismatch. Expected %s, got %s. %s" , * request .args .Recipient , tag .Value )
875
937
}
876
938
} else {
877
- logrus . Error ( fmt . Sprintf ( "Given nil Transfer Recipient. %s" , defaultErrorInfo ) )
939
+ return amount , errors . Err ( "Given nil Transfer Recipient. %s" )
878
940
}
879
941
case "TimeStamp" :
880
942
allowedTimeDifference , _ := time .ParseDuration ("5m" )
881
943
timeStamp , err := strconv .Atoi (tag .Value )
882
944
if err != nil {
883
- logrus . Error ( fmt . Sprintf ( "Failed to parse timestamp %v. %s" , err .Error (), defaultErrorInfo ))
945
+ return amount , errors . Err ( "Failed to parse timestamp %v. %s" , err .Error ())
884
946
}
885
947
deltaMs := math .Abs (float64 (int64 (timeStamp ) - time .Now ().UnixMilli ()))
886
948
if int64 (deltaMs ) > allowedTimeDifference .Milliseconds () {
887
949
parsedDelta , _ := time .ParseDuration (fmt .Sprintf ("%dms" , int64 (deltaMs )))
888
- logrus . Error ( fmt . Sprintf ( "Timestamp %d over allowed difference of %dm, difference %dm. %s" , timeStamp , int64 (allowedTimeDifference .Minutes ()), int64 (parsedDelta .Minutes ()), defaultErrorInfo ))
950
+ return amount , errors . Err ( "Timestamp %d over allowed difference of %dm, difference %dm. %s" , timeStamp , int64 (allowedTimeDifference .Minutes ()), int64 (parsedDelta .Minutes ()))
889
951
}
890
952
case "Signature" :
891
953
signature = tag .Value
@@ -900,13 +962,50 @@ func handleUsdcTip(request *createRequest) {
900
962
}
901
963
}
902
964
903
- err = lbry .ValidateSignatureAndTS (request .args .ChannelID , signature , signatureTS , request .args .ChannelName )
965
+ err : = lbry .ValidateSignatureAndTS (request .args .ChannelID , signature , signatureTS , request .args .ChannelName )
904
966
if err != nil {
905
- logrus . Error ( fmt . Sprintf ( "%v %s" , errors .Prefix ("could not authenticate channel signature:" , err ), defaultErrorInfo ))
967
+ return amount , errors . Err ( "%v %s" , errors .Prefix ("could not authenticate channel signature:" , err ))
906
968
}
907
969
908
970
if len (tagsLeftToCheck ) != 0 {
909
- logrus .Error (fmt .Sprintf ("Didn't found tags %v from the tx. %s" , tagsLeftToCheck , defaultErrorInfo ))
971
+ return amount , errors .Err ("Didn't found tags %v from the tx. %s" , tagsLeftToCheck )
972
+ }
973
+
974
+ return amount , nil
975
+
976
+ }
977
+
978
+ func handleUsdcTip (request * createRequest ) {
979
+ if request .args .SupportTxID == nil {
980
+ logrus .Error (fmt .Sprintf ("Can't verify the tip, support txid not given. CommentID: %s" , request .comment .CommentID ))
981
+ return
982
+ }
983
+ defaultErrorInfo := fmt .Sprintf ("TxID: %s CommentID: %s" , * request .args .SupportTxID , request .comment .CommentID )
984
+
985
+ respData , err := getSupportTxFromGraphQL (request )
986
+ if err != nil {
987
+ logrus .Error (fmt .Sprintf ("%v %s" , err , defaultErrorInfo ))
988
+ }
989
+ if len (respData .Transactions .Edges ) == 0 {
990
+ // If tx can't be found let it pass (assume a delay with gateway indexing)
991
+ request .comment .Amount .SetValid (request .comment .Amount .Uint64 )
992
+ request .comment .Currency .SetValid (* request .args .Currency )
993
+ return
994
+ }
995
+
996
+ amount , err := checkSupportTxAndGetAmount (request , & respData )
997
+ if err != nil {
998
+ logrus .Error (fmt .Sprintf ("%v %s" , err , defaultErrorInfo ))
999
+ }
1000
+
1001
+ timeout := 2
1002
+ result , err := getResultFromCu (* request .args .SupportTxID , wUsdcPid , timeout )
1003
+ if err != nil {
1004
+ logrus .Error (fmt .Sprintf ("%v %s" , err , defaultErrorInfo ))
1005
+ }
1006
+ err = checkCuResult (result )
1007
+ if err != nil {
1008
+ logrus .Error (fmt .Sprintf ("%v %s" , err , defaultErrorInfo ))
910
1009
}
911
1010
912
1011
request .comment .Amount .SetValid (amount )
0 commit comments