Created
July 27, 2017 04:41
-
-
Save bpeters/f1f7ba686302b10e48f4176731dde377 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.11; | |
library SafeMath { | |
function mul(uint a, uint b) internal returns (uint) { | |
uint c = a * b; | |
assert(a == 0 || c / a == b); | |
return c; | |
} | |
function div(uint a, uint b) internal returns (uint) { | |
uint c = a / b; | |
return c; | |
} | |
function sub(uint a, uint b) internal returns (uint) { | |
assert(b <= a); | |
return a - b; | |
} | |
function add(uint a, uint b) internal returns (uint) { | |
uint c = a + b; | |
assert(c >= a); | |
return c; | |
} | |
} | |
library DataMath { | |
using SafeMath for uint; | |
function paymentToData(uint conversion, uint payment) internal returns (int) { | |
return int(payment.div(conversion)); | |
} | |
function dataToPayment(uint conversion, int data) internal returns (uint) { | |
return uint(data).mul(conversion); | |
} | |
function add(uint a, uint b) internal returns (uint) { | |
return a.add(b); | |
} | |
function sub(uint a, uint b) internal returns (uint) { | |
return a.sub(b); | |
} | |
function mul(uint a, uint b) internal returns (uint) { | |
return a.mul(b); | |
} | |
function div(uint a, uint b) internal returns (uint) { | |
return a.div(b); | |
} | |
} | |
contract HasSIMs { | |
struct SIM { | |
uint index; // pointer to simList index | |
uint userIndex; // pointer to sims index on user | |
address user; // address of user | |
int dataPaid; // data in bytes paid for | |
int dataConsumed; // total data in bytes consumed | |
bool isActivated; // if the SIM is activated or not | |
bool updateStatus; // if the SIM should flip it's status from oracle | |
} | |
mapping (bytes32 => SIM) sims; | |
bytes32[] simList; | |
modifier mustBeSIM(bytes32 sim) { | |
require(isSIM(sim)); | |
_; | |
} | |
function isSIM(bytes32 sim) public constant returns (bool) { | |
if (simList.length == 0) { | |
return false; | |
} | |
return simList[sims[sim].index] == sim; | |
} | |
function getSIM(bytes32 sim) public constant mustBeSIM(sim) returns (address user, int dataPaid, int dataConsumed, bool isActivated, bool updateStatus) { | |
return (sims[sim].user, sims[sim].dataPaid, sims[sim].dataConsumed, sims[sim].isActivated, sims[sim].updateStatus); | |
} | |
} | |
contract HasUsers is HasSIMs { | |
struct User { | |
uint index; | |
uint balance; // refundable amount for the user | |
int data; // amount of data in bytes available | |
bytes32[] sims; // registered SIMs the user owns | |
} | |
mapping (address => User) users; | |
address[] userList; | |
modifier senderMustBeUser() { | |
require(isUser(msg.sender)); | |
_; | |
} | |
modifier mustBeSenderSIM(bytes32 sim) { | |
require(isUserSIM(msg.sender, sim)); | |
_; | |
} | |
function isUser(address user) public constant returns (bool) { | |
if (userList.length == 0) { | |
return false; | |
} | |
return userList[users[user].index] == user; | |
} | |
function isUserSIM(address user, bytes32 sim) public constant returns (bool) { | |
if (!isUser(user)) { | |
return false; | |
} | |
if (!isSIM(sim)) { | |
return false; | |
} | |
return sims[sim].user == user; | |
} | |
function getUser() public constant senderMustBeUser returns (uint balance, int data, bytes32[] sims) { | |
return (users[msg.sender].balance, users[msg.sender].data, users[msg.sender].sims); | |
} | |
function deposit() public payable senderMustBeUser { | |
users[msg.sender].balance += msg.value; | |
} | |
function withdraw(uint withdrawAmount) public senderMustBeUser { | |
require(withdrawAmount <= users[msg.sender].balance); | |
users[msg.sender].balance -= withdrawAmount; | |
if (!msg.sender.send(withdrawAmount)) { | |
users[msg.sender].balance += withdrawAmount; | |
} | |
} | |
} | |
contract Ownable { | |
address public owner; | |
uint public balance; | |
function Ownable() { | |
owner = msg.sender; | |
} | |
modifier onlyOwner() { | |
require(msg.sender == owner); | |
_; | |
} | |
function transferOwnership(address newOwner) onlyOwner { | |
if (newOwner != address(0)) { | |
owner = newOwner; | |
} | |
} | |
function withdrawBalance(uint withdrawAmount) public onlyOwner { | |
require(withdrawAmount <= balance); | |
balance -= withdrawAmount; | |
if (!msg.sender.send(withdrawAmount)) { | |
balance += withdrawAmount; | |
} | |
} | |
function () { | |
revert(); | |
} | |
} | |
contract Lava is Ownable, HasUsers { | |
using DataMath for uint; | |
uint public activationFee = 0.04 ether; // fee to register & activate SIM | |
uint public minimumBalance = 0.04 ether; // balance needed on account to keep SIM active | |
uint public etherPerByte = 0.000002 ether; // eth cost per byte of data | |
uint public lastPrice = 0.000002 ether; // last etherPerByte price | |
uint public lowestPrice = 0.000002 ether; // historically lowest etherPerByte price | |
uint public highestPrice = 0.000002 ether; // historically highest etherPerByte price | |
event LogActivateSIM(address user, bytes32 sim); | |
event LogDeactivateSIM(address user, bytes32 sim); | |
modifier greaterThanZero(uint cost) { | |
require(cost > 0); | |
_; | |
} | |
function setBounty() public payable onlyOwner greaterThanZero(msg.value) { | |
balance += msg.value; | |
} | |
function setActivationFee(uint cost) public onlyOwner greaterThanZero(cost) { | |
activationFee = cost; | |
} | |
function setMinimumBalance(uint cost) public onlyOwner greaterThanZero(cost) { | |
minimumBalance = cost; | |
} | |
function setEtherPerByte(uint cost) public onlyOwner greaterThanZero(cost) { | |
lastPrice = etherPerByte; | |
etherPerByte = cost; | |
if (cost > highestPrice) { | |
highestPrice = cost; | |
} | |
if (cost < lowestPrice) { | |
lowestPrice = cost; | |
} | |
} | |
function updateSIMStatus(bytes32 sim) public onlyOwner mustBeSIM(sim) { | |
require(sims[sim].updateStatus); | |
sims[sim].isActivated = !sims[sim].isActivated; | |
sims[sim].updateStatus = false; | |
} | |
function collect(int dataConsumed, bytes32 sim) public onlyOwner mustBeSIM(sim) { | |
require(dataConsumed > 0); | |
SIM userSIM = sims[sim]; | |
User user = users[userSIM.user]; | |
int dataPaid = userSIM.dataPaid; | |
int newDataPaid = dataConsumed; | |
int dataOwed = dataConsumed - dataPaid; | |
if (dataOwed > user.data) { | |
uint payableAmount = etherPerByte.dataToPayment(dataOwed - user.data); | |
if (user.balance < payableAmount) { | |
payableAmount = user.balance; | |
newDataPaid = dataPaid + etherPerByte.paymentToData(payableAmount); | |
} | |
user.data = 0; | |
user.balance -= payableAmount; | |
balance += payableAmount; | |
} else { | |
user.data -= dataOwed; | |
} | |
userSIM.dataPaid = newDataPaid; | |
userSIM.dataConsumed = dataConsumed; | |
if (user.balance < minimumBalance) { | |
if (userSIM.isActivated) { | |
userSIM.updateStatus = true; | |
LogDeactivateSIM(userSIM.user, sim); | |
} | |
} | |
} | |
function register(bytes32 sim) public payable { | |
uint fees = activationFee.add(minimumBalance); | |
require(msg.value >= fees); | |
require(!isSIM(sim)); | |
if (!isUser(msg.sender)) { | |
users[msg.sender].index = userList.push(msg.sender) - 1; | |
} | |
balance += activationFee; | |
users[msg.sender].balance += minimumBalance; | |
uint extra = msg.value.sub(fees); | |
if (extra > 0) { | |
users[msg.sender].data += etherPerByte.paymentToData(extra); | |
balance += extra; | |
} | |
sims[sim] = SIM( | |
{ | |
index: simList.push(sim) - 1, | |
userIndex: users[msg.sender].sims.push(sim) - 1, | |
user: msg.sender, | |
dataPaid: 0, | |
dataConsumed: 0, | |
isActivated: false, | |
updateStatus: true | |
} | |
); | |
LogActivateSIM(msg.sender, sim); | |
} | |
function purchaseData() public payable senderMustBeUser greaterThanZero(msg.value) { | |
users[msg.sender].data += etherPerByte.paymentToData(msg.value); | |
balance += msg.value; | |
} | |
function sellData(int dataAmount) public payable senderMustBeUser { | |
require(dataAmount <= users[msg.sender].data); | |
uint amount = etherPerByte.dataToPayment(dataAmount); | |
require(balance > amount); | |
users[msg.sender].data -= dataAmount; | |
users[msg.sender].balance += amount; | |
balance -= amount; | |
} | |
function flipSIMStatus(bytes32 sim) public mustBeSenderSIM(sim) { | |
require(!sims[sim].updateStatus); | |
if (!sims[sim].isActivated) { | |
require(users[msg.sender].balance >= minimumBalance); | |
LogActivateSIM(msg.sender, sim); | |
} else { | |
LogDeactivateSIM(msg.sender, sim); | |
} | |
sims[sim].updateStatus = true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment