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;
}
}