What it does:
Automatically collects advertising revenue and distributes it on-chain to publishers, creators, platforms, and referrers based on predefined allocation rules.
Why it matters:
Removes opaque ad networks, prevents revenue manipulation, enables instant payouts, and gives publishers full transparency into how ad money is calculated and distributed.
How it works:
Advertisers deposit campaign funds directly into the smart contract
Each ad impression, click, or conversion triggers revenue allocation logic
Revenue is split among stakeholders (publisher, creator, platform, referrer) by fixed percentages
Funds are accumulated in on-chain balances per stakeholder
Stakeholders can withdraw earnings at any time without waiting for monthly settlements
All revenue flows, events, and payouts are fully transparent and auditable on-chain
Integrates with websites, apps, games, and content platforms via oracles or signed reports
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title AdRevenueDistribution
* @author Nam
* @notice Distributes advertising revenue to multiple stakeholders transparently on-chain
*/
contract AdRevenueDistribution {
address public admin;
uint256 public campaignCount;
constructor() {
admin = msg.sender;
}
// -------------------- STRUCTS --------------------
struct Stakeholder {
address account;
uint256 share; // out of 10000 (basis points)
}
struct Campaign {
address advertiser;
uint256 budget;
uint256 spent;
Stakeholder[] stakeholders;
mapping(address => uint256) balances;
bool active;
}
mapping(uint256 => Campaign) public campaigns;
// -------------------- EVENTS --------------------
event CampaignCreated(uint256 indexed campaignId, address indexed advertiser, uint256 budget);
event RevenueDistributed(uint256 indexed campaignId, uint256 amount);
event StakeholderWithdrawal(uint256 indexed campaignId, address indexed stakeholder, uint256 amount);
event CampaignPaused(uint256 indexed campaignId);
event CampaignResumed(uint256 indexed campaignId);
// -------------------- MODIFIERS --------------------
modifier onlyAdmin() {
require(msg.sender == admin, "Not admin");
_;
}
modifier onlyAdvertiser(uint256 _campaignId) {
require(msg.sender == campaigns[_campaignId].advertiser, "Not advertiser");
_;
}
modifier campaignActive(uint256 _campaignId) {
require(campaigns[_campaignId].active, "Campaign not active");
_;
}
// -------------------- CAMPAIGN MANAGEMENT --------------------
function createCampaign(
Stakeholder[] calldata _stakeholders
) external payable returns (uint256) {
require(msg.value > 0, "Budget required");
require(_stakeholders.length > 0, "No stakeholders");
uint256 totalShares;
for (uint256 i = 0; i < _stakeholders.length; i++) {
totalShares += _stakeholders[i].share;
}
require(totalShares == 10000, "Shares must total 100%");
campaignCount += 1;
Campaign storage c = campaigns[campaignCount];
c.advertiser = msg.sender;
c.budget = msg.value;
c.active = true;
for (uint256 i = 0; i 0, "Invalid amount");
require(c.spent + _amount <= c.budget, "Budget exceeded");
c.spent += _amount;
for (uint256 i = 0; i 0, "No balance");
c.balances[msg.sender] = 0;
payable(msg.sender).transfer(amount);
emit StakeholderWithdrawal(_campaignId, msg.sender, amount);
}
function balanceOf(uint256 _campaignId, address _stakeholder) external view returns (uint256) {
return campaigns[_campaignId].balances[_stakeholder];
}
// -------------------- UNUSED BUDGET REFUND --------------------
function refundRemainingBudget(uint256 _campaignId)
external
onlyAdvertiser(_campaignId)
{
Campaign storage c = campaigns[_campaignId];
require(!c.active, "Pause campaign first");
uint256 remaining = c.budget - c.spent;
require(remaining > 0, "No remaining budget");
c.budget = c.spent;
payable(c.advertiser).transfer(remaining);
}
}
Build and Grow By Nam Le Thanh