@@ -33,13 +33,34 @@ export class TransactionsService {
3333 ) { }
3434
3535 /**
36- * Create a new transaction in PENDING state
36+ * Create a new transaction in PENDING state.
37+ * If an idempotencyKey is supplied and a transaction with that key already
38+ * exists, the existing transaction is returned without creating a duplicate.
3739 */
3840 async create (
3941 createTransactionDto : CreateTransactionDto ,
4042 ) : Promise < TransactionEntity > {
41- const { amount, asset, senderWalletId, receiverWalletId, metadata } =
42- createTransactionDto ;
43+ const {
44+ amount,
45+ asset,
46+ senderWalletId,
47+ receiverWalletId,
48+ metadata,
49+ idempotencyKey,
50+ } = createTransactionDto ;
51+
52+ // Idempotency check: return existing transaction if key already used
53+ if ( idempotencyKey ) {
54+ const existing = await this . prisma . transaction . findUnique ( {
55+ where : { idempotencyKey } ,
56+ } ) ;
57+ if ( existing ) {
58+ this . logger . log (
59+ `Idempotency hit for key ${ idempotencyKey } , returning existing transaction ${ existing . id } ` ,
60+ ) ;
61+ return this . mapPrismaToEntity ( existing ) ;
62+ }
63+ }
4364
4465 // Validate wallets exist
4566 const senderWallet = await this . prisma . wallet . findUnique ( {
@@ -83,20 +104,20 @@ export class TransactionsService {
83104 }
84105
85106 // Create transaction in database
86- const created = await this . prisma . transaction . create ( {
87- data : {
88- amount ,
89- assetType : asset . type ,
90- assetCode : asset . code ?? null ,
91- assetIssuer : asset . issuer ?? null ,
92- senderWalletId ,
93- receiverWalletId : receiverWalletId ?? null ,
94- status : TransactionStatus . PENDING ,
95- metadata : metadata ?? null ,
96- } ,
97- } ) ;
98-
99- this . logger . log ( `Created transaction ${ created . id } in PENDING state` ) ;
107+ try {
108+ const created = await this . prisma . transaction . create ( {
109+ data : {
110+ amount ,
111+ assetType : asset . type ,
112+ assetCode : asset . code ?? null ,
113+ assetIssuer : asset . issuer ?? null ,
114+ senderWalletId ,
115+ receiverWalletId : receiverWalletId ?? null ,
116+ status : TransactionStatus . PENDING ,
117+ metadata : metadata ?? null ,
118+ idempotencyKey : idempotencyKey ?? null ,
119+ } ,
120+ } ) ;
100121
101122 this . webhookEventEmitter
102123 . emitTransactionCreated ( {
@@ -329,6 +350,7 @@ export class TransactionsService {
329350 confirmedAt : prismaTransaction . confirmedAt ,
330351 failedAt : prismaTransaction . failedAt ,
331352 metadata : prismaTransaction . metadata ,
353+ idempotencyKey : prismaTransaction . idempotencyKey ,
332354 createdAt : prismaTransaction . createdAt ,
333355 updatedAt : prismaTransaction . updatedAt ,
334356 } ;
0 commit comments