Smart Donation Will Contract

What it does:
Enables users to create digital wills that automatically donate funds to chosen charities upon verification of death or predefined conditions.

Why it matters:
Ensures transparent, automated, and tamper-proof charitable giving, reduces reliance on intermediaries, and guarantees that donations are distributed as intended.

How it works:

  • Users create a will specifying charities and percentage allocations

  • Funds are deposited into the smart contract in advance

  • Verification (via oracles, legal services, or trusted signers) triggers fund distribution

  • Smart contract automatically splits and transfers funds to designated charities

  • Supports recurring charitable triggers or conditional donations

  • Integrates with Smart Will & Testament, Personal Data Vault, or Reputation-Based Governance

  • Dashboards show pending wills, executed donations, and fund allocations

      // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title SmartDonationWill
 * @author Nam
 * @notice Executes charitable donations automatically based on user-defined wills
 */
contract SmartDonationWill is Ownable {

    struct Charity {
        address payable charityAddress;
        uint256 percentage; // 0-100
    }

    struct DonationWill {
        address creator;
        uint256 totalAmount;
        Charity[] charities;
        bool executed;
    }

    mapping(uint256 => DonationWill) public wills;
    uint256 public willCount;

    mapping(address => bool) public authorizedOracles;

    // -------------------- EVENTS --------------------

    event OracleApproved(address oracle);
    event OracleRevoked(address oracle);
    event WillCreated(uint256 indexed willId, address creator, uint256 totalAmount);
    event WillExecuted(uint256 indexed willId);

    // -------------------- ORACLE MANAGEMENT --------------------

    function approveOracle(address _oracle) external onlyOwner {
        authorizedOracles[_oracle] = true;
        emit OracleApproved(_oracle);
    }

    function revokeOracle(address _oracle) external onlyOwner {
        authorizedOracles[_oracle] = false;
        emit OracleRevoked(_oracle);
    }

    modifier onlyOracle() {
        require(authorizedOracles[msg.sender], "Not authorized oracle");
        _;
    }

    // -------------------- WILL CREATION --------------------

    function createWill(address[] calldata _charities, uint256[] calldata _percentages) external payable {
        require(_charities.length == _percentages.length, "Mismatch lengths");
        uint256 totalPercent = 0;
        for (uint256 i = 0; i  0, "Must deposit funds");

        willCount += 1;
        DonationWill storage w = wills[willCount];
        w.creator = msg.sender;
        w.totalAmount = msg.value;
        w.executed = false;

        for (uint256 i = 0; i < _charities.length; i++) {
            w.charities.push(Charity({
                charityAddress: payable(_charities[i]),
                percentage: _percentages[i]
            }));
        }

        emit WillCreated(willCount, msg.sender, msg.value);
    }

    // -------------------- EXECUTION --------------------

    function executeWill(uint256 _willId) external onlyOracle {
        DonationWill storage w = wills[_willId];
        require(!w.executed, "Already executed");

        for (uint256 i = 0; i < w.charities.length; i++) {
            Charity storage c = w.charities[i];
            uint256 amount = (w.totalAmount * c.percentage) / 100;
            c.charityAddress.transfer(amount);
        }

        w.executed = true;
        emit WillExecuted(_willId);
    }

    // -------------------- VIEW FUNCTIONS --------------------

    function getWillCharities(uint256 _willId) external view returns (Charity[] memory) {
        return wills[_willId].charities;
    }
}