Skip to content

feat: replace IPFS upload with cover metadata API and add cover data management#518

Open
valentinludu wants to merge 11 commits into
devfrom
feat/cover-metadata-api
Open

feat: replace IPFS upload with cover metadata API and add cover data management#518
valentinludu wants to merge 11 commits into
devfrom
feat/cover-metadata-api

Conversation

@valentinludu

@valentinludu valentinludu commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace direct IPFS upload in Quote.getQuoteAndBuyCoverInputs with a call to POST /cover-metadata on the backend
  • The backend now handles IPFS upload (stores only a UUID reference) and keeps private proof-of-loss data in Postgres
  • Remove ipfsCidOrContent param, replace with coverMetadata accepting { proofOfLoss?, publicData? }
  • Use isProofOfLossRequired (from product type API) to enforce metadata requirement
  • Add CoverData class with getCover, viewCoverMetadata, and editCoverMetadata methods
  • Add EIP-712 authentication helpers (buildAuthTypedData, buildCoverMetadataAuthMessage) for signed cover metadata requests

What was removed

  • Ipfs dependency from Quote class (still available on NexusSDK.ipfs for claims/governance)
  • 8 cover-specific IPFS content types and schemas: coverValidators, coverQuotaShare, coverAumCoverAmountPercentage, coverWalletAddress, coverWalletAddresses, coverFreeText, coverDesignatedWallets, defiPassContent
  • ipfsContentType field from ProductType

What was added

  • CoverData class (src/cover/Cover.ts) exposed as NexusSDK.cover with:
    • getCover(coverId) — fetch cover details by ID
    • viewCoverMetadata({ coverMetadataId, signature? }) — view cover metadata (public fields always returned; private proofOfLoss only with a valid EIP-712 signature)
    • editCoverMetadata({ coverMetadataId, proofOfLoss, signature }) — update proof-of-loss entries on existing cover metadata (requires authentication)
  • Authentication module (src/auth.ts):
    • buildAuthTypedData(message) — builds an EIP-712 typed-data object for Nexus Mutual API authentication
    • buildCoverMetadataAuthMessage() — convenience wrapper with the cover metadata auth message
  • Cover metadata types (src/types/cover-metadata.ts):
    • CoverMetadataInput, CoverMetadataResponse — create metadata during buy-cover flow
    • ProofOfLossEntry (discriminated union: address, api_key, validator, csv, free_text)
    • AddressValue, ApiKeyValue, ValidatorValue, CsvValue, FreeTextValue — entry content types
    • CoverPublicData — optional quotaShare / aumCoverAmountPercentage
    • GetCoverResponse, ViewCoverMetadataResponse, EditCoverMetadataParams, AuthSignature, AuthPayload — API contracts
  • isProofOfLossRequired on ProductType, proofOfLossInputTypes on Product
  • Private createCoverMetadata() method in Quote that POSTs to /cover-metadata and returns the CID

Why

Previously the SDK uploaded proof-of-loss data directly to IPFS, making sensitive information (wallet addresses, validator keys, API keys) publicly accessible on-chain. The new flow stores private data server-side in Postgres and only puts a UUID reference on IPFS, improving privacy for cover holders.

Additionally, integrators had no way to view or edit cover metadata after purchase. The new CoverData class provides authenticated endpoints for both viewing private metadata and updating proof-of-loss entries.

Breaking changes

  • GetQuoteAndBuyCoverInputsParams.ipfsCidOrContent removed → use coverMetadata
  • Quote constructor no longer accepts an Ipfs instance
  • Cover-specific ContentType enum values removed from exports

Summary by CodeRabbit

  • New Features

    • Added cover metadata management: retrieve cover information, view cover-specific metadata, and edit existing cover details
    • Introduced proof-of-loss submission support for products requiring documentation of losses
    • Implemented secure authentication mechanism for protecting cover metadata operations
  • Tests

    • Enhanced test coverage for new cover metadata management and authentication workflows

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3b27d046-90b2-4f47-b40c-4b0e32db1f05

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR refactors cover input handling from client-side schema validation to server-side metadata generation. It removes all legacy cover input IPFS schemas, redefines the IPFS content type system, introduces cover metadata type contracts with proof-of-loss entries and authentication types, refactors the Quote service to POST metadata to a dedicated backend endpoint instead of accepting pre-validated IPFS content, adds authentication and CoverData APIs, and updates all dependent tests.

Changes

Cover Metadata Generation Refactoring

