Contract Name:
RobotLiability
Contract Source Code:
File 1 of 1 : RobotLiability
pragma solidity ^0.4.13;
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (_a == 0) {
return 0;
}
c = _a * _b;
assert(c / _a == _b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
// assert(_b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return _a / _b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
assert(_b <= _a);
return _a - _b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
c = _a + _b;
assert(c >= _a);
return c;
}
}
contract LightContract {
/**
* @dev Shared code smart contract
*/
address lib;
constructor(address _library) public {
lib = _library;
}
function() public {
require(lib.delegatecall(msg.data));
}
}
contract DutchAuction {
/*
* Events
*/
event BidSubmission(address indexed sender, uint256 amount);
/*
* Constants
*/
uint constant public MAX_TOKENS_SOLD = 800 * 10**9; // 8M XRT = 10M - 1M (Foundation) - 1M (Early investors base)
uint constant public WAITING_PERIOD = 0; // 1 days;
/*
* Storage
*/
XRT public xrt;
address public ambix;
address public wallet;
address public owner;
uint public ceiling;
uint public priceFactor;
uint public startBlock;
uint public endTime;
uint public totalReceived;
uint public finalPrice;
mapping (address => uint) public bids;
Stages public stage;
/*
* Enums
*/
enum Stages {
AuctionDeployed,
AuctionSetUp,
AuctionStarted,
AuctionEnded,
TradingStarted
}
/*
* Modifiers
*/
modifier atStage(Stages _stage) {
// Contract on stage
require(stage == _stage);
_;
}
modifier isOwner() {
// Only owner is allowed to proceed
require(msg.sender == owner);
_;
}
modifier isWallet() {
// Only wallet is allowed to proceed
require(msg.sender == wallet);
_;
}
modifier isValidPayload() {
require(msg.data.length == 4 || msg.data.length == 36);
_;
}
modifier timedTransitions() {
if (stage == Stages.AuctionStarted && calcTokenPrice() <= calcStopPrice())
finalizeAuction();
if (stage == Stages.AuctionEnded && now > endTime + WAITING_PERIOD)
stage = Stages.TradingStarted;
_;
}
/*
* Public functions
*/
/// @dev Contract constructor function sets owner.
/// @param _wallet Multisig wallet.
/// @param _ceiling Auction ceiling.
/// @param _priceFactor Auction price factor.
constructor(address _wallet, uint _ceiling, uint _priceFactor)
public
{
require(_wallet != 0 && _ceiling > 0 && _priceFactor > 0);
owner = msg.sender;
wallet = _wallet;
ceiling = _ceiling;
priceFactor = _priceFactor;
stage = Stages.AuctionDeployed;
}
/// @dev Setup function sets external contracts' addresses.
/// @param _xrt Robonomics token address.
/// @param _ambix Distillation cube address.
function setup(address _xrt, address _ambix)
public
isOwner
atStage(Stages.AuctionDeployed)
{
// Validate argument
require(_xrt != 0 && _ambix != 0);
xrt = XRT(_xrt);
ambix = _ambix;
// Validate token balance
require(xrt.balanceOf(this) == MAX_TOKENS_SOLD);
stage = Stages.AuctionSetUp;
}
/// @dev Starts auction and sets startBlock.
function startAuction()
public
isWallet
atStage(Stages.AuctionSetUp)
{
stage = Stages.AuctionStarted;
startBlock = block.number;
}
/// @dev Calculates current token price.
/// @return Returns token price.
function calcCurrentTokenPrice()
public
timedTransitions
returns (uint)
{
if (stage == Stages.AuctionEnded || stage == Stages.TradingStarted)
return finalPrice;
return calcTokenPrice();
}
/// @dev Returns correct stage, even if a function with timedTransitions modifier has not yet been called yet.
/// @return Returns current auction stage.
function updateStage()
public
timedTransitions
returns (Stages)
{
return stage;
}
/// @dev Allows to send a bid to the auction.
/// @param receiver Bid will be assigned to this address if set.
function bid(address receiver)
public
payable
isValidPayload
timedTransitions
atStage(Stages.AuctionStarted)
returns (uint amount)
{
require(msg.value > 0);
amount = msg.value;
// If a bid is done on behalf of a user via ShapeShift, the receiver address is set.
if (receiver == 0)
receiver = msg.sender;
// Prevent that more than 90% of tokens are sold. Only relevant if cap not reached.
uint maxWei = MAX_TOKENS_SOLD * calcTokenPrice() / 10**9 - totalReceived;
uint maxWeiBasedOnTotalReceived = ceiling - totalReceived;
if (maxWeiBasedOnTotalReceived < maxWei)
maxWei = maxWeiBasedOnTotalReceived;
// Only invest maximum possible amount.
if (amount > maxWei) {
amount = maxWei;
// Send change back to receiver address. In case of a ShapeShift bid the user receives the change back directly.
receiver.transfer(msg.value - amount);
}
// Forward funding to ether wallet
wallet.transfer(amount);
bids[receiver] += amount;
totalReceived += amount;
BidSubmission(receiver, amount);
// Finalize auction when maxWei reached
if (amount == maxWei)
finalizeAuction();
}
/// @dev Claims tokens for bidder after auction.
/// @param receiver Tokens will be assigned to this address if set.
function claimTokens(address receiver)
public
isValidPayload
timedTransitions
atStage(Stages.TradingStarted)
{
if (receiver == 0)
receiver = msg.sender;
uint tokenCount = bids[receiver] * 10**9 / finalPrice;
bids[receiver] = 0;
require(xrt.transfer(receiver, tokenCount));
}
/// @dev Calculates stop price.
/// @return Returns stop price.
function calcStopPrice()
view
public
returns (uint)
{
return totalReceived * 10**9 / MAX_TOKENS_SOLD + 1;
}
/// @dev Calculates token price.
/// @return Returns token price.
function calcTokenPrice()
view
public
returns (uint)
{
return priceFactor * 10**18 / (block.number - startBlock + 7500) + 1;
}
/*
* Private functions
*/
function finalizeAuction()
private
{
stage = Stages.AuctionEnded;
finalPrice = totalReceived == ceiling ? calcTokenPrice() : calcStopPrice();
uint soldTokens = totalReceived * 10**9 / finalPrice;
if (totalReceived == ceiling) {
// Auction contract transfers all unsold tokens to Ambix contract
require(xrt.transfer(ambix, MAX_TOKENS_SOLD - soldTokens));
} else {
// Auction contract burn all unsold tokens
xrt.burn(MAX_TOKENS_SOLD - soldTokens);
}
endTime = now;
}
}
contract PublicResolver {
bytes4 constant INTERFACE_META_ID = 0x01ffc9a7;
bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de;
bytes4 constant CONTENT_INTERFACE_ID = 0xd8389dc5;
bytes4 constant NAME_INTERFACE_ID = 0x691f3431;
bytes4 constant ABI_INTERFACE_ID = 0x2203ab56;
bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233;
bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c;
bytes4 constant MULTIHASH_INTERFACE_ID = 0xe89401a1;
event AddrChanged(bytes32 indexed node, address a);
event ContentChanged(bytes32 indexed node, bytes32 hash);
event NameChanged(bytes32 indexed node, string name);
event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
event TextChanged(bytes32 indexed node, string indexedKey, string key);
event MultihashChanged(bytes32 indexed node, bytes hash);
struct PublicKey {
bytes32 x;
bytes32 y;
}
struct Record {
address addr;
bytes32 content;
string name;
PublicKey pubkey;
mapping(string=>string) text;
mapping(uint256=>bytes) abis;
bytes multihash;
}
ENS ens;
mapping (bytes32 => Record) records;
modifier only_owner(bytes32 node) {
require(ens.owner(node) == msg.sender);
_;
}
/**
* Constructor.
* @param ensAddr The ENS registrar contract.
*/
function PublicResolver(ENS ensAddr) public {
ens = ensAddr;
}
/**
* Sets the address associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param addr The address to set.
*/
function setAddr(bytes32 node, address addr) public only_owner(node) {
records[node].addr = addr;
AddrChanged(node, addr);
}
/**
* Sets the content hash associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* Note that this resource type is not standardized, and will likely change
* in future to a resource type based on multihash.
* @param node The node to update.
* @param hash The content hash to set
*/
function setContent(bytes32 node, bytes32 hash) public only_owner(node) {
records[node].content = hash;
ContentChanged(node, hash);
}
/**
* Sets the multihash associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param hash The multihash to set
*/
function setMultihash(bytes32 node, bytes hash) public only_owner(node) {
records[node].multihash = hash;
MultihashChanged(node, hash);
}
/**
* Sets the name associated with an ENS node, for reverse records.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param name The name to set.
*/
function setName(bytes32 node, string name) public only_owner(node) {
records[node].name = name;
NameChanged(node, name);
}
/**
* Sets the ABI associated with an ENS node.
* Nodes may have one ABI of each content type. To remove an ABI, set it to
* the empty string.
* @param node The node to update.
* @param contentType The content type of the ABI
* @param data The ABI data.
*/
function setABI(bytes32 node, uint256 contentType, bytes data) public only_owner(node) {
// Content types must be powers of 2
require(((contentType - 1) & contentType) == 0);
records[node].abis[contentType] = data;
ABIChanged(node, contentType);
}
/**
* Sets the SECP256k1 public key associated with an ENS node.
* @param node The ENS node to query
* @param x the X coordinate of the curve point for the public key.
* @param y the Y coordinate of the curve point for the public key.
*/
function setPubkey(bytes32 node, bytes32 x, bytes32 y) public only_owner(node) {
records[node].pubkey = PublicKey(x, y);
PubkeyChanged(node, x, y);
}
/**
* Sets the text data associated with an ENS node and key.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param key The key to set.
* @param value The text data value to set.
*/
function setText(bytes32 node, string key, string value) public only_owner(node) {
records[node].text[key] = value;
TextChanged(node, key, key);
}
/**
* Returns the text data associated with an ENS node and key.
* @param node The ENS node to query.
* @param key The text data key to query.
* @return The associated text data.
*/
function text(bytes32 node, string key) public view returns (string) {
return records[node].text[key];
}
/**
* Returns the SECP256k1 public key associated with an ENS node.
* Defined in EIP 619.
* @param node The ENS node to query
* @return x, y the X and Y coordinates of the curve point for the public key.
*/
function pubkey(bytes32 node) public view returns (bytes32 x, bytes32 y) {
return (records[node].pubkey.x, records[node].pubkey.y);
}
/**
* Returns the ABI associated with an ENS node.
* Defined in EIP205.
* @param node The ENS node to query
* @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
* @return contentType The content type of the return value
* @return data The ABI data
*/
function ABI(bytes32 node, uint256 contentTypes) public view returns (uint256 contentType, bytes data) {
Record storage record = records[node];
for (contentType = 1; contentType <= contentTypes; contentType <<= 1) {
if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) {
data = record.abis[contentType];
return;
}
}
contentType = 0;
}
/**
* Returns the name associated with an ENS node, for reverse records.
* Defined in EIP181.
* @param node The ENS node to query.
* @return The associated name.
*/
function name(bytes32 node) public view returns (string) {
return records[node].name;
}
/**
* Returns the content hash associated with an ENS node.
* Note that this resource type is not standardized, and will likely change
* in future to a resource type based on multihash.
* @param node The ENS node to query.
* @return The associated content hash.
*/
function content(bytes32 node) public view returns (bytes32) {
return records[node].content;
}
/**
* Returns the multihash associated with an ENS node.
* @param node The ENS node to query.
* @return The associated multihash.
*/
function multihash(bytes32 node) public view returns (bytes) {
return records[node].multihash;
}
/**
* Returns the address associated with an ENS node.
* @param node The ENS node to query.
* @return The associated address.
*/
function addr(bytes32 node) public view returns (address) {
return records[node].addr;
}
/**
* Returns true if the resolver implements the interface specified by the provided hash.
* @param interfaceID The ID of the interface to check for.
* @return True if the contract implements the requested interface.
*/
function supportsInterface(bytes4 interfaceID) public pure returns (bool) {
return interfaceID == ADDR_INTERFACE_ID ||
interfaceID == CONTENT_INTERFACE_ID ||
interfaceID == NAME_INTERFACE_ID ||
interfaceID == ABI_INTERFACE_ID ||
interfaceID == PUBKEY_INTERFACE_ID ||
interfaceID == TEXT_INTERFACE_ID ||
interfaceID == MULTIHASH_INTERFACE_ID ||
interfaceID == INTERFACE_META_ID;
}
}
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address _who) public view returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
interface ENS {
// Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner);
// Logged when the resolver for a node changes.
event NewResolver(bytes32 indexed node, address resolver);
// Logged when the TTL of a node changes
event NewTTL(bytes32 indexed node, uint64 ttl);
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public;
function setResolver(bytes32 node, address resolver) public;
function setOwner(bytes32 node, address owner) public;
function setTTL(bytes32 node, uint64 ttl) public;
function owner(bytes32 node) public view returns (address);
function resolver(bytes32 node) public view returns (address);
function ttl(bytes32 node) public view returns (uint64);
}
contract ENSRegistry is ENS {
struct Record {
address owner;
address resolver;
uint64 ttl;
}
mapping (bytes32 => Record) records;
// Permits modifications only by the owner of the specified node.
modifier only_owner(bytes32 node) {
require(records[node].owner == msg.sender);
_;
}
/**
* @dev Constructs a new ENS registrar.
*/
function ENSRegistry() public {
records[0x0].owner = msg.sender;
}
/**
* @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node.
* @param node The node to transfer ownership of.
* @param owner The address of the new owner.
*/
function setOwner(bytes32 node, address owner) public only_owner(node) {
Transfer(node, owner);
records[node].owner = owner;
}
/**
* @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node.
* @param node The parent node.
* @param label The hash of the label specifying the subnode.
* @param owner The address of the new owner.
*/
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public only_owner(node) {
var subnode = keccak256(node, label);
NewOwner(node, label, owner);
records[subnode].owner = owner;
}
/**
* @dev Sets the resolver address for the specified node.
* @param node The node to update.
* @param resolver The address of the resolver.
*/
function setResolver(bytes32 node, address resolver) public only_owner(node) {
NewResolver(node, resolver);
records[node].resolver = resolver;
}
/**
* @dev Sets the TTL for the specified node.
* @param node The node to update.
* @param ttl The TTL in seconds.
*/
function setTTL(bytes32 node, uint64 ttl) public only_owner(node) {
NewTTL(node, ttl);
records[node].ttl = ttl;
}
/**
* @dev Returns the address that owns the specified node.
* @param node The specified node.
* @return address of the owner.
*/
function owner(bytes32 node) public view returns (address) {
return records[node].owner;
}
/**
* @dev Returns the address of the resolver for the specified node.
* @param node The specified node.
* @return address of the resolver.
*/
function resolver(bytes32 node) public view returns (address) {
return records[node].resolver;
}
/**
* @dev Returns the TTL of a node, and any records associated with it.
* @param node The specified node.
* @return ttl of the node.
*/
function ttl(bytes32 node) public view returns (uint64) {
return records[node].ttl;
}
}
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) internal balances;
uint256 internal totalSupply_;
/**
* @dev Total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return totalSupply_;
}
/**
* @dev Transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_value <= balances[msg.sender]);
require(_to != address(0));
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256) {
return balances[_owner];
}
}
contract RobotLiabilityAPI {
bytes public model;
bytes public objective;
bytes public result;
ERC20 public token;
uint256 public cost;
uint256 public lighthouseFee;
uint256 public validatorFee;
bytes32 public askHash;
bytes32 public bidHash;
address public promisor;
address public promisee;
address public validator;
bool public isConfirmed;
bool public isFinalized;
LiabilityFactory public factory;
}
contract RobotLiability is RobotLiabilityAPI, LightContract {
constructor(address _lib) public LightContract(_lib)
{ factory = LiabilityFactory(msg.sender); }
}
contract LighthouseAPI {
address[] public members;
function membersLength() public view returns (uint256)
{ return members.length; }
mapping(address => uint256) indexOf;
mapping(address => uint256) public balances;
uint256 public minimalFreeze;
uint256 public timeoutBlocks;
LiabilityFactory public factory;
XRT public xrt;
uint256 public keepaliveBlock = 0;
uint256 public marker = 0;
uint256 public quota = 0;
function quotaOf(address _member) public view returns (uint256)
{ return balances[_member] / minimalFreeze; }
}
contract Lighthouse is LighthouseAPI, LightContract {
constructor(
address _lib,
uint256 _minimalFreeze,
uint256 _timeoutBlocks
)
public
LightContract(_lib)
{
require(_minimalFreeze > 0 && _timeoutBlocks > 0);
minimalFreeze = _minimalFreeze;
timeoutBlocks = _timeoutBlocks;
factory = LiabilityFactory(msg.sender);
xrt = factory.xrt();
}
}
contract ERC20 is ERC20Basic {
function allowance(address _owner, address _spender)
public view returns (uint256);
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool);
function approve(address _spender, uint256 _value) public returns (bool);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(
address _from,
address _to,
uint256 _value
)
public
returns (bool)
{
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
require(_to != address(0));
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(
address _owner,
address _spender
)
public
view
returns (uint256)
{
return allowed[_owner][_spender];
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _addedValue The amount of tokens to increase the allowance by.
*/
function increaseApproval(
address _spender,
uint256 _addedValue
)
public
returns (bool)
{
allowed[msg.sender][_spender] = (
allowed[msg.sender][_spender].add(_addedValue));
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed[_spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseApproval(
address _spender,
uint256 _subtractedValue
)
public
returns (bool)
{
uint256 oldValue = allowed[msg.sender][_spender];
if (_subtractedValue >= oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
contract BurnableToken is BasicToken {
event Burn(address indexed burner, uint256 value);
/**
* @dev Burns a specific amount of tokens.
* @param _value The amount of token to be burned.
*/
function burn(uint256 _value) public {
_burn(msg.sender, _value);
}
function _burn(address _who, uint256 _value) internal {
require(_value <= balances[_who]);
// no need to require value <= totalSupply, since that would imply the
// sender's balance is greater than the totalSupply, which *should* be an assertion failure
balances[_who] = balances[_who].sub(_value);
totalSupply_ = totalSupply_.sub(_value);
emit Burn(_who, _value);
emit Transfer(_who, address(0), _value);
}
}
contract Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(owner);
owner = address(0);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) public onlyOwner {
_transferOwnership(_newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
contract MintableToken is StandardToken, Ownable {
event Mint(address indexed to, uint256 amount);
event MintFinished();
bool public mintingFinished = false;
modifier canMint() {
require(!mintingFinished);
_;
}
modifier hasMintPermission() {
require(msg.sender == owner);
_;
}
/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(
address _to,
uint256 _amount
)
public
hasMintPermission
canMint
returns (bool)
{
totalSupply_ = totalSupply_.add(_amount);
balances[_to] = balances[_to].add(_amount);
emit Mint(_to, _amount);
emit Transfer(address(0), _to, _amount);
return true;
}
/**
* @dev Function to stop minting new tokens.
* @return True if the operation was successful.
*/
function finishMinting() public onlyOwner canMint returns (bool) {
mintingFinished = true;
emit MintFinished();
return true;
}
}
contract XRT is MintableToken, BurnableToken {
string public constant name = "Robonomics Beta";
string public constant symbol = "XRT";
uint8 public constant decimals = 9;
uint256 public constant INITIAL_SUPPLY = 1000 * (10 ** uint256(decimals));
constructor() public {
totalSupply_ = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
emit Transfer(0x0, msg.sender, INITIAL_SUPPLY);
}
}
contract LiabilityFactory {
constructor(
address _robot_liability_lib,
address _lighthouse_lib,
DutchAuction _auction,
XRT _xrt,
ENS _ens
) public {
robotLiabilityLib = _robot_liability_lib;
lighthouseLib = _lighthouse_lib;
auction = _auction;
xrt = _xrt;
ens = _ens;
}
/**
* @dev New liability created
*/
event NewLiability(address indexed liability);
/**
* @dev New lighthouse created
*/
event NewLighthouse(address indexed lighthouse, string name);
/**
* @dev Robonomics dutch auction contract
*/
DutchAuction public auction;
/**
* @dev Robonomics network protocol token
*/
XRT public xrt;
/**
* @dev Ethereum name system
*/
ENS public ens;
/**
* @dev Total GAS utilized by Robonomics network
*/
uint256 public totalGasUtilizing = 0;
/**
* @dev GAS utilized by liability contracts
*/
mapping(address => uint256) public gasUtilizing;
/**
* @dev The count of utilized gas for switch to next epoch
*/
uint256 public constant gasEpoch = 347 * 10**10;
/**
* @dev Weighted average gasprice
*/
uint256 public constant gasPrice = 10 * 10**9;
/**
* @dev Used market orders accounting
*/
mapping(bytes32 => bool) public usedHash;
/**
* @dev Lighthouse accounting
*/
mapping(address => bool) public isLighthouse;
/**
* @dev Robot liability shared code smart contract
*/
address public robotLiabilityLib;
/**
* @dev Lightouse shared code smart contract
*/
address public lighthouseLib;
/**
* @dev XRT emission value for utilized gas
*/
function wnFromGas(uint256 _gas) public view returns (uint256) {
// Just return wn=gas when auction isn't finish
if (auction.finalPrice() == 0)
return _gas;
// Current gas utilization epoch
uint256 epoch = totalGasUtilizing / gasEpoch;
// XRT emission with addition coefficient by gas utilzation epoch
uint256 wn = _gas * 10**9 * gasPrice * 2**epoch / 3**epoch / auction.finalPrice();
// Check to not permit emission decrease below wn=gas
return wn < _gas ? _gas : wn;
}
/**
* @dev Only lighthouse guard
*/
modifier onlyLighthouse {
require(isLighthouse[msg.sender]);
_;
}
/**
* @dev Parameter can be used only once
* @param _hash Single usage hash
*/
function usedHashGuard(bytes32 _hash) internal {
require(!usedHash[_hash]);
usedHash[_hash] = true;
}
/**
* @dev Create robot liability smart contract
* @param _ask ABI-encoded ASK order message
* @param _bid ABI-encoded BID order message
*/
function createLiability(
bytes _ask,
bytes _bid
)
external
onlyLighthouse
returns (RobotLiability liability)
{
// Store in memory available gas
uint256 gasinit = gasleft();
// Create liability
liability = new RobotLiability(robotLiabilityLib);
emit NewLiability(liability);
// Parse messages
require(liability.call(abi.encodePacked(bytes4(0x82fbaa25), _ask))); // liability.ask(...)
usedHashGuard(liability.askHash());
require(liability.call(abi.encodePacked(bytes4(0x66193359), _bid))); // liability.bid(...)
usedHashGuard(liability.bidHash());
// Transfer lighthouse fee to lighthouse worker directly
require(xrt.transferFrom(liability.promisor(),
tx.origin,
liability.lighthouseFee()));
// Transfer liability security and hold on contract
ERC20 token = liability.token();
require(token.transferFrom(liability.promisee(),
liability,
liability.cost()));
// Transfer validator fee and hold on contract
if (address(liability.validator()) != 0 && liability.validatorFee() > 0)
require(xrt.transferFrom(liability.promisee(),
liability,
liability.validatorFee()));
// Accounting gas usage of transaction
uint256 gas = gasinit - gasleft() + 110525; // Including observation error
totalGasUtilizing += gas;
gasUtilizing[liability] += gas;
}
/**
* @dev Create lighthouse smart contract
* @param _minimalFreeze Minimal freeze value of XRT token
* @param _timeoutBlocks Max time of lighthouse silence in blocks
* @param _name Lighthouse subdomain,
* example: for 'my-name' will created 'my-name.lighthouse.1.robonomics.eth' domain
*/
function createLighthouse(
uint256 _minimalFreeze,
uint256 _timeoutBlocks,
string _name
)
external
returns (address lighthouse)
{
bytes32 lighthouseNode
// lighthouse.1.robonomics.eth
= 0x3662a5d633e9a5ca4b4bd25284e1b343c15a92b5347feb9b965a2b1ef3e1ea1a;
// Name reservation check
bytes32 subnode = keccak256(abi.encodePacked(lighthouseNode, keccak256(_name)));
require(ens.resolver(subnode) == 0);
// Create lighthouse
lighthouse = new Lighthouse(lighthouseLib, _minimalFreeze, _timeoutBlocks);
emit NewLighthouse(lighthouse, _name);
isLighthouse[lighthouse] = true;
// Register subnode
ens.setSubnodeOwner(lighthouseNode, keccak256(_name), this);
// Register lighthouse address
PublicResolver resolver = PublicResolver(ens.resolver(lighthouseNode));
ens.setResolver(subnode, resolver);
resolver.setAddr(subnode, lighthouse);
}
/**
* @dev Is called whan after liability finalization
* @param _gas Liability finalization gas expenses
*/
function liabilityFinalized(
uint256 _gas
)
external
returns (bool)
{
require(gasUtilizing[msg.sender] > 0);
uint256 gas = _gas - gasleft();
require(_gas > gas);
totalGasUtilizing += gas;
gasUtilizing[msg.sender] += gas;
require(xrt.mint(tx.origin, wnFromGas(gasUtilizing[msg.sender])));
return true;
}
}