Skip to main content
See also: API Reference Examples — executable TypeScript walkthroughs.

The Business

MedConnect is a healthcare platform that connects patients with specialist doctors for consultations, lab work, and follow-up care. Patients pay upfront, but their funds are held in escrow until the doctor confirms the service was delivered. If the service is not delivered within the agreed timeframe, the patient gets a full refund.

Why Oak?

MedConnect needs a trustless escrow mechanism that:
  • Holds patient payments securely until service confirmation
  • Allows the platform to confirm delivery on behalf of the provider
  • Enables automatic refunds if service is not delivered
  • Tracks fees (platform booking fee, protocol fee) transparently
  • Works with any accepted ERC-20 on the campaign’s token whitelist (examples below use USDC for readability)

Oak Contract Used

Multi-token support

Payments specify paymentToken; the contract reverts unless CampaignInfo.isTokenAccepted(paymentToken) is true. The campaign may accept several ERC-20s for one logical currency; pending, confirmed, fee, and refund accounting is per token address in each token’s native decimals. Snippets in this guide use USDC as a stand-in—use any whitelisted token your GlobalParams / campaign configuration allows. Resolve the list with globalParams.getTokensForCurrency(currency) or read the campaign’s cached copy via campaign.getAcceptedTokens() (same addresses the factory stored at creation).

Roles

Integration Flow

Step 1: Create a CampaignInfo contract

Role: Any callercreateCampaign is permissionless.
Before deploying a PaymentTreasury, MedConnect needs a CampaignInfo contract. This holds NFT receipts for crypto payments and defines the accepted token list.

Step 2: Deploy the PaymentTreasury

Role: Any callerdeploy on TreasuryFactory is permissionless (the implementation must have been registered and approved during platform onboarding).
MedConnect deploys a PaymentTreasury linked to the CampaignInfo from Step 1.

Step 3: Patient books appointment — two independent payment flows

Sarah books a cardiology consultation with Dr. Rivera. The appointment costs 150 USDC broken down into two line items: consultation (120 USDC) and lab work (30 USDC). MedConnect supports two payment methods — they are not sequential steps:

Flow A: Off-chain / fiat payment (createPayment)

Role: Platform Admin — only the platform admin can create payment records.
MedConnect creates a payment record on-chain. The createPayment transaction does not pull ERC-20 from the buyer’s wallet — it only records the obligation and pending accounting. Sarah pays through off-chain rails (credit card, insurance billing, etc.). Before MedConnect can call confirmPayment, the treasury must actually hold enough of the payment token on-chain (for example the platform deposits USDC after fiat settlement). The contract checks the treasury’s ERC-20 balance when confirming; if the tokens are not there, confirmPayment reverts.
At this point the payment record exists on-chain and pending amounts are tracked, but no ERC-20 was transferred in this transaction. Sarah completes payment off-chain; your operations then fund the treasury with the agreed token amount before you confirm (how you bridge or deposit is product-specific).
Confirm payment (platform admin)
Role: Platform Admin — only the platform admin can call confirmPayment for payments created with createPayment.
Dr. Rivera completes the consultation and marks it as delivered. After off-chain verification and once the treasury holds the required ERC-20 balance, the backend calls confirmPayment to move accounting from pending to confirmed (and optionally mint an NFT if you pass Sarah’s wallet as buyerAddress).
The payment status is now confirmed. Funds are ready for fee disbursement and withdrawal.

Flow B: On-chain crypto payment (processCryptoPayment)

Role: Any callerprocessCryptoPayment is permissionless, but the buyer must first approve the treasury to transfer their ERC-20 tokens.
This is a standalone operation — it creates the payment record AND transfers ERC-20 tokens in a single transaction. It does not require or complete a prior createPayment call. An NFT is minted to Sarah as proof of payment. Sarah opens the MedConnect app, sees the $150 charge, and approves the transfer:
Now the payment can be processed:

Step 4: Read the final treasury state

Role: Any caller — all read functions are public.
MedConnect’s dashboard shows the current state of the escrow pool.

Step 5: Disburse fees

Role: Any callerdisburseFees is permissionless. Fees are sent to the Protocol Admin and Platform Admin automatically.
Before the provider can withdraw, accumulated protocol and platform fees are distributed.

Step 6: Withdraw settled funds

