Skip to content

Instantly share code, notes, and snippets.

@bpeters
Created July 27, 2017 04:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bpeters/f1f7ba686302b10e48f4176731dde377 to your computer and use it in GitHub Desktop.
Save bpeters/f1f7ba686302b10e48f4176731dde377 to your computer and use it in GitHub Desktop.
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