Skip to content

feat(escrow): add arbiter_address support for 2-of-3 multisig escrow#256

Open
Aiden181 wants to merge 1 commit into
profullstack:masterfrom
Aiden181:fix/multisig-escrow-arbiter-field
Open

feat(escrow): add arbiter_address support for 2-of-3 multisig escrow#256
Aiden181 wants to merge 1 commit into
profullstack:masterfrom
Aiden181:fix/multisig-escrow-arbiter-field

Conversation

@Aiden181
Copy link
Copy Markdown
Contributor

Summary

Adds arbiter_address support to enable 2-of-3 Multisig escrow via CoinPayPortal. Previously, only the Custodial escrow model was supported.

Changes

src/lib/coinpayportal.ts

  • Added arbiter_address?: string to the CreateEscrowOptions interface
  • Added arbiter_address: options.arbiter_address to the API request body sent to CoinPayPortal

src/app/api/gigs/[id]/escrow/route.ts

  • Added arbiter_address: z.string().min(10).optional() to the Zod validation schema
  • Added arbiter_address to the destructured params from the validated request body
  • Passed arbiter_address to the createEscrow() call
  • Added arbiter_address: arbiter_address || null to the gig_escrows database insert

Related

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 25, 2026

Greptile Summary

This PR adds optional arbiter_address support to enable 2-of-3 multisig escrow via CoinPayPortal, threading the new field through the Zod schema, the createEscrow() call, and the gig_escrows database insert.

  • src/lib/coinpayportal.ts: arbiter_address?: string added to CreateEscrowOptions and forwarded in the API request body; JSON.stringify silently drops the key when undefined, so custodial escrows are unaffected.
  • src/app/api/gigs/[id]/escrow/route.ts: Field is validated, destructured, and passed through — but it is also written unconditionally to the gig_escrows insert object without a corresponding database migration, meaning every escrow creation POST will fail at the DB layer until ALTER TABLE gig_escrows ADD COLUMN arbiter_address text; is applied.

Confidence Score: 2/5

Not safe to merge — the unconditional DB insert of arbiter_address breaks all escrow creation until a migration is added.

The arbiter_address field is written into every gig_escrows INSERT regardless of whether the caller supplies it, but the column has never been added to the table. This regresses the existing custodial escrow flow, not just the new multisig path.

src/app/api/gigs/[id]/escrow/route.ts needs a companion migration file before the insert will succeed.

Important Files Changed

Filename Overview
src/app/api/gigs/[id]/escrow/route.ts Adds arbiter_address to escrow creation, but inserts it into gig_escrows unconditionally without the required DB column; every POST will error at the database layer until a migration is added.
src/lib/coinpayportal.ts Adds optional arbiter_address to CreateEscrowOptions interface and the API request body; JSON.stringify omits the key when undefined so custodial escrows are unaffected.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Route as POST /api/gigs/[id]/escrow
    participant CPP as CoinPayPortal API
    participant DB as gig_escrows

    Client->>Route: depositor_address, beneficiary_address, arbiter_address optional
    Route->>Route: Zod validate arbiter_address optional min 10
    Route->>CPP: createEscrow with arbiter_address optional
    Note over CPP: Key omitted from JSON when undefined for custodial mode
    CPP-->>Route: escrowResult with escrow_id and payment_address
    Route->>DB: INSERT gig_escrows with arbiter_address value or null
    Note over DB: Column does not exist - no migration in this PR
    DB-->>Route: error column arbiter_address does not exist
    Route-->>Client: 500 Failed to create escrow
Loading

Reviews (1): Last reviewed commit: "feat(escrow): add arbiter_address suppor..." | Re-trigger Greptile

Comment on lines 192 to 196
currency,
platform_fee_usd: platformFee,
platform_fee_rate: platformFeeRate,
arbiter_address: arbiter_address || null,
status: "pending_payment",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Missing database migration for arbiter_address column

The gig_escrows table (created in 20260321080000_add_gig_escrows.sql) has no arbiter_address column, and no migration in the repository adds one. Because arbiter_address: arbiter_address || null is unconditionally included in every insert payload (not gated on a defined value), every call to POST /api/gigs/[id]/escrow will hit a PostgreSQL error like column "arbiter_address" of relation "gig_escrows" does not exist, completely breaking escrow creation even when no arbiter is supplied.

A new migration — e.g. ALTER TABLE gig_escrows ADD COLUMN arbiter_address text; — must be included in this PR.

currency: z.enum(["usdc_pol", "usdc_sol", "pol", "sol", "btc", "eth", "usdc_eth", "usdt"]),
depositor_address: z.string().min(10, "Depositor wallet address is required"),
beneficiary_address: z.string().min(10, "Beneficiary wallet address is required"),
arbiter_address: z.string().min(10).optional(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 The arbiter_address min-length validation is missing a user-facing error message, unlike the required depositor_address and beneficiary_address fields which both have descriptive messages.

Suggested change
arbiter_address: z.string().min(10).optional(),
arbiter_address: z.string().min(10, "Arbiter wallet address must be at least 10 characters").optional(),

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.

Missing multisig escrow support: arbiter_address field not passed to CoinPayPortal API

1 participant