Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
68970de
feat(safe): install safe-core-sdk and safe-ethers-lib
Majormaxx Sep 27, 2025
8db5d4c
feat(org): add safe configuration fields to organization entity
Majormaxx Sep 27, 2025
cce211e
refactor(controllers): removed any casts and fixed type augmentation
Majormaxx Sep 27, 2025
1f7d519
feat(org): updated RecognitionTokenMode enum to support MINT and TRAN…
Majormaxx Sep 27, 2025
0a04315
feat(org): updated updateSafeConfiguration to use new enum
Majormaxx Sep 27, 2025
f6dd48f
feat(payout): added Payout, TxProposal, and PayoutRecipient entities
Majormaxx Sep 27, 2025
82c075f
feat(payout): created PayoutService with initial structure
Majormaxx Sep 27, 2025
563ccfc
feat(org): add MINTER_ROLE validation for recognition token
Majormaxx Sep 27, 2025
969afd8
feat(org): add controller and router for configuration
Majormaxx Sep 27, 2025
dc9d5fc
fix(payout): removed previewPayout and fixed error handling in contro…
Majormaxx Sep 27, 2025
ad7b448
Added MINTER_ROLE enforcement for TeamPoints minting scenarios
Majormaxx Sep 29, 2025
2f55055
Removed sensitive configuration
Majormaxx Sep 29, 2025
5634c9a
Added dependency injection configuration for Module II services
Majormaxx Oct 3, 2025
d6614b1
Added rounds listing API with incomplete round filtering
Majormaxx Oct 3, 2025
d62b876
Added rounds listing and preview APIs with validation warnings
Majormaxx Oct 4, 2025
ac1f9b1
Integrated payout management routes for rounds listing, preview, prop…
Majormaxx Oct 4, 2025
baba04c
Added database entities for payout recipients, transactions, and Safe…
Majormaxx Oct 4, 2025
c7cddb3
build: add Safe API Kit dependency for transaction service integration
Majormaxx Oct 16, 2025
b9e4816
feat: implement Safe transaction service wrapper for multisig operations
Majormaxx Oct 16, 2025
1c8e5d1
feat: add Joi validation schemas for payout endpoints
Majormaxx Oct 16, 2025
fe542a0
feat: apply Joi validation to payout controller endpoints
Majormaxx Oct 16, 2025
1586f21
feat: integrate Safe SDK for transaction creation and status polling
Majormaxx Oct 16, 2025
a7ce3be
refactor: convert payout router to class-based dependency injection p…
Majormaxx Oct 16, 2025
2ca4e9a
fix: resolve TypeScript compilation errors in Module-II implementation
Majormaxx Oct 16, 2025
7aa2b87
fix: resolve Module-I TypeScript errors to enable clean build
Majormaxx Oct 16, 2025
d8566fb
feat: implement getSupportedChains and validateSafeConfig methods
Majormaxx Oct 16, 2025
8ee970e
refactor:module-fixes
shubh2294 Nov 7, 2025
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ package-lock.json
/lib/
.env
dist
mysql-data
mysql-data

14 changes: 14 additions & 0 deletions be2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
### API Endpoints
- **GET** `/payouts/rounds?orgId=` → List incomplete rounds.
- **GET** `/payouts/preview?roundId=` → Recipient list (human + base-unit), totals, preflight checks (balance, role), and chunk plan.
- **POST** `/payouts/propose` `{ roundId, tokenType }` → Build batched calls, create Safe transaction, propose it, store proposal, return Safe link.
- **GET** `/payouts/status?roundId=` → Poll Transaction Service for statuses; update records accordingly.

### Chunking logic (dev one-liner)
> “Build a batched Safe MultiSend of up to N recipients, `estimateGas`; if gas or calldata exceeds cap, split and re-estimate recursively until ≤ cap; store chunks as `tx_proposals` with `partIndex/partCount`.”


### Server-side Validations
- Wallet address validation and dedupe.
- Convert amounts using real `decimals()`.
- Balance checks for transfers; TP mint requires Safe to hold `MINTER_ROLE`.
Binary file added cb-local.sqlite
Binary file not shown.
199 changes: 199 additions & 0 deletions module.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# CollabBerry - Token Payments via SAFE Multisig (Spec)

## Scope (what this delivers)
- **Admin configuration (Module A)** - Set Safe, stablecoin, and recognition mode (TeamPoints mint or DAO token transfer).
- **Payouts (Module II)** - Workflow: *Preview → Propose → Sign → Execute* for round-based distributions (stablecoin + TP/DAO).
- **Status & History (Module III)** - Show chunked proposals per payout, Safe links, execution states, and **Export CSV**.
- **Manual payouts via Safe (Module IV)** - Ad-hoc transfers/mints with the same Safe flow, tracked & exportable.

### Core primitives used
- **Safe Protocol Kit** - Build batched MultiSend transactions via `createTransaction([...MetaTransactionData])`. Supports arrays of calls.

- **Safe API Kit / Transaction Service** - Propose, collect confirmations, and track execution status.

- **OpenZeppelin ERC-20 & AccessControl** - Always read `decimals()` (do not assume 18); manage roles (`hasRole`, `grantRole`) for TP minting.


---

## Module A - Admin Configuration (Safe & Tokens) [Recap]
- **UI**: Chain selector, Safe address, Stablecoin address, Recognition mode (TeamPoints mint | DAO token).
- **Backend validation**:
- Safe is a contract; (optionally) sanity-check via Safe Transaction Service.
- Token is ERC-20; fetch and cache `decimals()`.
- If TeamPoints (mint): Safe must have `MINTER_ROLE`. Enforce using AccessControl.
- **Why**: Ensures correctness for batched payouts using Safe.

---

## Module II - Payouts (Preview → Propose → Sign → Execute)

### Frontend Flow
1. **Rounds list** - Incomplete payoff rounds.
2. **Preview** - Table: members, stable & recognition amounts, totals, warnings (balance & role checks).
3. **Actions** - Buttons for “Create fiat transaction” and “Create recognition transaction.” Optional “Create both.”
4. **Post-propose** - Show “Pending in Safe” link; status auto-updates to Executed/Failed.

### API Endpoints
- **GET** `/payouts/rounds?orgId=` → List incomplete rounds.
- **GET** `/payouts/preview?roundId=` → Recipient list (human + base-unit), totals, preflight checks (balance, role), and chunk plan.
- **POST** `/payouts/propose` `{ roundId, tokenType }` → Build batched calls, create Safe transaction, propose it, store proposal, return Safe link.
- **GET** `/payouts/status?roundId=` → Poll Transaction Service for statuses; update records accordingly.

### Chunking logic (dev one-liner)
> “Build a batched Safe MultiSend of up to N recipients, `estimateGas`; if gas or calldata exceeds cap, split and re-estimate recursively until ≤ cap; store chunks as `tx_proposals` with `partIndex/partCount`.”


### Server-side Validations
- Wallet address validation and dedupe.
- Convert amounts using real `decimals()`.
- Balance checks for transfers; TP mint requires Safe to hold `MINTER_ROLE`.

---

## Module III - Status & History (+ Export)

### UI
- List payouts with status (Pending / Executed / Partial / Failed).
- Details: show `tx_proposals` (tokenType, chunk info, attempt, status, Safe link, timestamps), and recipients snapshot.
- **Retry** on failed proposals: creates new slot with `attempt+1` and links back to original.
- **Export CSV** of each payout.

### Export API
```javascript
Returns `text/csv` with columns:
round_id, payout_type, token_type, part_index, part_count, attempt,
safe_tx_hash, status, proposed_at, executed_at, explorer_url,
wallet_address, amount_human, amount_base_units, recipient_status, error
```

**Why**: Combines on-chain Safe metadata and DB snapshots for full audit trace.
Module IV - Manual Payouts via Safe (Enabled) Approach: Allow manual
payouts (stablecoin & TP mint) via Safe flow.

Requirements: Safe must have MINTER_ROLE to mint TP.

Identical validations, chunking, proposals, status, and exports as
Module II.

Why via Safe: Maintains multisig governance and trace.

## Data Model (Final)

### payouts

```

- id (uuid pk),
- organization_id (fk),
- round_id (nullable),
- status (draft\|proposed\|executed\|partial\|failed),
- total_stable_payout,
- total_recognition_payout,
- timestamps


```

### tx_proposals

```

- id (uuid pk),
- payout_id (fk),
- payout_type ('round'\|'manual'),
- token_type ('stablecoin'\|'recognition'),
- part_index (int),
- part_count (int),
- attempt (int, default 1),
- retry_of_tx_proposal_id (uuid, nullable),
- safeTxHash,
- status (proposed\|executed\|failed\|canceled),
- proposed_at,
- executed_at,
- payload_json,
- explorer_url

```

