2018-03-27 13:33:33 -04:00

186 lines
5.9 KiB
Solidity
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

pragma solidity ^0.4.17;
import "../token/MiniMeToken.sol";
import "../common/Controlled.sol";
/**
* @title MessageTribute
* @author Richard Ramos (Status Research & Development GmbH)
* @dev Inspired by one of Satoshi Nakamotos original suggested use cases for Bitcoin,
we will be introducing an economics-based anti-spam filter, in our case for
receiving messages and “cold” contact requests from users.
SNT is deposited, and transferred from stakeholders to recipients upon receiving
a reply from the recipient.
*/
contract MessageTribute is Controlled {
MiniMeToken public SNT;
struct Fee {
uint256 amount;
bool tribute;
bool permanent;
}
mapping(address => mapping(address => Fee)) public feeCatalog;
mapping(address => uint256) public balances;
mapping(bytes32 => uint256) private friendIndex;
address[] private friends;
struct Audience {
uint256 blockNum;
uint256 timestamp;
Fee fee;
bytes32 hashedSecret;
}
mapping(address => mapping(address => Audience)) audienceRequested;
function MessageTribute(MiniMeToken _SNT) public {
SNT = _SNT;
}
function addFriends(address[] _friends) public {
uint256 len = _friends.length;
for (uint256 i = 0; i < len; i++) {
bytes32 frHash = keccak256(_friends[i], msg.sender);
if (friendIndex[frHash] == 0)
friendIndex[frHash] = friends.push(_friends[i]);
}
}
function removeFriends(address[] _friends) public {
uint256 len = _friends.length;
for (uint256 i = 0; i < len; i++) {
bytes32 frHash = keccak256(_friends[i], msg.sender);
require(friendIndex[frHash] > 0);
uint index = friendIndex[frHash] - 1;
delete friendIndex[frHash];
address replacer = friends[friends.length - 1];
friends[index] = replacer;
friendIndex[keccak256(replacer, msg.sender)] = index;
friends.length--;
}
}
function areFriends(address sourceAccount, address accountToCheck) public view returns(bool) {
return friendIndex[keccak256(accountToCheck, sourceAccount)] > 0;
}
function setRequiredTribute(address _to, uint _amount, bool _isTribute, bool _isPermanent) public {
require(friendIndex[keccak256(msg.sender, _to)] == 0);
feeCatalog[msg.sender][_to] = Fee(_amount, _isTribute, _isPermanent);
}
function getRequiredFee(address _from) public view
returns (uint256 fee, bool tribute)
{
Fee memory f = getFee(_from);
fee = f.amount;
tribute = f.tribute;
}
function deposit(uint256 _value) public {
require(_value > 0);
balances[msg.sender] += _value;
require(SNT.transferFrom(msg.sender, address(this), _value));
}
function balance() public view returns (uint256) {
return balances[msg.sender];
}
function withdraw(uint256 _value) public {
require(balances[msg.sender] > 0);
require(_value <= balances[msg.sender]);
balances[msg.sender] -= _value;
require(SNT.transfer(msg.sender, _value));
}
event AudienceRequested(address indexed from, address indexed to);
event AudienceCancelled(address indexed from, address indexed to);
event AudienceGranted(address indexed from, address indexed to, bool approve);
function requestAudience(address _from, bytes32 hashedSecret)
public
{
Fee memory f = getFee(_from);
require(f.amount <= balances[msg.sender]);
require(audienceRequested[_from][msg.sender].blockNum == 0);
AudienceRequested(_from, msg.sender);
audienceRequested[_from][msg.sender] = Audience(block.number, now, f, hashedSecret);
balances[msg.sender] -= f.amount;
}
function hasPendingAudience(address _from, address _to) public view returns (bool) {
return audienceRequested[_from][_to].blockNum > 0;
}
function cancelAudienceRequest(address _from) public {
require(audienceRequested[_from][msg.sender].blockNum > 0);
require(audienceRequested[_from][msg.sender].timestamp + 2 hours <= now);
AudienceCancelled(_from, msg.sender);
balances[msg.sender] += audienceRequested[_from][msg.sender].fee.amount;
delete audienceRequested[_from][msg.sender];
}
function grantAudience(address _to, bool _approve, bytes32 secret) public {
Audience storage aud = audienceRequested[msg.sender][_to];
require(aud.blockNum > 0);
require(aud.hashedSecret == keccak256(msg.sender, _to, secret));
AudienceGranted(msg.sender, _to, _approve);
bool isTribute = aud.fee.tribute;
uint256 amount = aud.fee.amount;
delete audienceRequested[msg.sender][_to];
clearFee(msg.sender, _to);
if (isTribute) {
if (_approve) {
require(SNT.transfer(msg.sender, amount));
} else {
balances[_to] += amount;
}
} else {
balances[_to] += amount;
}
}
function hasEnoughFundsToTalk(address _to)
public
view
returns(bool)
{
return getFee(_to).amount <= balances[msg.sender];
}
function getFee(address _from) internal view
returns (Fee)
{
Fee memory generalFee = feeCatalog[_from][address(0)];
Fee memory specificFee = feeCatalog[_from][msg.sender];
if (friendIndex[keccak256(msg.sender, _from)] > 0)
return Fee(0, false, false);
return specificFee.amount > 0 ? specificFee : generalFee;
}
function clearFee(address _from, address _to) private {
if (!feeCatalog[_from][_to].permanent) {
feeCatalog[_from][_to].amount = 0;
feeCatalog[_from][_to].tribute = false;
feeCatalog[_from][_to].permanent = false;
}
}
}