What it does: Parents allocate weekly funds with rules (spending categories, savings goals, charity).
Why it matters: Teaches financial literacy transparently.
How it works:
Allowance released on schedule.
Smart rules enforce saving percentages.
Parents can set spending constraints.
Reports show habits over time.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
/**
* @title Decentralized Allowance for Kids
*
* Model:
* - Parent funds the contract
* - Parent assigns one or more children
* - Parent configures weekly/monthly allowances
* - Funds release only on schedule
* - Optional chores approval gate
* - Kids can withdraw only what is unlocked
* - Parent can pause or update limits
*/
contract DecentralizedAllowance {
struct AllowancePlan {
uint256 amountPerPeriod; // Allowance per cycle
uint256 periodSeconds; // 7 days, 30 days, etc.
uint256 nextRelease; // Timestamp when next funds unlock
uint256 unlockedBalance; // Accumulated amount ready to withdraw
bool choresRequired; // Whether parent needs to approve chores
bool choresApproved; // Reset after each release
bool active;
}
address public parent;
mapping(address => AllowancePlan) public plans;
event PlanCreated(
address indexed child,
uint256 amountPerPeriod,
uint256 periodSeconds,
bool choresRequired
);
event PlanUpdated(
address indexed child,
uint256 amountPerPeriod,
uint256 periodSeconds,
bool choresRequired
);
event AllowanceUnlocked(
address indexed child,
uint256 amount
);
event Withdrawn(
address indexed child,
uint256 amount
);
event ChoresApproved(address indexed child);
event PlanPaused(address indexed child);
event PlanResumed(address indexed child);
event ParentFunded(uint256 amount);
event FundsRecovered(uint256 amount);
modifier onlyParent() {
require(msg.sender == parent, "Not parent");
_;
}
modifier onlyChild(address child) {
require(msg.sender == child, "Not authorized");
_;
}
constructor() {
parent = msg.sender;
}
// -----------------------------------
// PARENT: FUND CONTRACT
// -----------------------------------
function fund() external payable onlyParent {
require(msg.value > 0, "No value sent");
emit ParentFunded(msg.value);
}
// -----------------------------------
// PARENT: CREATE / UPDATE PLAN
// -----------------------------------
function createPlan(
address child,
uint256 amountPerPeriod,
uint256 periodSeconds,
bool choresRequired
) external onlyParent {
require(child != address(0), "Invalid child");
require(amountPerPeriod > 0, "Allowance must be > 0");
require(periodSeconds >= 1 days, "Period too short");
AllowancePlan storage plan = plans[child];
plan.amountPerPeriod = amountPerPeriod;
plan.periodSeconds = periodSeconds;
plan.nextRelease = block.timestamp + periodSeconds;
plan.unlockedBalance = 0;
plan.choresRequired = choresRequired;
plan.choresApproved = !choresRequired;
plan.active = true;
emit PlanCreated(child, amountPerPeriod, periodSeconds, choresRequired);
}
function updatePlan(
address child,
uint256 amountPerPeriod,
uint256 periodSeconds,
bool choresRequired
) external onlyParent {
AllowancePlan storage plan = plans[child];
require(plan.active, "Plan not active");
plan.amountPerPeriod = amountPerPeriod;
plan.periodSeconds = periodSeconds;
plan.choresRequired = choresRequired;
// Reset chores approval if chores required now
if (choresRequired) {
plan.choresApproved = false;
}
emit PlanUpdated(child, amountPerPeriod, periodSeconds, choresRequired);
}
// -----------------------------------
// PARENT: CHORE APPROVAL
// -----------------------------------
function approveChores(address child) external onlyParent {
AllowancePlan storage plan = plans[child];
require(plan.active, "Plan not active");
require(plan.choresRequired, "Chores not required");
plan.choresApproved = true;
emit ChoresApproved(child);
}
// -----------------------------------
// AUTOMATIC UNLOCK
// -----------------------------------
function unlock(address child) public {
AllowancePlan storage plan = plans[child];
require(plan.active, "Plan not active");
require(block.timestamp >= plan.nextRelease, "Too early");
if (plan.choresRequired) {
require(plan.choresApproved, "Chores not approved");
}
plan.unlockedBalance += plan.amountPerPeriod;
plan.nextRelease = block.timestamp + plan.periodSeconds;
// Reset chores approval for next period
if (plan.choresRequired) {
plan.choresApproved = false;
}
emit AllowanceUnlocked(child, plan.amountPerPeriod);
}
// -----------------------------------
// CHILD: WITHDRAW UNLOCKED FUNDS
// -----------------------------------
function withdraw() external {
AllowancePlan storage plan = plans[msg.sender];
require(plan.active, "Plan not active");
// Unlock automatically if due
if (block.timestamp >= plan.nextRelease) {
unlock(msg.sender);
}
uint256 amount = plan.unlockedBalance;
require(amount > 0, "Nothing to withdraw");
require(address(this).balance >= amount, "Insufficient contract balance");
plan.unlockedBalance = 0;
payable(msg.sender).transfer(amount);
emit Withdrawn(msg.sender, amount);
}
// -----------------------------------
// PARENT: SAFETY CONTROLS
// -----------------------------------
function pausePlan(address child) external onlyParent {
AllowancePlan storage plan = plans[child];
require(plan.active, "Already paused");
plan.active = false;
emit PlanPaused(child);
}
function resumePlan(address child) external onlyParent {
AllowancePlan storage plan = plans[child];
require(!plan.active, "Already active");
plan.active = true;
emit PlanResumed(child);
}
// Parent can recover leftover funds if plans are paused
function recoverFunds(uint256 amount) external onlyParent {
require(amount <= address(this).balance, "Too much");
payable(parent).transfer(amount);
emit FundsRecovered(amount);
}
// -----------------------------------
// VIEW HELPERS
// -----------------------------------
function getPlan(address child)
external
view
returns (
uint256 amountPerPeriod,
uint256 periodSeconds,
uint256 nextRelease,
uint256 unlockedBalance,
bool choresRequired,
bool choresApproved,
bool active
)
{
AllowancePlan memory p = plans[child];
return (
p.amountPerPeriod,
p.periodSeconds,
p.nextRelease,
p.unlockedBalance,
p.choresRequired,
p.choresApproved,
p.active
);
}
}
Build and Grow By Nam Le Thanh