Layer / File(s) Summary
Cover metadata type contracts
src/types/cover-metadata.ts, src/types/index.ts
New file defines proof-of-loss discriminated union with five value types (address, api_key, validator, csv, free_text), ProofOfLossEntry[] for submission, CoverPublicData with optional quota/percentage fields, CoverMetadataInput/CoverMetadataResponse request/response contracts. Adds GetCoverResponse/GetCoverApiResponse, AuthPayload/AuthSignature for EIP-712, ViewCoverMetadataParams/PrivateMetadata/ViewCoverMetadataResponse for viewing, and EditCoverMetadataParams/EditCoverMetadataApiResponse for editing. Barrel re-export added to types module.
IPFS content type system redesign
src/ipfs/schemas.ts, src/types/ipfs.ts, src/ipfs/validateIPFSContent.test.ts
Removes coverValidators, coverQuotaShare, coverAumCoverAmountPercentage, coverWalletAddress(s), coverFreeText, coverDesignatedWallets, and defiPassContentSchema from schemas. Replaces ContentType enum members and exported type aliases: removes cover/DeFi family types, adds stakingPoolDetails, claimProof, assessmentCriteriaAnswers, assessmentReason, governanceProposal, governanceCategory, file, productAnnex, coverMetadataRef. Updates IPFSContentTypes union and IPFSTypeContentTuple. Removes all cover type validation tests and adjusts test setup.
Product and SDK parameter contracts
src/types/product.ts, src/types/sdk.ts
ProductType gains optional isProofOfLossRequired boolean flag (replaces ipfsContentType). Product adds optional proofOfLossInputTypes array typed from ProofOfLossEntry['type'][]. GetQuoteAndBuyCoverInputsParams adds optional coverMetadata field typed as CoverMetadataInput.
Authentication and CoverData APIs
src/auth.ts, src/auth.test.ts, src/cover/Cover.ts, src/cover/Cover.test.ts, src/cover/index.ts
src/auth.ts introduces EIP-712 typed-data builders: buildAuthTypedData(message) produces domain/types/primaryType/value with Unix timestamp as BigInt, and buildCoverMetadataAuthMessage() delegates with "proof of loss data" message. src/cover/Cover.ts adds CoverData class with getCover(coverId), viewCoverMetadata(params), and editCoverMetadata(params) methods validating inputs, building auth headers with bigint-to-string serialization, and issuing GET/PUT requests. Corresponding test suites validate input validation, successful requests, auth header behavior, and failure handling.
Quote service refactoring and SDK wiring
src/nexus-sdk.ts, src/quote/Quote.ts, src/index.ts
Quote constructor removes optional ipfs parameter. getQuoteAndBuyCoverInputs destructures coverMetadata instead of ipfsCidOrContent. Removes prior CID/content validation logic. Adds proof-of-loss gating: returns error if required but missing. When metadata provided with proofOfLoss or publicData, calls createCoverMetadata to POST to /cover-metadata and obtains CID as ipfsData. Failures return "Failed to create cover metadata" error. When metadata absent/empty, sets ipfsData to empty string. NexusSDK instantiates CoverData with config and adds public cover field. Main index.ts imports/spreads auth and cover modules into nexusSdk default export and adds wildcard re-exports.
Test updates and validation
src/ipfs/uploadIPFSContent.test.ts, src/quote/getQuoteAndBuyCoverInputs.test.ts
uploadIPFSContent tests replace CoverFreeText fixture with StakingPoolDetails. getQuoteAndBuyCoverInputs tests remove IPFS imports, add CoverMetadataInput import, update fixture to remove ipfsCidOrContent, and replace IPFS validation section with cover-metadata workflow tests: validates missing required metadata error, missing proof-of-loss types, empty arrays, verifies POST /cover-metadata called with correct payload, confirms returned CID becomes ipfsData, skips POST when metadata absent/empty, handles POST failures, validates cover edit flow, and updates final ipfsData assertion to empty string.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant Quote
  participant ProductAPI as Product API
  participant MetadataAPI as POST /cover-metadata
  Caller->>Quote: getQuoteAndBuyCoverInputs({coverMetadata, ...})
  Quote->>ProductAPI: fetch product config
  ProductAPI-->>Quote: ProductType with isProofOfLossRequired
  alt isProofOfLossRequired && !coverMetadata
    Quote-->>Caller: error: Missing cover metadata
  else coverMetadata with proofOfLoss or publicData
    Quote->>MetadataAPI: POST CoverMetadataInput
    alt success
      MetadataAPI-->>Quote: {cid}
      Quote-->>Caller: buyCoverInput with ipfsData=cid
    else failure
      Quote-->>Caller: error: Failed to create cover metadata
    end
  else metadata absent or empty
    Quote-->>Caller: buyCoverInput with ipfsData=''
  end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly Related PRs

  • NexusMutual/sdk#513: Adds and wires ContentType.coverMetadataRef end-to-end across schemas, types, and validation logic, directly overlapping with this PR's IPFS type system redesign.
  • NexusMutual/sdk#491: Modifies the Quote.ts and getQuoteAndBuyCoverInputs code path to use runtime product API data; this PR further refactors that same path to generate ipfsData from coverMetadata via server-side POST.

