Skip to content

Fix InsuranceContractError build break; add pause/unpause, transferInvoice, convertInvoiceToken; harden disputeInvoice - #512

Merged
Levi-Ojukwu merged 5 commits into
Invoice-Liquidity-Network:mainfrom
Temi-suwa18:fix/issues-464-468-469-470
Jul 25, 2026
Merged

Fix InsuranceContractError build break; add pause/unpause, transferInvoice, convertInvoiceToken; harden disputeInvoice#512
Levi-Ojukwu merged 5 commits into
Invoice-Liquidity-Network:mainfrom
Temi-suwa18:fix/issues-464-468-469-470

Conversation

@Temi-suwa18

@Temi-suwa18 Temi-suwa18 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Summary

InsuranceContractError class — one directly in insurance.ts, one in errors.ts (re-imported into insurance.ts). Both diffs were purely additive so they merged without a conflict marker, but the result doesn't compile: duplicate identifiers in index.ts/insurance.ts, and literal duplicate import statements in insurance.test.ts merged in from both PRs. Fixed by keeping insurance.ts's original class (the one actually used at runtime) and removing the duplicate.

#470 — pause/unpause. pause(client)/unpause(client) wrap the contract's emergency admin controls, requiring the admin's signature.

#469 — transferInvoice. transferInvoice(client, invoiceId, newFreelancer) wraps transfer_invoice, requiring the current freelancer's signature, and validates the invoice is Pending client-side before submitting.

#468 — convertInvoiceToken. convertInvoiceToken(client, freelancerAddress, invoiceId, newToken) wraps convert_invoice_token, validating Pending status client-side. Token-approval itself is contract-enforced only (no public allowlist query exists to check client-side), so an unapproved token surfaces as ILNError.Unauthorized from simulation rather than a fabricated pre-flight check — documented in the JSDoc.

#464 — disputeInvoice hardening. Previously relied on rpc.prepareTransaction's implicit simulation, which threw raw untyped errors — no ILNError mapping at all, and no test file existed for it. Rewrote the write path to explicitly simulate and map through ILNError.fromError, added a pre-flight status check (Pending/PartiallyFunded/Funded, mirroring the contract's own match arm), and added a full test file. Retry-with-backoff was already present via the existing retry() utility on the account/tx calls — extended it to the newly-added simulateTransaction/getNetwork calls too.

Closes #464
Closes #468
Closes #469
Closes #470

Test plan

  • npx vitest run in sdk/: all new tests pass across adminControls.test.ts/transferInvoice.test.ts/convertInvoiceToken.test.ts/disputeInvoice.test.ts (new file), plus the now-fixed insurance.test.ts; 11 pre-existing unrelated failures (getTokenDecimals.test.ts, nft.test.ts) confirmed to already exist on main
  • npx tsc --noEmit in sdk/: zero new errors (including the InsuranceContractError duplicate-identifier errors, now fixed); one pre-existing unrelated error in xdrDecoder.ts

PR Invoice-Liquidity-Network#508 (issues 475-478) added a local InsuranceContractError class
directly in insurance.ts. PR Invoice-Liquidity-Network#510 (issues 459-465, merged after) added a
second, separately-written InsuranceContractError to errors.ts and
imported it into insurance.ts. Both PRs' diffs were additive (new import
lines, new class blocks) so they merged into main without a git conflict
marker, but the result doesn't compile: duplicate identifier errors in
index.ts and insurance.ts, plus literal duplicate import statements in
insurance.test.ts (InsuranceContractError, and separately SorobanRpc/
Keypair/Address) merged in from both PRs' test-file edits.

Keeps insurance.ts's original local class (the one actually used at
runtime by its own simulateCall/submitCall) and removes the duplicate
from errors.ts, the now-dangling import in insurance.ts, and the
duplicate import lines in insurance.test.ts. `npx tsc --noEmit` in sdk/
now shows zero errors beyond the one pre-existing unrelated xdrDecoder.ts
issue; full vitest suite matches the known baseline (11 pre-existing
unrelated failures in getTokenDecimals.test.ts/nft.test.ts).
(closes Invoice-Liquidity-Network#470)

pause(client)/unpause(client) wrap the contract's pause()/unpause()
emergency admin controls. Both require the contract admin's signature —
client.signer must be the stored admin — and map simulation errors
(e.g. Unauthorized) through the existing ILNError.fromError.

Adds tests for both, including the no-signer guard and error mapping.
(closes Invoice-Liquidity-Network#469)

transferInvoice(client, invoiceId, newFreelancer) wraps
transfer_invoice(invoice_id, new_freelancer), requiring the invoice's
*current* freelancer's signature. Validates the invoice is currently
Pending client-side (via getInvoice) before submitting — the contract
enforces this too and updates the submitter index on both the old and
new freelancer.

Adds tests covering the happy path, the Pending-status validation, and
the no-signer guard.
(closes Invoice-Liquidity-Network#468)

convertInvoiceToken(client, freelancerAddress, invoiceId, newToken) wraps
convert_invoice_token(freelancer, invoice_id, new_token), requiring the
freelancer's signature. Validates the invoice is currently Pending
client-side before submitting.

Note: token-approval is enforced entirely by the contract — there's no
public query to check the allowlist client-side, so an unapproved token
surfaces as ILNError.Unauthorized from the simulation rather than a
pre-flight check, documented in the JSDoc.

Adds tests covering the happy path, Pending-status validation, and
error-code mapping for an unapproved token.
(closes Invoice-Liquidity-Network#464)

disputeInvoice previously relied on rpc.prepareTransaction's implicit
simulation, which throws raw (untyped) errors — no ILNError mapping at
all. Rewrote the write path to explicitly simulate, check
isSimulationError, and throw through ILNError.fromError, so callers get
typed errors (AlreadyDisputed, InvoiceDefaulted, InvoiceExpired, etc.)
instead of opaque RPC exceptions.

Added a pre-flight check: fetches the invoice via getInvoice and
validates it's in a disputable status (Pending/PartiallyFunded/Funded,
mirroring the contract's own match arm) before submitting.

Retry-with-backoff was already present via the existing retry() utility
on getAccount/prepareTransaction/sendTransaction — extended it to the
new simulateTransaction/getNetwork calls too, and expanded the JSDoc
with the full set of @throws now that they're typed.

Adds a test file for this method (previously had none) covering the
happy path, the pre-flight status check, and error-code mapping.
@drips-wave

drips-wave Bot commented Jul 25, 2026

Copy link
Copy Markdown

@Temi-suwa18 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Levi-Ojukwu
Levi-Ojukwu merged commit 9da12b1 into Invoice-Liquidity-Network:main Jul 25, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants