Ad Revenue Distribution Contract
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);
}
}