@@ -47,14 +47,23 @@ import {
4747} from "@exactly/common/generated/chain" ;
4848import MIN_BORROW_INTERVAL from "@exactly/common/MIN_BORROW_INTERVAL" ;
4949import revertReason from "@exactly/common/revertReason" ;
50- import { Address , type Hash , type Hex } from "@exactly/common/validation" ;
50+ import { Address , Hex , type Hash } from "@exactly/common/validation" ;
5151import { MATURITY_INTERVAL , splitInstallments } from "@exactly/lib" ;
5252
5353import database , { cards , credentials , transactions } from "../database/index" ;
5454import t , { f } from "../i18n" ;
5555import keeper from "../utils/keeper" ;
5656import { sendPushNotification } from "../utils/onesignal" ;
57- import { collectors , createMutex , getMutex , getUser , headerValidator , signIssuerOp , updateUser } from "../utils/panda" ;
57+ import {
58+ collectors ,
59+ createMutex ,
60+ getMutex ,
61+ getUser ,
62+ headerValidator ,
63+ signIssuerOp ,
64+ updateUser ,
65+ verifyPandaSignature ,
66+ } from "../utils/panda" ;
5867import publicClient from "../utils/publicClient" ;
5968import revertFingerprint from "../utils/revertFingerprint" ;
6069import risk , { feedback } from "../utils/sardine" ;
@@ -87,6 +96,8 @@ const BaseTransaction = v.object({
8796 authorizedAmount : v . nullish ( v . number ( ) ) ,
8897 authorizationMethod : v . optional ( v . string ( ) ) ,
8998 userId : v . string ( ) ,
99+ signature : v . optional ( Hex ) ,
100+ timestamp : v . optional ( v . number ( ) ) ,
90101 } ) ,
91102} ) ;
92103
@@ -510,6 +521,32 @@ export default new Hono().post(
510521 Math . floor ( new Date ( payload . body . spend . authorizedAt ) . getTime ( ) / 1000 ) -
511522 Number ( BigInt ( `0x${ payload . id . replaceAll ( / [ ^ 0 - 9 a - f ] / g, "" ) } ` ) % 3600n ) ;
512523 const signature = await signIssuerOp ( { account, amount : - refundAmount , timestamp } ) ; // TODO replace with payload signature
524+ if ( payload . body . spend . signature ) {
525+ await startSpan (
526+ {
527+ name : "panda.signature" ,
528+ op : "panda.signature" ,
529+ attributes : {
530+ "signature.account" : account ,
531+ "signature.amount" : String ( - refundAmount ) ,
532+ "signature.timestamp" : String ( payload . body . spend . timestamp ?? 0 ) ,
533+ } ,
534+ } ,
535+ ( span ) => {
536+ if ( ! payload . body . spend . signature ) throw new Error ( "signature not found" ) ;
537+ if ( ! payload . body . spend . timestamp ) throw new Error ( "timestamp not found" ) ;
538+ return verifyPandaSignature ( {
539+ account,
540+ amount : - refundAmount ,
541+ timestamp : payload . body . spend . timestamp ,
542+ signature : payload . body . spend . signature ,
543+ } ) . then ( ( valid ) => {
544+ span . setAttribute ( "signature.valid" , valid ) ;
545+ if ( ! valid ) captureException ( new Error ( "invalid panda signature" ) , { level : "error" } ) ;
546+ } ) ;
547+ } ,
548+ ) . catch ( ( error : unknown ) => captureException ( error , { level : "error" } ) ) ;
549+ }
513550 try {
514551 await keeper . exaSend (
515552 { name : "exa.refund" , op : "exa.refund" , attributes : { account } } ,
@@ -1097,6 +1134,33 @@ async function prepareCollection(
10971134 ( payload . body . spend . authorizedAt ? new Date ( payload . body . spend . authorizedAt ) : new Date ( ) ) . getTime ( ) / 1000 , // TODO remove fallback
10981135 ) ;
10991136 const signature = await signIssuerOp ( { account, amount, timestamp } ) ; // TODO replace with payload signature
1137+ if ( payload . body . spend . signature ) {
1138+ await startSpan (
1139+ {
1140+ name : "panda.signature" ,
1141+ op : "panda.signature" ,
1142+ attributes : {
1143+ "signature.account" : account ,
1144+ "signature.amount" : String ( amount ) ,
1145+ "signature.timestamp" : String ( payload . body . spend . timestamp ?? 0 ) ,
1146+ } ,
1147+ } ,
1148+ ( span ) => {
1149+ if ( ! payload . body . spend . signature ) throw new Error ( "signature not found" ) ;
1150+ if ( ! payload . body . spend . timestamp ) throw new Error ( "timestamp not found" ) ;
1151+ return verifyPandaSignature ( {
1152+ account,
1153+ amount,
1154+ timestamp : payload . body . spend . timestamp ,
1155+ signature : payload . body . spend . signature ,
1156+ } ) . then ( ( valid ) => {
1157+ span . setAttribute ( "signature.valid" , valid ) ;
1158+ if ( ! valid ) captureException ( new Error ( "invalid panda signature" ) , { level : "error" } ) ;
1159+ } ) ;
1160+ } ,
1161+ ) . catch ( ( error : unknown ) => captureException ( error , { level : "error" } ) ) ;
1162+ }
1163+
11001164 if ( card . mode === 0 ) {
11011165 return { functionName : "collectDebit" , args : [ amount , BigInt ( timestamp ) , signature ] } as const ;
11021166 }
0 commit comments