Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
251 lines (215 sloc) 6.66 KB
pragma solidity 0.4.26;
import "./AccessControl/AccessControlled.sol";
import "./AccessRoles.sol";
import "./Agreement.sol";
import "./Standards/IERC223Token.sol";
import "./Standards/IERC223LegacyCallback.sol";
import "./IsContract.sol";
import "./Snapshot/DailyAndSnapshotable.sol";
import "./SnapshotToken/Helpers/TokenMetadata.sol";
import "./SnapshotToken/StandardSnapshotToken.sol";
import "./NeumarkIssuanceCurve.sol";
import "./Reclaimable.sol";
contract Neumark is
AccessControlled,
AccessRoles,
Agreement,
DailyAndSnapshotable,
StandardSnapshotToken,
TokenMetadata,
IERC223Token,
NeumarkIssuanceCurve,
Reclaimable,
IsContract
{
////////////////////////
// Constants
////////////////////////
string private constant TOKEN_NAME = "Neumark";
uint8 private constant TOKEN_DECIMALS = 18;
string private constant TOKEN_SYMBOL = "NEU";
string private constant VERSION = "NMK_1.0";
////////////////////////
// Mutable state
////////////////////////
// disable transfers when Neumark is created
bool private _transferEnabled = false;
// at which point on curve new Neumarks will be created, see NeumarkIssuanceCurve contract
// do not use to get total invested funds. see burn(). this is just a cache for expensive inverse function
uint256 private _totalEurUlps;
////////////////////////
// Events
////////////////////////
event LogNeumarksIssued(
address indexed owner,
uint256 euroUlps,
uint256 neumarkUlps
);
event LogNeumarksBurned(
address indexed owner,
uint256 euroUlps,
uint256 neumarkUlps
);
////////////////////////
// Constructor
////////////////////////
constructor(
IAccessPolicy accessPolicy,
IEthereumForkArbiter forkArbiter
)
AccessRoles()
Agreement(accessPolicy, forkArbiter)
StandardSnapshotToken(
IClonedTokenParent(0x0),
0
)
TokenMetadata(
TOKEN_NAME,
TOKEN_DECIMALS,
TOKEN_SYMBOL,
VERSION
)
DailyAndSnapshotable(0)
NeumarkIssuanceCurve()
Reclaimable()
public
{}
////////////////////////
// Public functions
////////////////////////
/// @notice issues new Neumarks to msg.sender with reward at current curve position
/// moves curve position by euroUlps
/// callable only by ROLE_NEUMARK_ISSUER
function issueForEuro(uint256 euroUlps)
public
only(ROLE_NEUMARK_ISSUER)
acceptAgreement(msg.sender)
returns (uint256)
{
require(_totalEurUlps + euroUlps >= _totalEurUlps);
uint256 neumarkUlps = incremental(_totalEurUlps, euroUlps);
_totalEurUlps += euroUlps;
mGenerateTokens(msg.sender, neumarkUlps);
emit LogNeumarksIssued(msg.sender, euroUlps, neumarkUlps);
return neumarkUlps;
}
/// @notice used by ROLE_NEUMARK_ISSUER to transer newly issued neumarks
/// typically to the investor and platform operator
function distribute(address to, uint256 neumarkUlps)
public
only(ROLE_NEUMARK_ISSUER)
acceptAgreement(to)
{
mTransfer(msg.sender, to, neumarkUlps);
}
/// @notice msg.sender can burn their Neumarks, curve is rolled back using inverse
/// curve. as a result cost of Neumark gets lower (reward is higher)
function burn(uint256 neumarkUlps)
public
only(ROLE_NEUMARK_BURNER)
{
burnPrivate(neumarkUlps, 0, _totalEurUlps);
}
/// @notice executes as function above but allows to provide search range for low gas burning
function burn(uint256 neumarkUlps, uint256 minEurUlps, uint256 maxEurUlps)
public
only(ROLE_NEUMARK_BURNER)
{
burnPrivate(neumarkUlps, minEurUlps, maxEurUlps);
}
function enableTransfer(bool enabled)
public
only(ROLE_TRANSFER_ADMIN)
{
_transferEnabled = enabled;
}
function createSnapshot()
public
only(ROLE_SNAPSHOT_CREATOR)
returns (uint256)
{
return DailyAndSnapshotable.createSnapshot();
}
function transferEnabled()
public
constant
returns (bool)
{
return _transferEnabled;
}
function totalEuroUlps()
public
constant
returns (uint256)
{
return _totalEurUlps;
}
function incremental(uint256 euroUlps)
public
constant
returns (uint256 neumarkUlps)
{
return incremental(_totalEurUlps, euroUlps);
}
//
// Implements IERC223Token with IERC223Callback (onTokenTransfer) callback
//
// old implementation of ERC223 that was actual when ICBM was deployed
// as Neumark is already deployed this function keeps old behavior for testing
function transfer(address to, uint256 amount, bytes data)
public
returns (bool)
{
// it is necessary to point out implementation to be called
BasicSnapshotToken.mTransfer(msg.sender, to, amount);
// Notify the receiving contract.
if (isContract(to)) {
IERC223LegacyCallback(to).onTokenTransfer(msg.sender, amount, data);
}
return true;
}
////////////////////////
// Internal functions
////////////////////////
//
// Implements MTokenController
//
function mOnTransfer(
address from,
address, // to
uint256 // amount
)
internal
acceptAgreement(from)
returns (bool allow)
{
// must have transfer enabled or msg.sender is Neumark issuer
return _transferEnabled || accessPolicy().allowed(msg.sender, ROLE_NEUMARK_ISSUER, this, msg.sig);
}
function mOnApprove(
address owner,
address, // spender,
uint256 // amount
)
internal
acceptAgreement(owner)
returns (bool allow)
{
return true;
}
////////////////////////
// Private functions
////////////////////////
function burnPrivate(uint256 burnNeumarkUlps, uint256 minEurUlps, uint256 maxEurUlps)
private
{
uint256 prevEuroUlps = _totalEurUlps;
// burn first in the token to make sure balance/totalSupply is not crossed
mDestroyTokens(msg.sender, burnNeumarkUlps);
_totalEurUlps = cumulativeInverse(totalSupply(), minEurUlps, maxEurUlps);
// actually may overflow on non-monotonic inverse
assert(prevEuroUlps >= _totalEurUlps);
uint256 euroUlps = prevEuroUlps - _totalEurUlps;
emit LogNeumarksBurned(msg.sender, euroUlps, burnNeumarkUlps);
}
}
You can’t perform that action at this time.