Skip to content
This repository has been archived by the owner on Oct 11, 2018. It is now read-only.

Contracts for MVP #1

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.vscode/
.idea/

# Created by https://www.gitignore.io/api/osx,solidity

Expand Down Expand Up @@ -94,3 +95,5 @@ build/**


# End of https://www.gitignore.io/api/osx,solidity

truffle-config.js
9 changes: 0 additions & 9 deletions config.local.provider.js

This file was deleted.

51 changes: 51 additions & 0 deletions contracts/AirContainer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
pragma solidity ^0.4.23;

import "./AppRegistry.sol";

contract AirContainer {
using SafeMath for uint256;
using SafeERC20 for ERC20;

ERC20 public token;
AppRegistry public appReg;

struct Row {
bytes32 appId;
uint256 amount;
bool isValid;
}

mapping (bytes32 => Row) book;

constructor(ERC20 _token, AppRegistry _appReg) public {
token = _token;
appReg = _appReg;
}

function deposit(bytes32 appId, bytes32 dataId, uint256 amount) public {
if(hasRow(dataId)) {
book[dataId].amount.add(amount);
} else {
book[dataId] = Row(appId, amount, true);
}
}

function withdraw(bytes32 dataId) public {
require(
appReg.isAppOwner(book[dataId].appId, msg.sender),
"Only app owner can withdraw token."
);

uint256 amount = book[dataId].amount;
book[dataId].amount = 0;
token.safeTransfer(msg.sender, amount);
}

function stake(bytes32 dataId) public view returns (uint256) {
return book[dataId].amount;
}

function hasRow(bytes32 dataId) public view returns (bool) {
return book[dataId].isValid;
}
}
141 changes: 141 additions & 0 deletions contracts/App.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
pragma solidity ^0.4.23;

import "./RiskStake.sol";
import "./DataCategory.sol";

// Basic App info for minimum proof. Rest of the data is available on off-chain.
contract App is RiskStake {
using SafeERC20 for ERC20;
using SafeMath for uint256;

event CategoryAdded(bytes32 id);
event CategoryRemoved(bytes32 id);

event UserAdded(address indexed addr);
event UserRemoved(address indexed addr);
event UserModified(address indexed pastAddr, address indexed newAddr);

struct CategoryOfApp {
bytes32 categoryId;
uint256 shareUser;
uint256 shareApp;
bool isValid;
}

DataCategory dataCtg;

uint256 public userCount;
mapping (bytes32 => CategoryOfApp) public ctgOfApps;
mapping (bytes32 => address) private users; // TODO: Privacy consideration

constructor(
ERC20 _token,
address _receiver,
PunisherRegistry _punReg,
DataCategory _dataCtg
)
RiskStake(_token, _receiver, _punReg)
public
{
userCount = 0;
dataCtg = _dataCtg;
}

/**
* Manage data categories (for app)
*/
function addCategory(
bytes32 id,
bytes32 categoryId,
uint256 shareUser,
uint256 shareApp
) public onlyOwner {
require(!ctgOfApps[id].isValid, "Category already exists.");
require(dataCtg.validate(categoryId), "Invalid data category.");
ctgOfApps[id] = CategoryOfApp(categoryId, shareUser, shareApp, true);
emit CategoryAdded(id);
}

function removeCategory(bytes32 id) public onlyOwner {
delete ctgOfApps[id];
emit CategoryRemoved(id);
}

function validate(bytes32 id) public view returns (bool) {
return ctgOfApps[id].isValid;
}

// for validate category of apps which data owns it.
function validateCategories(bytes32[] ids) public view returns (bool) {
for (uint256 i = 0; i < ids.length; i++) {
if(!validate(ids[i])) {
return false;
}
}
return true;
}

/**
* Manage users in contract (Has/Add/Remove/Modify)
*/
function hasUser(bytes32 id) public view returns(bool) {
return users[id] != address(0);
}

function addUser(bytes32 id, address addr) public onlyOwner {
require(!hasUser(id), "User already exists.");
require(
stake() >= getRequiredStake(1),
"Insufficient stake amount."
);
users[id] = addr;
userCount = userCount.add(1);
emit UserAdded(addr);
}

function addUsers(bytes32[] ids, address[] addrs) public onlyOwner {
for (uint256 i = 0; i < ids.length; i++) {
addUser(ids[i], addrs[i]); // TODO: Need default receiver?
}
}

function removeUser(bytes32 id) public onlyOwner {
address addr = users[id];
delete users[id];
userCount = userCount.sub(1);
emit UserRemoved(addr);
}

function removeUsers(bytes32[] ids) public onlyOwner {
for (uint256 i = 0; i < ids.length; i++) {
removeUser(ids[i]);
}
}

function modifyUser(bytes32 id, address newAddr) public onlyOwner {
require(newAddr != address(0), "New address cannot be zero.");
address addr = users[id];
users[id] = newAddr;
emit UserModified(addr, newAddr);
}

/**
* About staking
*/
// @Override Stake.sol
function withdraw(uint256 amount) public onlyOwner {
require(
stake() - amount >= getRequiredStake(0),
"Insufficient stake amount."
);
super.withdraw(amount);
}

