Skip to content

Commit 3b0af02

Browse files
snadrushugomrdias
andauthored
feat: add support for Curios's confirmedTxHash (#912)
Co-authored-by: Hugo Dias <hugomrdias@gmail.com>
1 parent b1fdbe9 commit 3b0af02

7 files changed

Lines changed: 70 additions & 6 deletions

File tree

packages/synapse-core/src/sp/add-pieces.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ export const AddPiecesPendingSchema = z.object({
176176
pieceCount: z.number(),
177177
addMessageOk: z.null(),
178178
piecesAdded: z.literal(false),
179+
/** Present once confirmed; equals txHash unless Curio replaced-by-fee. */
180+
confirmedTxHash: zHex.optional(),
179181
})
180182

181183
export const AddPiecesRejectedSchema = z.object({
@@ -185,6 +187,7 @@ export const AddPiecesRejectedSchema = z.object({
185187
pieceCount: z.number(),
186188
addMessageOk: z.null(),
187189
piecesAdded: z.literal(false),
190+
confirmedTxHash: zHex.optional(),
188191
})
189192

190193
export const AddPiecesSuccessSchema = z.object({
@@ -195,6 +198,8 @@ export const AddPiecesSuccessSchema = z.object({
195198
addMessageOk: z.literal(true),
196199
piecesAdded: z.literal(true),
197200
confirmedPieceIds: z.array(zNumberToBigInt),
201+
/** Hash included on chain. Equals txHash unless Curio replaced-by-fee. Use `confirmedTxHash ?? txHash` for explorers/receipts. */
202+
confirmedTxHash: zHex.optional(),
198203
})
199204

200205
export type AddPiecesPending = z.infer<typeof AddPiecesPendingSchema>

packages/synapse-core/src/sp/create-dataset-add-pieces.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,13 @@ export namespace waitForCreateDataSetAddPieces {
185185
pollInterval?: number
186186
}
187187
export type ReturnType = {
188+
/** Original Location / wait-key hash (not necessarily the included on-chain hash). */
188189
hash: string
190+
/**
191+
* Hash included on chain once confirmed. Differs from hash after replace-by-fee.
192+
* For explorers and receipt lookups use `confirmedTxHash ?? hash`.
193+
*/
194+
confirmedTxHash?: string
189195
dataSetId: bigint
190196
piecesIds: bigint[]
191197
}
@@ -227,6 +233,7 @@ export async function waitForCreateDataSetAddPieces(
227233
})
228234
return {
229235
hash: createdDataset.createMessageHash,
236+
confirmedTxHash: createdDataset.confirmedTxHash ?? addedPieces.confirmedTxHash,
230237
dataSetId: createdDataset.dataSetId,
231238
piecesIds: addedPieces.confirmedPieceIds,
232239
}

packages/synapse-core/src/sp/create-dataset.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ export const CreateDataSetPendingSchema = z.object({
165165
service: z.string(),
166166
txStatus: z.union([z.literal('pending'), z.literal('confirmed')]),
167167
ok: z.null(),
168+
/** Present once confirmed; equals createMessageHash unless Curio replaced-by-fee. */
169+
confirmedTxHash: zHex.optional(),
168170
})
169171

170172
/**
@@ -176,6 +178,7 @@ export const CreateDataSetRejectedSchema = z.object({
176178
service: z.string(),
177179
txStatus: z.literal('rejected'),
178180
ok: z.literal(false),
181+
confirmedTxHash: zHex.optional(),
179182
})
180183

181184
/**
@@ -188,6 +191,8 @@ export const CreateDataSetSuccessSchema = z.object({
188191
txStatus: z.literal('confirmed'),
189192
ok: z.literal(true),
190193
dataSetId: zNumberToBigInt,
194+
/** Hash included on chain. Equals createMessageHash unless Curio replaced-by-fee. Use `confirmedTxHash ?? createMessageHash` for explorers/receipts. */
195+
confirmedTxHash: zHex.optional(),
191196
})
192197

193198
export type CreateDataSetSuccess = z.infer<typeof CreateDataSetSuccessSchema>

packages/synapse-core/src/sp/terminate-service.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ POST /pdp/data-sets/{id}/terminate
4141
GET /pdp/data-sets/{id}/terminate (the status URL; valid immediately after the 202)
4242
queued {terminationTxHash: "", fwssTerminated: null}
4343
sent {terminationTxHash: "0x...", fwssTerminated: null}
44-
done {terminationTxHash: "0x..." or "", fwssTerminated: true, serviceTerminationEpoch: 4567}
44+
done {terminationTxHash: "0x..." or "", confirmedTxHash?: "0x...", fwssTerminated: true, serviceTerminationEpoch: 4567}
4545
reverted if we get a hash and then get a 404, the tx was rejected
4646
404 failed relays are discarded so the client can re-POST; also the
4747
response for SP-initiated terminations (only client-requested ones
@@ -54,6 +54,8 @@ GET /pdp/data-sets/{id}/terminate (the status URL; valid immediately after the 2
5454
competing terminate landed first; the goal state holds). When no terminate
5555
tx ever lands, ours or anyone's (e.g. the SP is unable to send), there is no
5656
terminal signal: the status stays queued and the poller runs to its timeout.
57+
confirmedTxHash is the included on-chain hash when present; it differs from
58+
terminationTxHash only if Curio replaced the original send by fee.
5759
*/
5860

5961
/**
@@ -250,6 +252,7 @@ export const TerminateServiceStatusPendingSchema = z.object({
250252
terminationTxHash: z.union([zHex, z.literal('')]),
251253
fwssTerminated: z.null(),
252254
serviceTerminationEpoch: z.null(),
255+
confirmedTxHash: zHex.optional(),
253256
})
254257

255258
/**
@@ -260,6 +263,8 @@ export const TerminateServiceStatusSuccessSchema = z.object({
260263
terminationTxHash: z.union([zHex, z.literal('')]),
261264
fwssTerminated: z.literal(true),
262265
serviceTerminationEpoch: zNumberToBigInt,
266+
/** Hash included on chain. Equals terminationTxHash unless Curio replaced-by-fee. Use `confirmedTxHash ?? terminationTxHash` for explorers/receipts. */
267+
confirmedTxHash: zHex.optional(),
263268
})
264269