Suggested Reviewers

  • MilGard91
  • shark0der
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main objective of the PR: replacing IPFS upload with a cover metadata API and adding cover data management capabilities.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cover-metadata-api
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/cover-metadata-api

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


Comment @coderabbitai help to get the list of available commands and usage tips.

@valentinludu valentinludu changed the title feat: replace direct IPFS upload with POST /cover-metadata endpoint [DO NOT MERGE] feat: replace direct IPFS upload with POST /cover-metadata endpoint Jun 3, 2026
@valentinludu valentinludu linked an issue Jun 3, 2026 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/quote/Quote.ts (1)

46-48: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update README to match the new coverMetadata + POST /cover-metadata flow

README.md still documents the removed ipfsCidOrContent / IPFSContentTypes param and describes local IPFS upload behavior, but Quote.getQuoteAndBuyCoverInputs now uses coverMetadata and creates the CID via POST /cover-metadata (then passes it as ipfsData). Update the README examples and the ipfsCidOrContent section (≈ lines 180-196, 210-224, 229-232).

Want me to draft the README update for the new coverMetadata flow?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/quote/Quote.ts` around lines 46 - 48, README still documents the removed
ipfsCidOrContent / IPFSContentTypes and local IPFS upload behavior; update all
examples and sections (~lines noted) to reflect that
Quote.getQuoteAndBuyCoverInputs now accepts coverMetadata, posts it to POST
/cover-metadata to obtain a CID which is passed as ipfsData to the API, remove
references to ipfsCidOrContent/IPFSContentTypes and replace with a short example
showing construction of coverMetadata, the POST /cover-metadata call returning
the CID, and how that CID is used as ipfsData in the getQuoteAndBuyCoverInputs
call.
🧹 Nitpick comments (1)
src/quote/Quote.ts (1)

236-243: 💤 Low value

Guard against a missing response before reading cid.

The sibling helpers getQuote and getProductCapacity both check if (!response) throw ... before dereferencing. createCoverMetadata reads response.cid directly; if sendRequest resolves to undefined, this throws an opaque TypeError instead of a clear error. Adding a guard keeps behavior consistent and produces a clearer message.

♻️ Proposed guard
     const response = await this.sendRequest<CoverMetadataResponse>('/cover-metadata', options);
+    if (!response?.cid) {
+      throw new Error('Failed to create cover metadata');
+    }
     return response.cid;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/quote/Quote.ts` around lines 236 - 243, createCoverMetadata currently