Role: Platform Admin or Campaign Owner — either party can trigger withdrawal. Funds are always sent to the campaign owner (Dr. Rivera’s clinic).
The settled amount (minus fees) is sent to the campaign owner.

Alternative: Cancellation and refund flows

Three distinct paths exist depending on payment state and type:
A) Cancel an unconfirmed off-chain payment (before confirmPayment):
Role: Platform AdmincancelPayment works only on unconfirmed, non-expired, non-crypto payments. The transaction removes the pending payment record from contract accounting; it does not automatically return ERC-20 that may already sit in the treasury—handle any token recovery operationally if you deposited before cancelling. Off-chain refunds (card reversal, etc.) are handled by MedConnect outside this call.
B) Refund a confirmed off-chain payment (non-NFT):
Role: Platform AdminclaimRefund(paymentId, refundAddress) refunds a confirmed payment where no NFT was minted. The contract verifies the payment is confirmed and has tokenId == 0.
C) Refund a crypto payment (NFT was minted via processCryptoPayment):
Role: Any caller (NFT owner)claimRefundSelf(paymentId) is for crypto payments (auto-confirmed on creation). The contract looks up the NFT owner, burns the NFT, and sends the refundable amount to that owner. No prior cancelPayment is needed — crypto payments cannot be cancelled via cancelPayment.
Before calling claimRefundSelf, the NFT owner must approve the treasury to manage the NFT. All pledge NFTs live on the CampaignInfo contract (not the treasury itself), so approval uses the CampaignInfo SDK entity:

Step 7: Claim non-goal line items

Role: Platform Admin — only the platform admin can claim non-goal line items.
If the payment included line items that don’t count toward the campaign goal (e.g., platform commission, processing fees), these accumulate separately. The platform admin can claim them at any time after confirmation.

Step 8: Pause, unpause, or cancel the treasury

Pause the treasury:
Role: Platform Admin — only the platform admin can pause and unpause.
If MedConnect needs to halt operations for compliance or investigation:
While paused, no payments, confirmations, refunds, or withdrawals can occur. Unpause the treasury:
Role: Platform Admin
Cancel the treasury permanently:
Role: Platform Admin or Campaign Owner — either party can cancel.
Cancellation is irreversible. After cancellation, backers can still claim refunds for confirmed NFT payments, but no new payments, confirmations, or withdrawals can happen.

Batch operations

Role: Platform Admin — batch create and confirm are platform-admin-only.
For high-volume platforms, PaymentTreasury supports batch operations to reduce gas costs and prevent nonce conflicts. Batch create payments:
Batch confirm payments:

Architecture Diagram

MedConnect Healthcare Escrow Flow

Key Takeaways

  • ERC-20 approval is required — the buyer must approve the treasury contract before processCryptoPayment can transfer tokens
  • createPayment path — the createPayment transaction does not pull ERC-20 from the buyer; fund the treasury before confirmPayment (the contract checks balance on confirm)
  • processCryptoPayment path — pulls tokens and confirms in one transaction; use disburseFees / withdraw afterward—do not call confirmPayment for these payments
  • Multi-tokenpaymentToken must be on the campaign’s accepted list; balances and refunds are tracked per ERC-20 (each token’s decimals)
  • Funds stay in the treasury — held under contract rules until withdrawal, disbursement, or refund flows
  • Role-based accesscreatePayment/confirmPayment/cancelPayment are platform-admin-only; processCryptoPayment and disburseFees are permissionless; withdraw requires admin or owner
  • Three cancellation/refund pathscancelPayment deletes unconfirmed off-chain records (no on-chain refund); claimRefund(paymentId, address) refunds confirmed non-NFT payments (platform admin); claimRefundSelf(paymentId) refunds crypto/NFT payments directly (NFT owner, no prior cancel needed; burns pledge NFT — requires prior ERC-721 approval on the CampaignInfo contract)
  • Line items allow granular tracking (consultation vs. lab work) with configurable goal-counting, fees, and refund rules
  • Non-goal line items (e.g., platform commission) can be claimed separately via claimNonGoalLineItems
  • Batch operationscreatePaymentBatch and confirmPaymentBatch for high-volume platforms
  • Pause / cancel controls — platform admin can pause; either admin or owner can permanently cancel
  • External fees track platform charges transparently on-chain (informational only, no financial impact)
  • Simulate before send catches errors before spending gas
  • multicall batches multiple reads into a single RPC call for dashboard views