265270
export type TerminateServiceStatusPending = z.infer<typeof TerminateServiceStatusPendingSchema>

packages/synapse-sdk/src/storage/context.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,7 @@ export class StorageContext {
941941

942942
return {
943943
txHash: addPiecesResult.txHash as Hex,
944+
...(confirmation.confirmedTxHash === undefined ? {} : { confirmedTxHash: confirmation.confirmedTxHash }),
944945
pieceIds: confirmedPieceIds,
945946
dataSetId: this._dataSetId,
946947
isNewDataSet: false,
@@ -965,6 +966,7 @@ export class StorageContext {
965966

966967
return {
967968
txHash: result.txHash as Hex,
969+
...(confirmation.confirmedTxHash === undefined ? {} : { confirmedTxHash: confirmation.confirmedTxHash as Hex }),
968970
pieceIds: confirmation.piecesIds,
969971
dataSetId: this._dataSetId,
970972
isNewDataSet: true,

packages/synapse-sdk/src/storage/terminate.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@ export async function terminateServiceFlow(
3838
onHash: onSubmitted,
3939
})
4040
const event = extractPDPPaymentTerminatedEvent(receipt.logs)
41-
return { txHash: receipt.transactionHash, dataSetId, endEpoch: event.args.endEpoch }
41+
return {
42+
txHash: receipt.transactionHash,
43+
confirmedTxHash: receipt.transactionHash,
44+
dataSetId,
45+
endEpoch: event.args.endEpoch,
46+
}
4247
}
4348

4449
// Resolve (and, on the manager path, validate) the target first so a bad
@@ -86,6 +91,7 @@ export async function terminateServiceFlow(
8691
})
8792
return {
8893
txHash: status.terminationTxHash === '' ? undefined : status.terminationTxHash,
94+
...(status.confirmedTxHash === undefined ? {} : { confirmedTxHash: status.confirmedTxHash }),
8995
dataSetId,
9096
endEpoch: status.serviceTerminationEpoch,
9197
}
@@ -102,6 +108,7 @@ export async function terminateServiceFlow(
102108
const status = await waitForTerminateService({ statusUrl, onHash: onSubmitted })
103109
return {
104110
txHash: status.terminationTxHash === '' ? undefined : status.terminationTxHash,
111+
...(status.confirmedTxHash === undefined ? {} : { confirmedTxHash: status.confirmedTxHash }),
105112
dataSetId,
106113
endEpoch: status.serviceTerminationEpoch,
107114
}

packages/synapse-sdk/src/types.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -619,16 +619,32 @@ export interface CommitOptions {
619619
pieces: Array<{ pieceCid: PieceCID; pieceMetadata?: MetadataObject }>
620620
/** Pre-built signed extraData (avoids re-signing) */
621621
extraData?: Hex
622-
/** Called when the commit transaction is submitted (before on-chain confirmation) */
622+
/**
623+
* Called when the commit transaction is submitted (before on-chain confirmation).
624+
* The hash is Curio's Location wait key and is not guaranteed to be the final
625+
* included on-chain hash if Curio replaces the send by fee. Prefer
626+
* {@link CommitResult.confirmedTxHash} after confirmation.
627+
*/
623628
onSubmitted?: (txHash: Hex) => void
624629
}
625630

626631
/**
627632
* Result of a commit operation
628633
*/
629634
export interface CommitResult {
630-
/** Transaction hash */
635+
/**
636+
* Original Location / wait-key transaction hash from Curio.
637+
* Not necessarily the included on-chain hash after replace-by-fee.
638+
* Keep using this for Curio status polling / resume URLs.
639+
*/
631640
txHash: Hex
641+
/**
642+
* Hash included on chain once confirmed. Differs from {@link txHash} when
643+
* Curio replaced the original send by fee. Omitted when the SP does not
644+
* report it (older Curio).
645+
* For explorers and receipt lookups use `confirmedTxHash ?? txHash`.
646+
*/
647+
confirmedTxHash?: Hex
632648
/** Piece IDs assigned by the contract */
633649
pieceIds: bigint[]
634650
/** Data set ID (may be newly created) */
@@ -649,16 +665,33 @@ export interface TerminateServiceOptions {
649665
* cooperation, but the service runs to the end of the lockup period.
650666
*/
651667
skipProvider?: boolean
652-
/** Called when the termination transaction is submitted (before on-chain confirmation) */
668+
/**
669+
* Called when the termination transaction is submitted (before on-chain confirmation).
670+
* For provider-relayed termination this is Curio's wait-key hash and may differ
671+
* from the included on-chain hash after replace-by-fee. Prefer
672+
* {@link TerminateServiceResult.confirmedTxHash} after confirmation.
673+
*/
653674
onSubmitted?: (txHash: Hex) => void
654675
}
655676

656677
/**
657678
* Result of a data set service termination
658679
*/
659680
export interface TerminateServiceResult {
660-
/** Transaction hash. Undefined when the service was already terminated without a provider transaction. */
681+
/**
682+
* Original wait-key transaction hash. Undefined when the service was already
683+
* terminated without a provider transaction. May differ from the included
684+
* on-chain hash after replace-by-fee.
685+
* Keep using this for Curio status polling / resume URLs.
686+
*/
661687
txHash?: Hex
688+
/**
689+
* Hash included on chain once confirmed. Differs from {@link txHash} when
690+
* Curio replaced the original send by fee. Omitted when the SP does not
691+
* report it (older Curio) or when no termination tx was sent.
692+
* For explorers and receipt lookups use `confirmedTxHash ?? txHash`.
693+
*/
694+
confirmedTxHash?: Hex
662695
/** The data set ID */
663696
dataSetId: bigint
664697
/**

0 commit comments

Comments
 (0)