dereferences response.cid without ensuring sendRequest returned a value; add the
same guard used in getQuote/getProductCapacity: after calling
this.sendRequest<CoverMetadataResponse>('/cover-metadata', options) check if
response is falsy and throw a descriptive error (e.g., "Failed to create cover
metadata: empty response") before returning response.cid so we avoid opaque
TypeErrors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/quote/Quote.ts`:
- Around line 141-162: Tighten the proof-of-loss gating: when
productType.isProofOfLossRequired is true, verify coverMetadata.proofOfLoss
exists and has content (e.g., check coverMetadata?.proofOfLoss?.length) and
return the same error if it’s missing or empty instead of only checking for
coverMetadata truthiness; update the hasCoverMetadata logic to reflect this.
Also harden createCoverMetadata usage by validating its response includes a
non-empty cid before assigning ipfsData (or return a clear error if cid is
missing), so you don’t silently proceed with ipfsData = '' when the backend
reply is unexpected.

---

Outside diff comments:
In `@src/quote/Quote.ts`:
- Around line 46-48: README still documents the removed ipfsCidOrContent /
IPFSContentTypes and local IPFS upload behavior; update all examples and
sections (~lines noted) to reflect that Quote.getQuoteAndBuyCoverInputs now
accepts coverMetadata, posts it to POST /cover-metadata to obtain a CID which is
passed as ipfsData to the API, remove references to
ipfsCidOrContent/IPFSContentTypes and replace with a short example showing
construction of coverMetadata, the POST /cover-metadata call returning the CID,
and how that CID is used as ipfsData in the getQuoteAndBuyCoverInputs call.

---

Nitpick comments:
In `@src/quote/Quote.ts`:
- Around line 236-243: createCoverMetadata currently dereferences response.cid
without ensuring sendRequest returned a value; add the same guard used in
getQuote/getProductCapacity: after calling
this.sendRequest<CoverMetadataResponse>('/cover-metadata', options) check if
response is falsy and throw a descriptive error (e.g., "Failed to create cover
metadata: empty response") before returning response.cid so we avoid opaque
TypeErrors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fe3d4bd1-d04e-46ba-ac68-3b6b2134fab0

📥 Commits

Reviewing files that changed from the base of the PR and between 0a65882 and 5236c88.

📒 Files selected for processing (12)
  • src/ipfs/Ipfs.ts
  • src/ipfs/schemas.ts
  • src/ipfs/uploadIPFSContent.test.ts
  • src/ipfs/validateIPFSContent.test.ts
  • src/nexus-sdk.ts
  • src/quote/Quote.ts
  • src/quote/getQuoteAndBuyCoverInputs.test.ts
  • src/types/cover-metadata.ts
  • src/types/index.ts
  • src/types/ipfs.ts
  • src/types/product.ts
  • src/types/sdk.ts
💤 Files with no reviewable changes (4)
  • src/ipfs/Ipfs.ts
  • src/ipfs/validateIPFSContent.test.ts
  • src/ipfs/schemas.ts
  • src/types/ipfs.ts

Comment thread src/quote/Quote.ts Outdated
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 3, 2026

Copy link
Copy Markdown

Deploying sdk with  Cloudflare Pages  Cloudflare Pages

Latest commit: 72a5f56
Status: ✅  Deploy successful!
Preview URL: https://f31be761.sdk-9yp.pages.dev
Branch Preview URL: https://feat-cover-metadata-api.sdk-9yp.pages.dev

View logs

@valentinludu valentinludu changed the title [DO NOT MERGE] feat: replace direct IPFS upload with POST /cover-metadata endpoint feat: replace direct IPFS upload with POST /cover-metadata endpoint Jun 10, 2026
@valentinludu valentinludu changed the title feat: replace direct IPFS upload with POST /cover-metadata endpoint feat: replace IPFS upload with cover metadata API and add cover data management Jun 17, 2026
@valentinludu

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/auth.test.ts`:
- Around line 10-12: The test file uses a spy on Date.now that needs to be
properly cleaned up to prevent test pollution. Move the spy restoration call
from within the test body (around line 21) to an afterEach hook that wraps the
entire test suite. This ensures that Date.now is always restored to its original
state after each test completes, even if an assertion fails before the
restoration line, preventing the mock from leaking into subsequent tests.

In `@src/cover/Cover.ts`:
- Around line 44-46: In the Cover.ts file where signature is checked before
calling buildAuthHeaders, add validation logic to ensure the signature object
has the expected shape and required properties before building auth headers.
Instead of only checking if signature exists with the current if (signature)
condition, validate that the signature contains all necessary fields required by
buildAuthHeaders to construct valid authorization headers. This way, if an
incomplete or invalid signature is passed, you will get an early error with
clear context rather than letting buildAuthHeaders create malformed headers that
fail later during the viewCoverMetadata operation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f3dfbdfc-3209-4bd4-8a61-d9010a6f725d

📥 Commits

Reviewing files that changed from the base of the PR and between 5236c88 and ebbaa82.

📒 Files selected for processing (11)
  • src/auth.test.ts
  • src/auth.ts
  • src/cover/Cover.test.ts
  • src/cover/Cover.ts
  • src/cover/index.ts
  • src/index.ts
  • src/nexus-sdk.ts
  • src/quote/Quote.ts
  • src/quote/getQuoteAndBuyCoverInputs.test.ts
  • src/types/cover-metadata.ts
  • src/types/product.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/types/product.ts
  • src/quote/getQuoteAndBuyCoverInputs.test.ts
  • src/quote/Quote.ts

Comment thread src/auth.test.ts
Comment thread src/cover/Cover.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upload cover metadata to DB

1 participant