Skip to content

Instantly share code, notes, and snippets.

@dima91
Created June 2, 2018 16:15
Show Gist options
  • Save dima91/f9f9c0904e3b542b126c3029697f51cc to your computer and use it in GitHub Desktop.
Save dima91/f9f9c0904e3b542b126c3029697f51cc to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.4.24+commit.e67f0147.js&optimize=true&gist=
pragma solidity ^0.4.24;
import "./sharedTypes.sol";
contract BaseContentManagementContract {
address private authorAddress; // Address of contract's author
address private catalogAddress; // Address of catalog to check if determined functions are called only by catalog
SharedTypes.contentType private typeOfContent; // Tpe of content which this contract contains
string private contentTitle; // Title which identifies this contract in catalog
string private content; // Content of resource
uint private numberOfViews; // Number of viwes about content of this contract
mapping (address => bool) allowedUsers; // Map of users that are allowed to access this content
constructor (SharedTypes.contentType _conType, string _conTitle, string _cnt, address _catAddr) public {
typeOfContent = _conType;
authorAddress= msg.sender;
numberOfViews= 0;
contentTitle= _conTitle;
content= _cnt;
catalogAddress= _catAddr;
}
// ***** ***** //
// ***** Modifiers ***** //
modifier onlyCatalog () {
require (msg.sender == catalogAddress);
_;
}
modifier onlyAllowedUsers (address _userAddr) {
require (allowedUsers[_userAddr] == true);
_;
}
// ***** ***** //
// ***** Helper private/internal functions ***** //
// ***** ***** //
// ***** Public functions ***** //
// Function used by catalog to check that has the same address of catalogAddress local variable
function getCatalogAddress () public view returns (address) {
return catalogAddress;
}
function getViewsCount () public view returns (uint) {
return numberOfViews;
}
function getTitle () public view returns (string) {
return contentTitle;
}
function getType () public view returns (SharedTypes.contentType) {
return typeOfContent;
}
// This function allows (only to catalog) to grant access to a user with address _userAddr
function grantAccessToUser (address _userAddr) public onlyCatalog () {
allowedUsers[_userAddr]= true;
}
/* This function allows subContracts of this contract to retreive content if and only if user
* with addrs _userAddr is into "allowedUsers" map
*/
function retreiveContent (address _userAddr) internal onlyAllowedUsers(_userAddr) returns (string) {
allowedUsers[_userAddr]= false;
numberOfViews++;
return content;
}
// ***** ***** //
// ***** Abastract functions ***** //
function consumeContent (address _userAddr) public returns (string);
}
pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "./sharedTypes.sol";
import "./ownable.sol";
import "./baseContentManagementContract.sol";
import "./contentManagementContracts.sol";
import "./stringUtils.sol";
contract CatalogSmartContract is Ownable {
// True if 'selfdestruct' function wasn't called --> is this necessary?
bool active= false;
// Mapping which contains a User struct for each user that hav published or have requeested a content
mapping (string => SharedTypes.User) usersMapping;
// Array containing addresses of users registered to system (for loop functions)
string [] usersArray;
// Number of user (also index of next user in the array)
uint usersCount;
// Mapping which contains an ExtendedContent struct for each content published on the platform (identified by a string)
mapping (string => SharedTypes.ExtendedContent) contentsMapping;
// Array containing addresses of contents published on the system (for loop functions)
string [] contentsArray;
// Number of contents (also index of next content in the array)
uint contentsCount;
constructor () public {
active= true;
usersCount=0;
contentsCount= 0;
}
// ***** ***** //
// ***** Modifiers ***** //
modifier isActive () {
require (active == true);
_;
}
modifier notPublished (string _contentTitle) {
require (alreadyPublished(_contentTitle) == false);
_;
}
modifier userExistsM (string _username) {
require (usersMapping[_username].exists == true);
_;
}
// ***** ***** //
// ***** Helper private functions ***** //
// Function to check if a user exists or not in usersMapping
function userExists (string _username) private view returns (bool){
return (usersMapping[_username].exists == true);
}
// Function which returns wether a content is already published on the platform
function alreadyPublished (string conTitle) private view returns (bool) {
return (contentsMapping[conTitle].exists == true);
}
// Function to register an user to system
function addUser (string _username, address _userAddr) private {
usersCount++;
usersArray.push (_username);
usersMapping[_username].userAddress= _userAddr;
usersMapping[_username].accType= SharedTypes.accountType.standard;
usersMapping[_username].exists= true;
usersMapping[_username].expirationTime= 0;
usersMapping[_username].latestContent = "";
}
// Function to add new content with address 'contAddr' registered by user with address 'userAddr'
function addContent (string _conTitle, address _contAddr, string _username) private {
contentsCount++;
contentsArray.push (_conTitle);
contentsMapping[_conTitle].exists= true;
contentsMapping[_conTitle].author= _username;
contentsMapping[_conTitle].contractAddress= _contAddr;
}
// ***** ***** //
// ***** Public functions ***** //
function killMe () public onlyOwner() {
active= false;
selfdestruct (owner);
}
// Function to link a content with the system
function publishContent (string _username, string _contentTitle, address _contentAddr) public {
if (!userExists(_username)) {
// Registering new user
addUser (_username, msg.sender);
}
addContent (_contentTitle, _contentAddr, _username);
}
// TODO Returns the number of views for each content
function getStatistics () public view returns (uint [], string []) {
uint [] memory stats;
string [] memory strs;
uint i= 0;
string memory tmpCnt;
for (i=0;i<contentsCount; i++) {
tmpCnt= contentsArray[i];
stats[i]= (BaseContentManagementContract (contentsMapping[tmpCnt].contractAddress)).getViewsCount();
strs[i]= tmpCnt;
}
return (stats, strs);
}
// Returns the list of contents without the number of views
function getContentList () public view returns (string []) {
string [] memory conList;
uint i=0;
for (i=0; i<contentsCount; i++) {
conList[i]= contentsArray[i];
}
return conList;
}
// Returns the list of x newest contents
function getNewContentList (uint _n) public view returns (string []) {
string [] memory newest;
uint i= 0;
uint count=0;
if (_n>contentsCount)
count=contentsCount;
else
count=_n;
while (count!=0) {
newest[i]= contentsArray[contentsCount-(++i)];
count--;
}
return newest;
}
// Returns the most recent content with genre x
function getLatestByGenre (SharedTypes.contentType _ct) public view returns (string) {
uint i= contentsCount;
bool found= false;
string memory reqStr= "";
if (contentsCount == 0) {
return "";
}
while (i != 0 && !found ) {
i--;
if ((BaseContentManagementContract(contentsMapping[contentsArray[i]].contractAddress)).getType() == _ct) {
found = true;
reqStr= (BaseContentManagementContract(contentsMapping[contentsArray[i]].contractAddress)).getTitle();
}
}
return reqStr;
}
// Returns the content with genre x, which has received the maximum number of views
function getMostPopularByGenre (SharedTypes.contentType _ct) public view returns (string) {
string memory reqStr= "";
uint maximum=0;
uint i= contentsCount;
if (contentsCount == 0) {
return "";
}
while (i != 0) {
i--;
BaseContentManagementContract remoteContract= BaseContentManagementContract(contentsMapping[contentsArray[i]].contractAddress);
if (remoteContract.getType() == _ct) {
if (remoteContract.getViewsCount() > maximum)
reqStr= remoteContract.getTitle();
}
}
return reqStr;
}
// Returns the most recent content of the author x
function getLatestByAuthor (string _author) public view returns (string) {
string memory reqStr;
bool found= false;
uint i= contentsCount;
if (contentsCount == 0) {
return "";
}
while (i != 0 && !found) {
i--;
string memory author= contentsMapping[contentsArray[i]].author;
if (StringUtils.equal (author, _author)) {
found = true;
reqStr= (BaseContentManagementContract(contentsMapping[contentsArray[i]].contractAddress)).getTitle();
}
}
return reqStr;
}
// Returns the content with most views of the author x
function getMostPopularByAuthor (string _author) public view returns (string) {
string memory reqStr= "";
uint maximum=0;
uint i= contentsCount;
if (contentsCount == 0) {
return "";
}
while (i != 0) {
i--;
BaseContentManagementContract remoteContract= BaseContentManagementContract(contentsMapping[contentsArray[i]].contractAddress);
if (StringUtils.equal (contentsMapping[contentsArray[i]].author, _author)) {
if (remoteContract.getViewsCount() > maximum)
reqStr= remoteContract.getTitle();
}
}
return reqStr;
}
// Returns true if x holds a still valid premium account, false otherwise
function isPremium (string _username) userExistsM (_username) public view returns (bool) {
return (usersMapping[_username].accType == SharedTypes.accountType.premium);
}
/* ********************************************* */
/* ********************************************* */
/* ********************************************* */
/* // Pays for access to content x
/*function getContent (...) public {
}
// Requests access to content x without paying, premium accounts only
function getContentPremium (...) public {
}
// Pays for granting access to content x to the user u
function giftContent (..., ...) public {
}
// Pays for granting a Premium Account to the user u
function giftPremium (...) public {
}
// Starts a new premium subscription
function buyPremium () public {
}
*/
}
pragma solidity ^0.4.24;
import "./baseContentManagementContract.sol";
contract SongManagementContract is BaseContentManagementContract {
constructor (string _cnt, string _title, address _catAddr)
BaseContentManagementContract(SharedTypes.contentType.song, _title, _cnt, _catAddr) public {
}
function consumeContent (address _userAddr) public returns (string) {
return retreiveContent (_userAddr);
}
}
/* ********************************************* */
/* ********************************************* */
/* ********************************************* */
contract VideoManagementContract is BaseContentManagementContract {
constructor (string _cnt, string _title, address _catAddr)
BaseContentManagementContract(SharedTypes.contentType.video, _title, _cnt, _catAddr) public {
}
function consumeContent (address _userAddr) public returns (string) {
return retreiveContent (_userAddr);
}
}
/* ********************************************* */
/* ********************************************* */
/* ********************************************* */
contract PhotoManagementContract is BaseContentManagementContract {
constructor (string _cnt, string _title, address _catAddr)
BaseContentManagementContract(SharedTypes.contentType.photo, _title, _cnt, _catAddr) public {
}
function consumeContent (address _userAddr) public returns (string) {
return retreiveContent (_userAddr);
}
}
/* ********************************************* */
/* ********************************************* */
/* ********************************************* */
contract DocumentManagementContract is BaseContentManagementContract {
constructor (string _cnt, string _title, address _catAddr)
BaseContentManagementContract(SharedTypes.contentType.document, _title, _cnt, _catAddr) public {
}
function consumeContent (address _userAddr) public returns (string) {
return retreiveContent (_userAddr);
}
}
pragma solidity ^0.4.24;
import "./mortal.sol";
contract Crowdfund {
struct Funder {
address addr;
uint amount;
}
struct Project {
bool created;
bool opened;
string name;
address owner;
mapping (uint => Funder) funders;
uint fundersSize;
uint amount;
uint fundingGoal;
}
event ProjectCreated (string _name, uint _fundingGoal);
event FundTransferred (address _backer, string _project, uint _amount, uint _remainingAmount);
event fundingGoalReached (string project);
address private owner;
mapping (string => Project) private projects;
modifier ProjectNotExists (string _name) {
require (projects[_name].created == false);
_;
}
modifier ProjectExists (string _name) {
require (projects[_name].created == true);
_;
}
constructor () public {
owner= msg.sender;
}
function createProject (string _projectName, uint _amount) public ProjectNotExists (_projectName) {
projects[_projectName]= Project (true, true, _projectName, msg.sender, 0, 0, _amount);
emit ProjectCreated (_projectName, _amount);
}
function sendMoney (string _projectName, uint _sum) public ProjectExists (_projectName) {
Project storage p= projects[_projectName];
p.funders[p.fundersSize]= Funder (msg.sender, _sum);
p.fundersSize++;
p.amount += _sum;
uint remaining= p.fundingGoal - _sum;
emit FundTransferred (msg.sender, _projectName, _sum, remaining);
checkGoalReached (_projectName);
}
function checkGoalReached (string _projectName) private returns (bool) {
Project storage p= projects[_projectName];
if (p.fundingGoal <= p.amount) {
emit fundingGoalReached (_projectName);
p.opened= false;
return true;
}
return false;
}
function getProject (string _projectName) public view returns (bool, address, uint, uint, uint, bool) {
Project storage p= projects[_projectName];
return (p.opened, p.owner, p.fundersSize, p.amount, p.fundingGoal, p.opened);
}
}
pragma solidity ^0.4.24;
contract Mortal {
address owner;
constructor () public {
owner= msg.sender;
}
function kill () public {
if (msg.sender == owner)
selfdestruct (owner);
}
}
pragma solidity ^0.4.24;
contract Ownable {
address owner;
constructor () public {
owner = msg.sender;
}
modifier onlyOwner () {
require (msg.sender == owner);
_;
}
}
pragma solidity ^0.4.24;
library SharedTypes {
// Kind of content
enum contentType {song, video, photo, document}
// Kind of account
enum accountType {standard, premium}
// Type for registered users, both authors or customers. This struct is stored in the catalog
struct User {
address userAddress; // Address of user (key value is the name)
bool exists; // To check if an user exists in the system
accountType accType; // Type of current account (default standard)
uint expirationTime; // Expiration time. Valid only for premium account
string latestContent; // Title of latest content published by current user
}
// Struct to hold togheter BasContentManagementContracts and list of users which payed to view these contents
// Title of content (a string) is the identifier of content
struct ExtendedContent {
bool exists; // To check if a content exists in the system
address contractAddress; // Contract's address associated to current content
string author; // Name of owner of content
// Others informations, about views and users which are granted to access to current content, are stored in BaseContentManagementContracts
}
}
pragma solidity ^0.4.24;
library StringUtils {
/// @dev Does a byte-by-byte lexicographical comparison of two strings.
/// @return a negative number if `_a` is smaller, zero if they are equal
/// and a positive numbe if `_b` is smaller.
function compare(string _a, string _b) private pure returns (int) {
bytes memory a = bytes(_a);
bytes memory b = bytes(_b);
uint minLength = a.length;
if (b.length < minLength) minLength = b.length;
//@todo unroll the loop into increments of 32 and do full 32 byte comparisons
for (uint i = 0; i < minLength; i ++)
if (a[i] < b[i])
return -1;
else if (a[i] > b[i])
return 1;
if (a.length < b.length)
return -1;
else if (a.length > b.length)
return 1;
else
return 0;
}
/// @dev Compares two strings and returns true iff they are equal.
function equal(string _a, string _b) public pure returns (bool) {
return compare(_a, _b) == 0;
}
/// @dev Finds the index of the first occurrence of _needle in _haystack
function indexOf(string _haystack, string _needle) public pure returns (int)
{
bytes memory h = bytes(_haystack);
bytes memory n = bytes(_needle);
if(h.length < 1 || n.length < 1 || (n.length > h.length))
return -1;
else if(h.length > (2**128 -1)) // since we have to be able to return -1 (if the char isn't found or input error), this function must return an "int" type with a max length of (2^128 - 1)
return -1;
else
{
uint subindex = 0;
for (uint i = 0; i < h.length; i ++)
{
if (h[i] == n[0]) // found the first char of b
{
subindex = 1;
while(subindex < n.length && (i + subindex) < h.length && h[i + subindex] == n[subindex]) // search until the chars don't match or until we reach the end of a or b
{
subindex++;
}
if(subindex == n.length)
return int(i);
}
}
return -1;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment