Savings Goals
Who it's for: Individuals saving toward a specific target — school fees, a business asset, a family event, or a down payment — who want their money to grow while it waits. Why it matters: Locking funds toward a named goal creates the discipline of a term deposit with the flexibility to bridge into a purchase the moment the goal matures.
Savings Goals let users lock cGHS for a defined period to meet a financial target — school fees, a phone, a car deposit. Funds earn yield inside the vault while locked. An optional early-exit penalty discourages premature withdrawal.
POST /goal/create
Request
{
"userAddressId": "wallet-uuid",
"userAddress": "0xabc...",
"stablecoin": "0x3126627A607E730E3eCF9BbfFD67fa18Deaab846",
"amount": "200000000",
"lockUntil": 1757548800,
"penaltyBps": 1000,
"name": "School Fees 2025"
}| Field | Constraints |
|---|---|
lockUntil | > now + 30 days and < now + 3 years |
penaltyBps | 0 – 2000 (max 20% early-exit penalty) |
name | Stored as bytes32 on-chain |
amount | Initial deposit in base units |
Transaction batch: [approve(lendingDiamond, amount), createGoal(stablecoin, amount, lockUntil, penaltyBps, nameBytes32)]
{ "id": "d1-uuid", "status": "pending" }POST /goal/:goalId/topup
Add more funds to an active goal before it matures.
Request{
"userAddressId": "wallet-uuid",
"userAddress": "0xabc...",
"amount": "50000000"
}POST /goal/:goalId/withdraw
Withdraw from a goal. Returns a preview of penalty before execution.
Response{
"id": "d1-uuid",
"status": "pending",
"preview": {
"gross": "230000000",
"penalty": "23000000",
"net": "207000000",
"isMature": false
}
}If isMature: true, penalty is 0 regardless of penaltyBps.
POST /goal/:goalId/buy
Use a matured savings goal as a down payment to trigger BNPL for a purchase. The goal assets fund the deposit and a lending pool covers the remainder in installments.
Request{
"userAddressId": "wallet-uuid",
"userAddress": "0xabc...",
"poolId": "1",
"merchant": "0xmerchant...",
"totalPrice": "500000000",
"numInstallments": 6,
"intervalSeconds": 2592000
}Requires: goal must be matured (lockUntil passed), and totalPrice > goalAssets.
Read Endpoints
GET /goal/:goalId — goal state + current assets
GET /goal/:goalId/preview — { gross, penalty, net, isMature }
GET /goal/user/:address — all goals for a user