function getRequiredStake(uint256 _add)
public
view
returns (uint256)
{
return userCount + _add; // TODO: Add algorithm about staking amount
}
}
102 changes: 37 additions & 65 deletions contracts/AppRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
pragma solidity ^0.4.23;

import "openzeppelin-solidity/contracts/examples/SimpleToken.sol";
import "./RiskTokenLockRegistry.sol";
import "openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol";

import "./App.sol";

/**
* AppRegistry stores an app information, and user IDs of the app.
Expand All @@ -10,83 +11,54 @@ import "./RiskTokenLockRegistry.sol";
* If an app did some bad things that prohibited by Airbloc Protocol's Law,
* then there's a risk for app can LOSE some amount of it's stake.
*/
contract AppRegistry is RiskTokenLockRegistry {
contract AppRegistry {
using AddressUtils for address;
using SafeMath for uint256;

// Basic App info for minimum proof. Rest of the data is available on off-chain.
// TODO: Privacy considerations
struct App {
bytes32 id;
uint256 userCount;
mapping(address => bool) users;
}
ERC20 token;
address receiver;
PunisherRegistry punReg;

mapping(address => App) public apps;
mapping(bytes32 => address) public addressOf;
DataCategory dataCtg;
mapping(bytes32 => App) public apps;

event AppRegister(bytes32 appId, address appAddress);

/**
* @param token The address of token for stake.
* @param penaltyBeneficiary The destination wallet that stake losses are transferred to.
*/
constructor(ERC20 token, address penaltyBeneficiary, address punisher)
RiskTokenLockRegistry(token, penaltyBeneficiary, punisher)
public
{
}
event AppRegistered(bytes32 appId, address owner);
event AppUnregistered(bytes32 appId, address owner);

/**
* @param appId ID of off-chain app metadata.
*/
function register(bytes32 appId) public {
apps[msg.sender] = App(appId, 0);
addressOf[appId] = msg.sender;
emit AppRegister(appId, msg.sender);
constructor(
ERC20 _token,
address _receiver,
PunisherRegistry _punReg,
DataCategory _dataCtg
) public {
token = _token;
receiver = _receiver;
punReg = _punReg;
dataCtg = _dataCtg;
}

/**
* Add user to app.
*/
function addUser(address[] addedUsers) public {
require(hasAppOf(msg.sender), "App not found.");
require(
stakeOf(msg.sender) >= getRequiredStake(apps[msg.sender].userCount + addedUsers.length),
"Insufficient stake amount."
);
App app = apps[msg.sender];

for (uint256 i = 0; i < addedUsers.length; i++) {
app.users[addedUsers[i]] = true;
}
app.userCount = app.userCount.add(addedUsers.length);
function register(bytes32 appId) public {
apps[appId] = new App(token, receiver, punReg, dataCtg);
emit AppRegistered(appId, msg.sender);
}

function removeUser(address[] removedUsers) public {
require(hasAppOf(msg.sender), "App not found.");
App app = apps[msg.sender];

for (uint256 i = 0; i < removedUsers.length; i++) {
app.users[removedUsers[i]] = false;
}
app.userCount = app.userCount.sub(removedUsers.length);
}
function unregister(bytes32 appId) public {
require(hasAppOf(appId), "App not found.");
require(isAppOwner(appId, msg.sender), "Only app owner can do this.");

function withdraw(uint256 amount) public {
require(hasAppOf(msg.sender), "App not found.");
require(stakeOf(msg.sender) - amount >= getRequiredStake(apps[msg.sender].userCount));
super.withdraw(amount);
delete apps[appId];
emit AppUnregistered(appId, msg.sender);
}

function hasAppOf(address addr) internal view returns (bool) {
return apps[addr].id != bytes32(0x0);
function validateCategories(bytes32 appId, bytes32[] ids) public view returns (bool) {
return apps[appId].validateCategories(ids);
}

function hasUser(bytes32 appId, address user) public view returns (bool) {
return apps[addressOf[appId]].users[user];
function isAppOwner(bytes32 appId, address addr) public view returns (bool) {
return apps[appId].owner() == addr;
}

function getRequiredStake(uint256 userCount) public pure returns (uint256) {
return userCount;
function hasAppOf(bytes32 appId) public view returns (bool) {
return apps[appId].token() != address(0);
}
}
}
17 changes: 0 additions & 17 deletions contracts/AuthRegistry.sol

This file was deleted.

21 changes: 21 additions & 0 deletions contracts/DAuthRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
pragma solidity ^0.4.23;

contract DAuthRegistry {
// only store boolean value whether the user authorized Auth rule.
// @address user's address
// @bytes32 categoryOfApp Id
// @bool authorization
mapping(address => mapping(bytes32 => bool)) private registry;

function register(bytes32 categoryOfAppId, bool authorizations) public {
registry[msg.sender][categoryOfAppId] = authorizations;
}

function isUserAllowed(address user, bytes32 categoryOfAppId) public view returns (bool) {
return registry[user][categoryOfAppId];
}

function getAuthorization(bytes32 categoryOfAppId) public view returns (bool) {
return isUserAllowed(msg.sender, categoryOfAppId);
}
}
Loading