← Back to Developer Resources
Smart Contract Documentation
Core Contracts
SDM Token (ERC-20)
The SDM token is the native utility token of the Diamondz Shadow ecosystem. It follows the ERC-20 standard with additional functionality for the Proof of Contribution mechanism.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
contract SDMToken is ERC20, ERC20Burnable, Pausable, AccessControl {
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant ORACLE_ROLE = keccak256("ORACLE_ROLE");
// Oracle-related variables
uint256 public viewCount;
uint256 public subscriberCount;
uint256 public lastUpdated;
event OracleDataUpdated(uint256 viewCount, uint256 subscriberCount, uint256 timestamp);
constructor() ERC20("Diamondz Shadow Movies Token", "SDM") {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(PAUSER_ROLE, msg.sender);
_grantRole(MINTER_ROLE, msg.sender);
_grantRole(ORACLE_ROLE, msg.sender);
}
function pause() public onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() public onlyRole(PAUSER_ROLE) {
_unpause();
}
function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
_mint(to, amount);
}
function updateOracleData(uint256 _viewCount, uint256 _subscriberCount) public onlyRole(ORACLE_ROLE) {
viewCount = _viewCount;
subscriberCount = _subscriberCount;
lastUpdated = block.timestamp;
emit OracleDataUpdated(_viewCount, _subscriberCount, block.timestamp);
}
function _beforeTokenTransfer(address from, address to, uint256 amount)
internal
whenNotPaused
override
{
super._beforeTokenTransfer(from, to, amount);
}
}
Key Functions
- • mint(address to, uint256 amount)
- • burn(uint256 amount)
- • updateOracleData(uint256 _viewCount, uint256 _subscriberCount)
- • pause() / unpause()
YouTube Oracle
The YouTube Oracle contract is responsible for bringing YouTube metrics on-chain and updating the token economics based on these metrics.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
import "./interfaces/ISDMToken.sol";
contract YouTubeOracle is AccessControl, ChainlinkClient {
using Chainlink for Chainlink.Request;
bytes32 public constant ORACLE_UPDATER_ROLE = keccak256("ORACLE_UPDATER_ROLE");
address public sdmToken;
bytes32 private jobId;
uint256 private fee;
// YouTube channel data
string public channelId;
uint256 public viewCount;
uint256 public subscriberCount;
uint256 public lastUpdated;
event OracleDataRequested(bytes32 requestId);
event OracleDataFulfilled(bytes32 requestId, uint256 viewCount, uint256 subscriberCount);
constructor(address _sdmToken, address _link, address _oracle, string memory _jobId) {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ORACLE_UPDATER_ROLE, msg.sender);
sdmToken = _sdmToken;
setChainlinkToken(_link);
setChainlinkOracle(_oracle);
jobId = bytes32(bytes(_jobId));
fee = 0.1 * 10 ** 18; // 0.1 LINK
channelId = "UCxxx..."; // Diamondz Shadow YouTube channel ID
}
function requestYouTubeData() public onlyRole(ORACLE_UPDATER_ROLE) returns (bytes32 requestId) {
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
// Set the URL to perform the GET request on
request.add("get", string(abi.encodePacked("https://www.googleapis.com/youtube/v3/channels?part=statistics&id=", channelId)));
// Set the path to find the desired data in the API response
request.add("path", "items.0.statistics.viewCount");
request.add("path", "items.0.statistics.subscriberCount");
// Send the request
bytes32 _requestId = sendChainlinkRequestTo(chainlinkOracleAddress(), request, fee);
emit OracleDataRequested(_requestId);
return _requestId;
}
function fulfill(bytes32 _requestId, uint256 _viewCount, uint256 _subscriberCount) public recordChainlinkFulfillment(_requestId) {
viewCount = _viewCount;
subscriberCount = _subscriberCount;
lastUpdated = block.timestamp;
// Update the token contract with the new data
ISDMToken(sdmToken).updateOracleData(_viewCount, _subscriberCount);
emit OracleDataFulfilled(_requestId, _viewCount, _subscriberCount);
}
// Manual update function for testing or emergency updates
function manualUpdate(uint256 _viewCount, uint256 _subscriberCount) public onlyRole(ORACLE_UPDATER_ROLE) {
viewCount = _viewCount;
subscriberCount = _subscriberCount;
lastUpdated = block.timestamp;
// Update the token contract with the new data
ISDMToken(sdmToken).updateOracleData(_viewCount, _subscriberCount);
}
}
Key Functions
- • requestYouTubeData()
- • fulfill(bytes32 _requestId, uint256 _viewCount, uint256 _subscriberCount)
- • manualUpdate(uint256 _viewCount, uint256 _subscriberCount)
Contribution Tracker
The Contribution Tracker contract is responsible for tracking and rewarding user contributions to the ecosystem.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./interfaces/ISDMToken.sol";
contract ContributionTracker is AccessControl {
bytes32 public constant CONTRIBUTOR_ROLE = keccak256("CONTRIBUTOR_ROLE");
bytes32 public constant VALIDATOR_ROLE = keccak256("VALIDATOR_ROLE");
address public sdmToken;
// Contribution types
enum ContributionType {
ContentCreation,
CommunityEngagement,
TechnicalContribution,
GovernanceParticipation,
CommunityBuilding
}
// Contribution structure
struct Contribution {
address contributor;
ContributionType contributionType;
uint256 points;
string description;
uint256 timestamp;
bool validated;
}
// Mapping from contributor address to their contributions
mapping(address => Contribution[]) public contributions;
// Mapping from contributor address to their total points
mapping(address => uint256) public contributionPoints;
// Total points in the system
uint256 public totalPoints;
// Early adopter multiplier (2x until mainnet launch)
uint256 public earlyAdopterMultiplier = 2;
event ContributionSubmitted(address indexed contributor, uint256 contributionId, ContributionType contributionType, uint256 points);
event ContributionValidated(address indexed contributor, uint256 contributionId);
event PointsRewarded(address indexed contributor, uint256 points, uint256 tokens);
constructor(address _sdmToken) {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(VALIDATOR_ROLE, msg.sender);
sdmToken = _sdmToken;
}
function submitContribution(
ContributionType _type,
string memory _description
) public returns (uint256) {
// Assign points based on contribution type
uint256 points;
if (_type == ContributionType.ContentCreation) {
points = 50; // Base points for content creation
} else if (_type == ContributionType.CommunityEngagement) {
points = 10; // Base points for community engagement
} else if (_type == ContributionType.TechnicalContribution) {
points = 30; // Base points for technical contribution
} else if (_type == ContributionType.GovernanceParticipation) {
points = 15; // Base points for governance participation
} else if (_type == ContributionType.CommunityBuilding) {
points = 20; // Base points for community building
}
// Apply early adopter multiplier if enabled
if (earlyAdopterMultiplier > 1) {
points = points * earlyAdopterMultiplier;
}
// Create the contribution
Contribution memory newContribution = Contribution({
contributor: msg.sender,
contributionType: _type,
points: points,
description: _description,
timestamp: block.timestamp,
validated: false
});
// Add to the contributor's contributions
contributions[msg.sender].push(newContribution);
uint256 contributionId = contributions[msg.sender].length - 1;
emit ContributionSubmitted(msg.sender, contributionId, _type, points);
return contributionId;
}
function validateContribution(address _contributor, uint256 _contributionId) public onlyRole(VALIDATOR_ROLE) {
require(_contributionId < contributions[_contributor].length, "Contribution does not exist");
require(!contributions[_contributor][_contributionId].validated, "Contribution already validated");
// Mark as validated
contributions[_contributor][_contributionId].validated = true;
// Add points to contributor's total
uint256 points = contributions[_contributor][_contributionId].points;
contributionPoints[_contributor] += points;
totalPoints += points;
emit ContributionValidated(_contributor, _contributionId);
}
function distributeRewards(uint256 _tokenAmount) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(totalPoints > 0, "No contributions to reward");
for (uint256 i = 0; i < getRoleMembers(CONTRIBUTOR_ROLE).length; i++) {
address contributor = getRoleMembers(CONTRIBUTOR_ROLE)[i];
if (contributionPoints[contributor] > 0) {
// Calculate tokens based on proportion of total points
uint256 tokens = (_tokenAmount * contributionPoints[contributor]) / totalPoints;
// Mint tokens to the contributor
ISDMToken(sdmToken).mint(contributor, tokens);
emit PointsRewarded(contributor, contributionPoints[contributor], tokens);
// Reset points after distribution
contributionPoints[contributor] = 0;
}
}
// Reset total points
totalPoints = 0;
}
function getContributionsCount(address _contributor) public view returns (uint256) {
return contributions[_contributor].length;
}
function getContribution(address _contributor, uint256 _contributionId) public view returns (
ContributionType contributionType,
uint256 points,
string memory description,
uint256 timestamp,
bool validated
) {
require(_contributionId < contributions[_contributor].length, "Contribution does not exist");
Contribution memory contribution = contributions[_contributor][_contributionId];
return (
contribution.contributionType,
contribution.points,
contribution.description,
contribution.timestamp,
contribution.validated
);
}
function setEarlyAdopterMultiplier(uint256 _multiplier) public onlyRole(DEFAULT_ADMIN_ROLE) {
earlyAdopterMultiplier = _multiplier;
}
function getRoleMembers(bytes32 role) internal view returns (address[] memory) {
uint256 count = getRoleMemberCount(role);
address[] memory members = new address[](count);
for (uint256 i = 0; i < count; i++) {
members[i] = getRoleMember(role, i);
}
return members;
}
}
Key Functions
- • submitContribution(ContributionType _type, string memory _description)
- • validateContribution(address _contributor, uint256 _contributionId)
- • distributeRewards(uint256 _tokenAmount)
Contract Interfaces
Our contracts use standardized interfaces to ensure interoperability and easy integration.
ISDMToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
interface ISDMToken {
function mint(address to, uint256 amount) external;
function burn(uint256 amount) external;
function updateOracleData(uint256 _viewCount, uint256 _subscriberCount) external;
}
For technical support or contract inquiries:
development@diamondzshadow.com