Skip to main content

Use Cases

This section contains use-case-driven integration guides that show how real businesses would integrate with the Oak protocol using the Contracts SDK. Each guide tells a complete business story — from the problem to the on-chain solution — with illustrative code snippets.

These are documentation guides, not runnable scripts. For executable API-reference examples, see API Reference Examples.

Multi-token ERC-20 support

Campaigns are not tied to a single asset like USDC or USDT. GlobalParams owns the canonical currency → ERC-20[] mapping: initialize seeds currencies and tokensPerCurrency at deploy, and the protocol admin can later addTokenToCurrency / removeTokenFromCurrency (emitting TokenAddedToCurrency / TokenRemovedFromCurrency). getTokensForCurrency(currency) returns the full address list for a currency key.

When CampaignInfoFactory.createCampaign runs, it resolves the campaign's campaignData.currency to that list and stores a cached copy on CampaignInfo (with isTokenAccepted for O(1) checks). In the SDK you can read the live list with campaign.getAcceptedTokens() or cross-check globalParams.getTokensForCurrency(currency) against what you passed at creation.

Every pledge or payment specifies pledgeToken / paymentToken; treasuries revert if the token is not accepted. Balances, fees, refunds, and raised-amount aggregates are per token address, in each token's native decimals (normalized where the protocol compares across tokens). The stories below use USDC or USDT as examples; in production, use any address from your campaign's accepted-token list.

Use Cases

Use CaseDemoContract(s) UsedBusiness Story
EscrowHealthcare EscrowCampaignInfoFactory + PaymentTreasuryMedConnect holds patient payments until a doctor confirms service delivery
MarketplaceE-Commerce MarketplaceCampaignInfoFactory + PaymentTreasuryCeloMarket locks buyer funds until seller ships; on-chain escrow with line items
PrepaymentAutomotive PrepaymentCampaignInfoFactory + TimeConstrainedPaymentTreasuryKarma Automotive holds vehicle deposits with time-based expiry; expired funds are swept to the platform/protocol, and end-customer refunds are handled per Karma's policy
Flexible FundingCommunity ProjectCampaignInfoFactory + KeepWhatsRaisedTechForge runs keep-what's-raised campaigns with partial withdrawals, tips, and gateway fees
CrowdfundingCreative CampaignCampaignInfoFactory + AllOrNothingArtFund runs all-or-nothing campaigns with NFT-backed pledges and reward tiers

How to Read These Demos

Each guide follows the same structure:

  1. The Business — who is the company and what do they do?
  2. Why Oak? — what specific problems does Oak solve for them?
  3. Contracts Used — which Oak smart contracts power the solution
  4. Roles — who are the actors (platform, buyer, seller, backer)?
  5. Integration Flow — step-by-step walkthrough with code snippets
  6. Architecture Diagram — visual flow of interactions
  7. Key Takeaways — lessons and patterns to apply to your own integration

Contract-to-Use-Case Mapping

Understanding which Oak contract to use for your business:

CampaignInfoFactory + PaymentTreasury

Best for: escrow, marketplace, service payments

Create a CampaignInfo contract first (holds NFT receipts, accepted token list), then deploy a PaymentTreasury via TreasuryFactory. Funds are held until the platform confirms delivery/service. Supports line items, external fees, batch operations, and refund flows.

CampaignInfoFactory + TimeConstrainedPaymentTreasury

Best for: prepayments, deposits, time-bound commitments

Same setup and interface as PaymentTreasury, but with on-chain time windows. After the campaign deadline plus the platform claim delay, the platform admin can call claimExpiredFunds() to sweep idle balances on-chain (recipients are defined by the contract); align end-customer refunds with your product policy.

CampaignInfoFactory + KeepWhatsRaised

Best for: flexible funding, hardware startups, ongoing projects

Like AllOrNothing, creates a campaign with goals and deadlines, but the creator keeps whatever is raised. Supports partial withdrawals (with platform approval), tips, payment gateway fees, and configurable refund delays.

CampaignInfoFactory + AllOrNothing

Best for: crowdfunding, fundraising, community-driven projects

Creates a campaign with a goal and deadline. Pledges mint NFTs. If the goal is met, the creator withdraws. If not, backers get full refunds. Supports reward tiers with physical/digital items.

Common Patterns Across All Demos

Simulate Before Send

Every write operation should be simulated first to catch errors without spending gas:

await entity.simulate.someMethod(args);   // dry run — reverts throw typed errors
const txHash = await entity.someMethod(args); // actual transaction
await oak.waitForReceipt(txHash);

Multicall for Dashboard Reads

Batch multiple reads into a single RPC call:

// PaymentTreasury / KeepWhatsRaised — all three methods available
const [raised, available, refunded] = await oak.multicall([
() => treasury.getRaisedAmount(),
() => treasury.getAvailableRaisedAmount(),
() => treasury.getRefundedAmount(),
]);

// AllOrNothing — uses getRaisedAmount + getLifetimeRaisedAmount (no getAvailableRaisedAmount)
const [raised, lifetime, refunded] = await oak.multicall([
() => aonTreasury.getRaisedAmount(),
() => aonTreasury.getLifetimeRaisedAmount(),
() => aonTreasury.getRefundedAmount(),
]);

Fee Lifecycle

Fees are always disbursed before withdrawal:

await treasury.disburseFees();   // protocol + platform fees distributed
await treasury.withdraw(); // AllOrNothing / PaymentTreasury — sends all remaining funds

KeepWhatsRaised uses a different withdrawal model — withdraw(token, amount) for partial withdrawals and claimFund() for the final withdrawal:

await kwrTreasury.withdraw(USDC_TOKEN_ADDRESS, 3_000_000000n);  // partial withdrawal
await kwrTreasury.claimFund(); // final withdrawal after deadline

Signer Flexibility

The SDK supports three levels of signer configuration for different architectures:

// Client-level (most common for backends)
const oak = createOakContractsClient({ privateKey: PLATFORM_KEY, ... });

// Per-entity (useful for dApps after wallet connect)
const treasury = oak.paymentTreasury(address, { signer: walletClient });

// Per-call (multi-role systems)
await treasury.confirmPayment(id, buyer, { signer: adminWalletClient });