Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
90d408b
Merge pull request #60 from oak-network/main
fahmidareem3 Mar 2, 2026
ca2031d
add: initial scratch
imon-ccp Mar 5, 2026
b3cff51
chore: reorganize package structure and update build configuration
mahabubAlahi Mar 5, 2026
b507e5a
feat: add common chain IDs for Celo networks
mahabubAlahi Mar 5, 2026
dff5113
feat: implement Oak Contracts SDK client
mahabubAlahi Mar 5, 2026
b74b353
feat: enhance client types and reorganization
mahabubAlahi Mar 5, 2026
ea1faa7
feat: add Celo Sepolia to chain registry and update imports
mahabubAlahi Mar 5, 2026
3c4ea02
feat: refactor contracts and introduce new entities
mahabubAlahi Mar 5, 2026
978d4ac
feat: add README for Oak Network contracts SDK
mahabubAlahi Mar 5, 2026
012e4b9
Merge pull request #70 from oak-network/main
fahmidareem3 Mar 5, 2026
a6a9f54
feat: update ABIs for various contracts
mahabubAlahi Mar 6, 2026
81cabcd
fix: correct function name casing in contract methods
mahabubAlahi Mar 6, 2026
226d143
feat: introduce new error classes for contract handling
mahabubAlahi Mar 6, 2026
b705617
fix: correct function name casing in client types
mahabubAlahi Mar 6, 2026
f2b6abd
Enhance contract functionalities and streamline client configuration …
mahabubAlahi Mar 9, 2026
d6022b4
Update README and enhance contract methods for clarity and functionality
mahabubAlahi Mar 9, 2026
f490f87
Refine contract SDK architecture (#76)
mahabubAlahi Mar 24, 2026
3bf830d
changeset: added changeset
tahseen-ccprotocol Mar 24, 2026
040ac54
Implement new viem provider utilities and structure for contract inte…
mahabubAlahi Mar 24, 2026
6597ae3
Remove deprecated abi files and associated functionalities
mahabubAlahi Mar 24, 2026
1e90ba5
Fix error decoding, stale test/README, and SDK hardening (#80)
mahabubAlahi Mar 30, 2026
607746b
test: added unit and integration test
tahseen-ccprotocol Mar 30, 2026
5251bcc
Merge branch 'feat/contract-sdk' into test/feat/contract-sdk
tahseen-ccprotocol Mar 30, 2026
4e2d936
test: added unit and integration test
tahseen-ccprotocol Mar 30, 2026
da2c509
fix: fixed integration for real values
tahseen-ccprotocol Mar 30, 2026
e212e62
Add per-contract call signer overrides feature (#83)
mahabubAlahi Mar 30, 2026
17e12a4
Merge pull request #82 from oak-network/test/feat/contract-sdk
tahseen-ccprotocol Mar 30, 2026
c60589d
fix: replaced hard coded variables
tahseen-ccprotocol Mar 30, 2026
270e9f3
Update README for Oak Contracts SDK with installation instructions, p…
mahabubAlahi Mar 31, 2026
382105d
Enhance documentation for PaymentTreasury and TimeConstrainedPaymentT…
mahabubAlahi Mar 31, 2026
a4e5d5b
fix: updated the readme and fix codex comment
tahseen-ccprotocol Mar 31, 2026
795d792
chore: update claude.md file
tahseen-ccprotocol Mar 31, 2026
30213f3
Update CLAUDE.md to clarify architecture principles for Contracts SDK
mahabubAlahi Mar 31, 2026
0ec7d2d
Enhance contract simulations and streamline error handling (#84)
mahabubAlahi Mar 31, 2026
627b9c3
chore: fix ci pipeline for contract
tahseen-ccprotocol Mar 31, 2026
4d5d485
chore: added secrets in ci
tahseen-ccprotocol Mar 31, 2026
a9506c9
Merge pull request #71 from oak-network/feat/contract-sdk
mahabubAlahi Mar 31, 2026
8c4d5be
chore: added MIT license path in readme
tahseen-ccprotocol Mar 31, 2026
416d4ad
Merge pull request #86 from oak-network/tahseen/hotfix/contract-sdk
tahseen-ccprotocol Mar 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fast-pets-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@oaknetwork/contracts": major
---

Added contract for sdk
13 changes: 11 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,21 @@ jobs:
run: pnpm -r --workspace-concurrency=Infinity build

- name: Run tests with coverage (enforces 100% threshold)
run: pnpm -r --workspace-concurrency=Infinity --filter=!@oaknetwork/contracts test --coverage
run: pnpm -r --workspace-concurrency=Infinity test --coverage
env:
CI: true
CLIENT_ID: ${{ secrets.CLIENT_ID }}
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
OAK_ENVIRONMENT: sandbox
RPC_URL: ${{ secrets.RPC_URL }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
ALL_OR_NOTHING_ADDRESS: ${{ secrets.ALL_OR_NOTHING_ADDRESS }}
CAMPAIGN_INFO_FACTORY_ADDRESS: ${{ secrets.CAMPAIGN_INFO_FACTORY_ADDRESS }}
GLOBAL_PARAMS_ADDRESS: ${{ secrets.GLOBAL_PARAMS_ADDRESS }}
TREASURY_FACTORY_ADDRESS: ${{ secrets.TREASURY_FACTORY_ADDRESS }}
CAMPAIGN_INFO_ADDRESS: ${{ secrets.CAMPAIGN_INFO_ADDRESS }}
PAYMENT_TREASURY_ADDRESS: ${{ secrets.PAYMENT_TREASURY_ADDRESS }}
KEEP_WHATS_RAISED_ADDRESS: ${{ secrets.KEEP_WHATS_RAISED_ADDRESS }}

- name: Upload coverage reports
uses: actions/upload-artifact@v4
Expand All @@ -58,4 +67,4 @@ jobs:
retention-days: 30

- name: Run lint
run: pnpm -r --workspace-concurrency=Infinity --filter=!@oaknetwork/contracts lint
run: pnpm -r --workspace-concurrency=Infinity lint
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ typings/
dist/
build/
lib/
!packages/contracts/src/lib/
lib-cov/
esm/
cjs/
Expand Down
241 changes: 220 additions & 21 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Oak SDK - AI Development Guidelines

**Last Updated:** February 2026
**Last Updated:** March 2026
**Status:** Pre-launch SDK (March 2026)

This document provides strict rules and standards for AI assistants (Claude Code, Cursor, etc.) working on the Oak SDK codebase. Following these guidelines is **mandatory** to maintain code quality, security, and architectural consistency.
Expand All @@ -9,20 +9,23 @@ This document provides strict rules and standards for AI assistants (Claude Code

## Table of Contents

1. [Architecture Principles](#architecture-principles)
2. [Code Standards](#code-standards)
3. [Security Rules](#security-rules)
4. [Testing Requirements](#testing-requirements)
5. [Anti-Patterns](#anti-patterns)
6. [Refactoring Guidelines](#refactoring-guidelines)
7. [Git Workflow](#git-workflow)
8. [Performance](#performance)
9. [Type System Rules](#type-system-rules)
10. [Documentation](#documentation)
1. [Architecture Principles (Payments SDK)](#architecture-principles-payments-sdk)
2. [Architecture Principles (Contracts SDK)](#architecture-principles-contracts-sdk)
3. [Code Standards](#code-standards)
4. [Security Rules](#security-rules)
5. [Testing Requirements](#testing-requirements)
6. [Anti-Patterns](#anti-patterns)
7. [Refactoring Guidelines](#refactoring-guidelines)
8. [Git Workflow](#git-workflow)
9. [Performance](#performance)
10. [Type System Rules](#type-system-rules)
11. [Documentation](#documentation)

---

## Architecture Principles
## Architecture Principles (Payments SDK)

> **Scope:** This section applies to the **payments SDK** (`packages/payments-sdk`). For the contracts package (`packages/contracts`), see [Architecture Principles (Contracts SDK)](#architecture-principles-contracts-sdk) below.

### Core Patterns (DO NOT BREAK)

Expand Down Expand Up @@ -79,6 +82,189 @@ export class CustomerService {

---

## Architecture Principles (Contracts SDK)

> **This section is specific to `packages/contracts`.** The contracts package interacts with on-chain smart contracts via **viem**, not REST APIs. Its patterns differ significantly from the payments SDK above.

### Architecture Overview

```
packages/contracts/src/
├── client/ # createOakContractsClient, config resolution, types
├── contracts/ # Per-protocol contract entities (kebab-case directories)
│ ├── global-params/
│ ├── campaign-info-factory/
│ ├── campaign-info/
│ ├── treasury-factory/
│ ├── payment-treasury/
│ ├── all-or-nothing/
│ ├── keep-whats-raised/
│ └── item-registry/
├── types/ # Cross-contract structs + SDK params (no logic)
├── utils/ # Pure helpers (account guards, chain, hash, hex, time)
├── constants/ # Chain IDs, encoding, fees, registry
├── errors/ # Typed revert error classes + parseContractError
├── metrics/ # Platform/campaign/treasury reporting
├── lib/ # Thin viem re-exports + provider helpers
└── scripts/ # ABI generation/checking (dev tooling)
```

### Client Factory

`createOakContractsClient(config)` is the entry point. It resolves viem clients and returns **entity factory methods**:

```typescript
const oak = createOakContractsClient({
chainId: CHAIN_IDS.CELO_TESTNET_SEPOLIA,
rpcUrl: process.env.RPC_URL,
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
});

const globalParams = oak.globalParams(GLOBAL_PARAMS_ADDRESS);
const feePercent = await globalParams.getProtocolFeePercent();
```

Client config supports three modes:
- **Read-only simple:** `{ chainId, rpcUrl }` -- writes/simulations throw
- **Simple:** `{ chainId, rpcUrl, privateKey }` -- standard usage
- **Full:** `{ chain, provider, signer }` -- BYO viem clients

### Entity Composition Pattern

Each contract directory contains `abi.ts`, `reads.ts`, `writes.ts`, `simulate.ts`, `events.ts`, `types.ts`, and `index.ts`. The entity factory composes them:

```typescript
// ✅ CORRECT - Entity factory pattern
export function createGlobalParamsEntity(
address: Address,
publicClient: PublicClient,
walletClient: WalletClient | null,
chain: Chain,
): GlobalParamsEntity {
return {
...createGlobalParamsReads(address, publicClient),
...createGlobalParamsWrites(address, walletClient, chain),
simulate: createGlobalParamsSimulate(address, publicClient, walletClient, chain),
events: createGlobalParamsEvents(address, publicClient),
};
}
```

Entity types combine reads + writes + nested simulate/events:

```typescript
export type GlobalParamsEntity = GlobalParamsReads & GlobalParamsWrites & {
simulate: GlobalParamsSimulate;
events: GlobalParamsEvents;
};
```

### Error Handling (Throws, NOT Result)

The contracts package **throws errors** instead of returning `Result<T, E>`. This is correct for on-chain interactions.

```typescript
// ✅ CORRECT for contracts - throw errors
export function requireSigner(walletClient: WalletClient | null): WalletClient {
if (walletClient === null) {
throw new Error("No signer configured.");
}
return walletClient;
}

// ❌ WRONG for contracts - do NOT use Result type
function requireSigner(walletClient: WalletClient | null): Result<WalletClient> {
if (walletClient === null) return err(new Error("No signer"));
return ok(walletClient);
}
```

On-chain revert errors are parsed into typed classes:

- `parseContractError(error)` -- decodes revert data into a typed error class
- `getRevertData(error)` -- extracts raw revert bytes from a caught error
- `simulateWithErrorDecode(...)` -- simulates a transaction and decodes any revert
- `getRecoveryHint(error)` -- returns a human-readable recovery suggestion

Each contract has its own typed error classes in `src/errors/contracts/` (e.g., `GlobalParamsUnauthorizedError`, `AllOrNothingNotClaimableError`).

### Signer Model

Three levels of signer resolution, from most specific to least:

1. **Per-call** (`CallSignerOptions`): `entity.enlistPlatform(..., { signer: walletClient })`
2. **Per-entity** (`EntitySignerOptions`): `oak.globalParams(address, { signer: walletClient })`
3. **Client-level**: `createOakContractsClient({ privateKey: "0x..." })`

Write and simulate methods **MUST** use `requireSigner` and `requireAccount` guards before calling `writeContract` or `simulateContract`.

### File and Naming Conventions

| Item | Convention | Example |
|------|-----------|---------|
| Contract directories | kebab-case | `all-or-nothing/`, `payment-treasury/` |
| Factory functions | `create<Contract><Layer>` | `createGlobalParamsReads`, `createAllOrNothingEntity` |
| Type interfaces | PascalCase + suffix | `GlobalParamsReads`, `AllOrNothingTreasuryEntity` |
| ABI files | `abi.ts` per contract | `src/contracts/global-params/abi.ts` |
| Struct types | `src/types/structs.ts` | On-chain struct mirrors, no logic |
| SDK params | `src/types/params.ts` | SDK input types, no logic |

### Subpath Exports

| Import path | Contents |
|-------------|----------|
| `@oaknetwork/contracts` | Client, utils, types, lib re-exports, constants, errors |
| `@oaknetwork/contracts/contracts` | Individual `create*Entity` factories |
| `@oaknetwork/contracts/client` | `createOakContractsClient` + client types |
| `@oaknetwork/contracts/utils` | Pure helper functions |
| `@oaknetwork/contracts/errors` | Error classes + parsing utilities |
| `@oaknetwork/contracts/metrics` | Reporting helpers (**NOT** re-exported from root) |

### Testing (Contracts-Specific)

#### Coverage Thresholds

- `pnpm test` enforces **100% coverage** globally (branches, functions, lines, statements)
- `pnpm test:integration` relaxes thresholds via `--coverageThreshold='{}'`
- ABI files (`abi.ts`) and barrel `index.ts` files are excluded from coverage collection

#### Unit Tests

Use the Hardhat `#0` private key and dummy addresses from `__tests__/setup/constant.ts`. No live RPC required:

```typescript
import { HARDHAT_PRIVATE_KEY, DUMMY_RPC_URL, DUMMY_ADDRESS } from "../setup/constant";

const client = createOakContractsClient({
chainId: CHAIN_IDS.CELO_TESTNET_SEPOLIA,
rpcUrl: DUMMY_RPC_URL,
privateKey: HARDHAT_PRIVATE_KEY,
});
```

#### Integration Tests

Require a `.env` file with `RPC_URL`, `PRIVATE_KEY`, and deployed contract addresses. Use `loadTestConfig()` from `__tests__/setup/config.ts`, which throws with a clear message if any required env var is missing.

### Contracts Anti-Patterns

1. ❌ Using `Result<T, E>` in contracts code -- use throws + typed errors
2. ❌ Using `withAuth` or `httpClient` -- contracts use viem clients directly
3. ❌ Inlining ABI arrays in read/write files -- always isolate in `abi.ts`
4. ❌ Skipping `requireSigner`/`requireAccount` guards in write methods
5. ❌ Putting logic in `src/types/` files -- types only, no runtime code
6. ❌ Adding runtime dependencies beyond `viem` -- keep the dep footprint minimal

### Build and Dependencies

- **Runtime dependency:** `viem` only (`^2.23.0`)
- **Build tool:** tsup (ESM only, `dts: true`, no splitting, clean)
- **TypeScript:** strict mode, `moduleResolution: "bundler"`
- **Module type:** ESM (`"type": "module"`)
- **Published files:** `dist/` only

---

## Code Standards

### TypeScript Strict Mode
Expand Down Expand Up @@ -714,16 +900,29 @@ export function verifyWebhookSignature(

## Common Mistakes to Avoid

### Shared (All Packages)

1. ❌ Using `any` instead of `unknown`
2. ❌ Not multiplying OAuth `expires_in` by 1000
3. ❌ Silent test skips with `console.warn` + `return`
4. ❌ Exposing `clientSecret` in public config
5. ❌ Hardcoding URLs instead of using `buildUrl`
6. ❌ Duplicating token-fetch logic instead of using `withAuth`
7. ❌ Putting test tools in `dependencies` instead of `devDependencies`
8. ❌ Creating zero-value wrapper functions
9. ❌ Using `ReturnType<typeof>` instead of named interfaces
10. ❌ Not handling both success and error paths in tests
2. ❌ Silent test skips with `console.warn` + `return`
3. ❌ Putting test tools in `dependencies` instead of `devDependencies`
4. ❌ Creating zero-value wrapper functions
5. ❌ Using `ReturnType<typeof>` instead of named interfaces
6. ❌ Not handling both success and error paths in tests

### Payments SDK Only

7. ❌ Not multiplying OAuth `expires_in` by 1000
8. ❌ Exposing `clientSecret` in public config
9. ❌ Hardcoding URLs instead of using `buildUrl`
10. ❌ Duplicating token-fetch logic instead of using `withAuth`

### Contracts Package Only

11. ❌ Using `Result<T, E>` instead of throws + typed errors
12. ❌ Using `withAuth` or `httpClient` instead of viem clients
13. ❌ Inlining ABI arrays instead of isolating in `abi.ts`
14. ❌ Skipping `requireSigner`/`requireAccount` guards in write methods
15. ❌ Adding runtime dependencies beyond `viem`

---

Expand Down
14 changes: 14 additions & 0 deletions packages/contracts/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Celo Sepolia testnet RPC
RPC_URL=https://forno.celo-sepolia.celo-testnet.org

# 0x-prefixed private key with funds on the testnet
PRIVATE_KEY=0x...

# Deployed contract addresses on Celo Sepolia
GLOBAL_PARAMS_ADDRESS=0x6c563C19Ec838d83854185F5cecc2c9d3b097F2D
CAMPAIGN_INFO_FACTORY_ADDRESS=0x1C9456c11753E7C189555b65D17A70e128bd3d74
TREASURY_FACTORY_ADDRESS=0xC8083f1190aD25A7FeFdc5fE3dd2FB8142e3f6eF
CAMPAIGN_INFO_ADDRESS=0x...
PAYMENT_TREASURY_ADDRESS=0x...
ALL_OR_NOTHING_ADDRESS=0x...
KEEP_WHATS_RAISED_ADDRESS=0x...
Loading
Loading