Mirrors Safe TS for status.

### payout_recipients

```

- id,
- payout_id,
- round_compensation_id (nullable),
- user_id,
- wallet_address_snapshot,
- token_type,
- token_address_snapshot,
- token_decimals_snapshot,
- amount_human,
- amount_base_units,
- tx_proposal_id,
- part_index,
- part_count,
- attempt (int, default 1),
- status (pending\|proposed\|executed\|failed\|skipped),
- error,
- timestamps

```
Immutable per-recipient snapshot.

## Milestones & Deliverables

- Module A - Admin Config setup & validation.
- Module II - Round-based payouts via Safe: Preview, Propose, Sign,
Execute.
- Module III - Status tracking, retry, and CSV export.
- Module IV - Manual payouts (stable & TP) via Safe.

## Global Acceptance Criteria

- All proposals created with Safe SDKs and signed via Safe UI.
- Accurate token decimal conversion.
- TP minting only when Safe holds rights.
- Chunking logic enforced.
- CSV exports fully traceable.

## Module ACCEPTANCE CRITERIA

## Module-I
Admin Configuration (Safe and Tokens)
Waiting for review
Configure Safe, stablecoin, and recognition mode (TeamPoints mint or DAO token).


Description
UI for chain selector, Safe address, stablecoin address, and recognition mode. Backend validation: Safe contract check, ERC-20 decimals, and MINTER_ROLE enforcement if TP minting.

Acceptance Criteria
Safe validated as contract
ERC-20 decimals cached
MINTER_ROLE enforced for TP minting
Deliverables
Admin config UI
Validation logic
Role checks

## Module-II

Round-based Payouts (Preview / Propose / Execute)
Not started
Implement payout rounds with preview, proposal to Safe, and execution tracking.

Description
Frontend flow: list incomplete rounds, preview table of recipients, propose transactions (fiat or recognition or both). API endpoints for preview, propose, and status. Includes chunking logic for MultiSend transactions.

Acceptance Criteria
Rounds list with preview and warnings
Safe proposals created and linked
Chunking logic enforced when calldata too large
Deliverables
Rounds UI
Preview API
Propose API
Status polling
14 changes: 11 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"start": "yarn build && node dist/src/index.js",
"start-background": "yarn build && node dist/src/roundsStartJob.index.js",
"export": "yarn build && node dist/src/export.js",
"dev": "npx ts-node-dev src/index.ts",
"dev": "npx ts-node-dev --src/index.ts",
"lint": "tslint --fix -c tslint.json 'src/**/*.ts'",
"test": "mocha --config test/.mocharc.yml"
},
Expand All @@ -19,6 +19,11 @@
"dependencies": {
"@aws-sdk/client-s3": "^3.669.0",
"@aws-sdk/lib-storage": "^3.669.0",
"@safe-global/api-kit": "^4.0.0",
"@safe-global/safe-core-sdk": "^3.3.5",
"@safe-global/safe-ethers-lib": "^1.9.4",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cors": "2.8.5",
"crypto": "1.0.1",
"desm": "1.3.1",
Expand All @@ -27,16 +32,18 @@
"express": "^4.20.0",
"express-validator": "^7.0.1",
"inversify": "6.0.2",
"inversify-express-utils": "^6.4.6",
"joi": "^17.4.0",
"jsonwebtoken": "9.0.2",
"multer": "^1.4.4",
"mysql2":"^3.11.3",
"mysql2": "^3.11.3",
"node-cron": "^3.0.0",
"nodemailer": "^6.6.3",
"passport": "^0.7.0",
"postmark": "^4.0.5",
"reflect-metadata": "^0.2.2",
"siwe": "^2.3.2",
"sqlite3": "^5.1.7",
"tslint-config-prettier": "^1.18.0",
"typeorm": "^0.3.20",
"uuid": "^8.3.2"
Expand All @@ -55,8 +62,9 @@
"@types/uuid": "^10.0.0",
"chai": "^5.1.1",
"chai-http": "^4.4.0",
"csv-writer":"^1.6.0",
"csv-writer": "^1.6.0",
"mocha": "^10.4.0",
"ts-mockito": "^2.6.1",
"ts-node": "^10.9.2",
"ts-node-dev": "2.0.0",
"tslint": "^6.1.3",
Expand Down
Loading