pragma solidity ^0.4.18;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
uint256 public totalSupply;
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);
}
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() 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 transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
contract PresaleFallbackReceiver {
bool public presaleFallBackCalled;
function presaleFallBack(uint256 _presaleWeiRaised) public returns (bool);
}
/**
* @title Pausable
* @dev Base contract which allows children to implement an emergency stop mechanism.
*/
contract Pausable is Ownable {
event Pause();
event Unpause();
bool public paused = false;
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*/
modifier whenNotPaused() {
require(!paused);
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*/
modifier whenPaused() {
require(paused);
_;
}
/**
* @dev called by the owner to pause, triggers stopped state
*/
function pause() onlyOwner whenNotPaused public {
paused = true;
Pause();
}
/**
* @dev called by the owner to unpause, returns to normal state
*/
function unpause() onlyOwner whenPaused public {
paused = false;
Unpause();
}
}
/**
* @title RefundVault
* @dev This contract is used for storing funds while a crowdsale
* is in progress. Supports refunding the money if crowdsale fails,
* and forwarding it if crowdsale is successful.
*/
contract RefundVault is Ownable {
using SafeMath for uint256;
enum State { Active, Refunding, Closed }
mapping (address => uint256) public deposited;
address public wallet;
State public state;
event Closed();
event RefundsEnabled();
event Refunded(address indexed beneficiary, uint256 weiAmount);
function RefundVault(address _wallet) public {
require(_wallet != address(0));
wallet = _wallet;
state = State.Active;
}
function deposit(address investor) onlyOwner public payable {
require(state == State.Active);
deposited[investor] = deposited[investor].add(msg.value);
}
function close() onlyOwner public {
require(state == State.Active);
state = State.Closed;
Closed();
wallet.transfer(this.balance);
}
function enableRefunds() onlyOwner public {
require(state == State.Active);
state = State.Refunding;
RefundsEnabled();
}
function refund(address investor) public {
require(state == State.Refunding);
uint256 depositedValue = deposited[investor];
deposited[investor] = 0;
investor.transfer(depositedValue);
Refunded(investor, depositedValue);
}
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
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 c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract Controlled {
/// @notice The address of the controller is the only address that can call
/// a function with this modifier
modifier onlyController { require(msg.sender == controller); _; }
address public controller;
function Controlled() public { controller = msg.sender;}
/// @notice Changes the controller of the contract
/// @param _newController The new controller of the contract
function changeController(address _newController) public onlyController {
controller = _newController;
}
}
contract BTCPaymentI is Ownable, PresaleFallbackReceiver {
PaymentFallbackReceiver public presale;
PaymentFallbackReceiver public mainsale;
function addPayment(address _beneficiary, uint256 _tokens) public;
function setPresale(address _presale) external;
function setMainsale(address _mainsale) external;
function presaleFallBack(uint256) public returns (bool);
}
contract PaymentFallbackReceiver {
BTCPaymentI public payment;
enum SaleType { pre, main }
function PaymentFallbackReceiver(address _payment) public {
require(_payment != address(0));
payment = BTCPaymentI(_payment);
}
modifier onlyPayment() {
require(msg.sender == address(payment));
_;
}
event MintByBTC(SaleType _saleType, address indexed _beneficiary, uint256 _tokens);
/**
* @dev paymentFallBack() is called in BTCPayment.addPayment().
* Presale or Mainsale contract should mint token to beneficiary,
* and apply corresponding ether amount to max ether cap.
* @param _beneficiary ethereum address who receives tokens
* @param _tokens amount of FXT to mint
*/
function paymentFallBack(address _beneficiary, uint256 _tokens) external onlyPayment();
}
/**
* @title Sudo
* @dev Some functions should be restricted so as not to be available in any situation.
* `onlySudoEnabled` modifier controlls it.
*/
contract Sudo is Ownable {
bool public sudoEnabled;
modifier onlySudoEnabled() {
require(sudoEnabled);
_;
}
event SudoEnabled(bool _sudoEnabled);
function Sudo(bool _sudoEnabled) public {
sudoEnabled = _sudoEnabled;
}
function enableSudo(bool _sudoEnabled) public onlyOwner {
sudoEnabled = _sudoEnabled;
SudoEnabled(_sudoEnabled);
}
}
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
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 FXTI is ERC20 {
bool public sudoEnabled = true;
function transfer(address _to, uint256 _amount) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _amount) public returns (bool success);
function generateTokens(address _owner, uint _amount) public returns (bool);
function destroyTokens(address _owner, uint _amount) public returns (bool);
function blockAddress(address _addr) public;
function unblockAddress(address _addr) public;
function enableSudo(bool _sudoEnabled) public;
function enableTransfers(bool _transfersEnabled) public;
// byList functions
function generateTokensByList(address[] _owners, uint[] _amounts) public returns (bool);
}
/**
* @title KYCInterface
*/
contract KYCI is Ownable {
function setAdmin(address _addr, bool _value) public returns (bool);
function isRegistered(address _addr, bool _isPresale) public returns (bool);
function register(address _addr, bool _isPresale) public;
function registerByList(address[] _addrs, bool _isPresale) public;
function unregister(address _addr, bool _isPresale)public;
function unregisterByList(address[] _addrs, bool _isPresale) public;
}
/**
* @dev This base contract is inherited by FXTPresale and FXTMainsale
* and have related contracts address and ether funded in the sale as state.
* Main purpose of this base contract is to provide the interface to control
* generating / burning token and increase / decrease ether ether funded in the sale.
* Those functions are only called in case of emergency situation such as
* erroneous action handling Bitcoin payment.
*/
contract SaleBase is Sudo, Pausable, PaymentFallbackReceiver {
using SafeMath for uint256;
// related contracts
FXTI public token;
KYCI public kyc;
RefundVault public vault;
// fuzex account to hold ownership of contracts after sale finalized
address public fuzexAccount;
// common sale parameters
mapping (address => uint256) public beneficiaryFunded;
uint256 public weiRaised;
bool public isFinalized; // whether sale is finalized
/**
* @dev After sale finalized, token and other contract ownership is transferred to
* another contract or account. So this modifier doesn't effect contract logic, just
* make sure of it.
*/
modifier onlyNotFinalized() {
require(!isFinalized);
_;
}
function SaleBase(
address _token,
address _kyc,
address _vault,
address _payment,
address _fuzexAccount)
Sudo(false) // sudoEnabled
PaymentFallbackReceiver(_payment)
public
{
require(_token != address(0)
&& _kyc != address(0)
&& _vault != address(0)
&& _fuzexAccount != address(0));
token = FXTI(_token);
kyc = KYCI(_kyc);
vault = RefundVault(_vault);
fuzexAccount = _fuzexAccount;
}
/**
* @dev Below 4 functions are only called in case of emergency and certain situation.
* e.g. Wrong parameters for BTCPayment.addPayment function so that token should be burned and
* wei-raised should be modified.
*/
function increaseWeiRaised(uint256 _amount) public onlyOwner onlyNotFinalized onlySudoEnabled {
weiRaised = weiRaised.add(_amount);
}
function decreaseWeiRaised(uint256 _amount) public onlyOwner onlyNotFinalized onlySudoEnabled {
weiRaised = weiRaised.sub(_amount);
}
function generateTokens(address _owner, uint _amount) public onlyOwner onlyNotFinalized onlySudoEnabled returns (bool) {
return token.generateTokens(_owner, _amount);
}
function destroyTokens(address _owner, uint _amount) public onlyOwner onlyNotFinalized onlySudoEnabled returns (bool) {
return token.destroyTokens(_owner, _amount);
}
/**
* @dev Prevent token holder from transfer.
*/
function blockAddress(address _addr) public onlyOwner onlyNotFinalized onlySudoEnabled {
token.blockAddress(_addr);
}
function unblockAddress(address _addr) public onlyOwner onlyNotFinalized onlySudoEnabled {
token.unblockAddress(_addr);
}
/**
* @dev Transfer ownership of other contract whoes owner is `this` to other address.
*/
function changeOwnership(address _target, address _newOwner) public onlyOwner {
Ownable(_target).transferOwnership(_newOwner);
}
/**
* @dev Transfer ownership of MiniMeToken whoes controller is `this` to other address.
*/
function changeController(address _target, address _newOwner) public onlyOwner {
Controlled(_target).changeController(_newOwner);
}
function setFinalize() internal onlyOwner {
require(!isFinalized);
isFinalized = true;
}
}
/**
* @title FXTPresale
* @dev Private-sale is finished before this contract is deployed.
*
*/
contract FXTPresale is SaleBase {
uint256 public baseRate = 12000; // 1 ETH = 12000 FXT
uint256 public PRE_BONUS = 25; // presale bonus 25%
uint256 public BONUS_COEFF = 100;
// private-sale parameters
uint256 public privateEtherFunded;
uint256 public privateMaxEtherCap;
// presale parameters
uint256 public presaleMaxEtherCap;
uint256 public presaleMinPurchase;
uint256 public maxEtherCap; // max ether cap for both private-sale & presale
uint64 public startTime; // when presale starts
uint64 public endTime; // when presale ends
event PresaleTokenPurchase(address indexed _purchaser, address indexed _beneficiary, uint256 toFund, uint256 tokens);
/**
* @dev only presale registered address can participate presale.
* private-sale doesn't require to check address because owner deals with it.
*/
modifier onlyRegistered(address _addr) {
require(kyc.isRegistered(_addr, true));
_;
}
function FXTPresale(
address _token,
address _kyc,
address _vault,
address _payment,
address _fuzexAccount,
uint64 _startTime,
uint64 _endTime,
uint256 _privateEtherFunded,
uint256 _privateMaxEtherCap,
uint256 _presaleMaxEtherCap,
uint256 _presaleMinPurchase)
SaleBase(_token, _kyc, _vault, _payment, _fuzexAccount)
public
{
require(now < _startTime && _startTime < _endTime);
require(_privateEtherFunded >= 0);
require(_privateMaxEtherCap > 0);
require(_presaleMaxEtherCap > 0);
require(_presaleMinPurchase > 0);
require(_presaleMinPurchase < _presaleMaxEtherCap);
startTime = _startTime;
endTime = _endTime;
privateEtherFunded = _privateEtherFunded;
privateMaxEtherCap = _privateMaxEtherCap;
presaleMaxEtherCap = _presaleMaxEtherCap;
presaleMinPurchase = _presaleMinPurchase;
maxEtherCap = privateMaxEtherCap.add(presaleMaxEtherCap);
weiRaised = _privateEtherFunded; // ether funded during private-sale
require(weiRaised <= maxEtherCap);
}
function () external payable {
buyPresale(msg.sender);
}
/**
* @dev paymentFallBack() assumes that paid BTC doesn't exceed the max ether cap.
* BTC / ETH price (or rate) is determined using reliable outer resources.
* @param _beneficiary ethereum address who receives tokens
* @param _tokens amount of FXT to mint
*/
function paymentFallBack(address _beneficiary, uint256 _tokens)
external
onlyPayment
{
// only check time and parameters
require(startTime <= now && now <= endTime);
require(_beneficiary != address(0));
require(_tokens > 0);
uint256 rate = getRate();
uint256 weiAmount = _tokens.div(rate);
require(weiAmount >= presaleMinPurchase);
// funded ether should not exceed max ether cap.
require(weiRaised.add(weiAmount) <= maxEtherCap);
weiRaised = weiRaised.add(weiAmount);
beneficiaryFunded[_beneficiary] = beneficiaryFunded[_beneficiary].add(weiAmount);
token.generateTokens(_beneficiary, _tokens);
MintByBTC(SaleType.pre, _beneficiary, _tokens);
}
function buyPresale(address _beneficiary)
public
payable
onlyRegistered(_beneficiary)
whenNotPaused
{
// check validity
require(_beneficiary != address(0));
require(msg.value >= presaleMinPurchase);
require(validPurchase());
uint256 toFund;
uint256 tokens;
(toFund, tokens) = buy(_beneficiary);
PresaleTokenPurchase(msg.sender, _beneficiary, toFund, tokens);
}
function buy(address _beneficiary)
internal
returns (uint256 toFund, uint256 tokens)
{
// calculate eth amount
uint256 weiAmount = msg.value;
uint256 totalAmount = weiRaised.add(weiAmount);
if (totalAmount > maxEtherCap) {
toFund = maxEtherCap.sub(weiRaised);
} else {
toFund = weiAmount;
}
require(toFund > 0);
require(weiAmount >= toFund);
uint256 rate = getRate();
tokens = toFund.mul(rate);
uint256 toReturn = weiAmount.sub(toFund);
weiRaised = weiRaised.add(toFund);
beneficiaryFunded[_beneficiary] = beneficiaryFunded[_beneficiary].add(toFund);
token.generateTokens(_beneficiary, tokens);
if (toReturn > 0) {
msg.sender.transfer(toReturn);
}
forwardFunds(toFund);
}
function validPurchase() internal view returns (bool) {
bool nonZeroPurchase = msg.value != 0;
bool validTime = now >= startTime && now <= endTime;
return nonZeroPurchase && !maxReached() && validTime;
}
/**
* @dev get current rate
*/
function getRate() public view returns (uint256) {
return calcRate(PRE_BONUS);
}
/**
* @dev Calculate rate wrt _bonus. if _bonus is 15, this function
* returns baseRate * 1.15.
* rate = 12000 * (25 + 100) / 100 for 25% bonus
*/
function calcRate(uint256 _bonus) internal view returns (uint256) {
return _bonus.add(BONUS_COEFF).mul(baseRate).div(BONUS_COEFF);
}
/**
* @dev Checks whether max ether cap is reached for presale
* @return true if max ether cap is reaced
*/
function maxReached() public view returns (bool) {
return weiRaised == maxEtherCap;
}
function forwardFunds(uint256 _toFund) internal {
vault.deposit.value(_toFund)(msg.sender);
}
function finalizePresale(address _mainsale) public onlyOwner {
require(!isFinalized);
require(maxReached() || now > endTime);
PresaleFallbackReceiver mainsale = PresaleFallbackReceiver(_mainsale);
require(mainsale.presaleFallBack(weiRaised));
require(payment.presaleFallBack(weiRaised));
vault.close();
changeController(address(token), _mainsale);
changeOwnership(address(vault), fuzexAccount);
enableSudo(false);
setFinalize();
}
}
{
"compilationTarget": {
"FXTPresale.sol": "FXTPresale"
},
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"decreaseWeiRaised","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"}],"name":"unblockAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"fuzexAccount","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"baseRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"privateEtherFunded","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"endTime","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxEtherCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"sudoEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_target","type":"address"},{"name":"_newOwner","type":"address"}],"name":"changeController","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"weiRaised","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"payment","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_beneficiary","type":"address"},{"name":"_tokens","type":"uint256"}],"name":"paymentFallBack","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"privateMaxEtherCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"presaleMaxEtherCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sudoEnabled","type":"bool"}],"name":"enableSudo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"startTime","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_amount","type":"uint256"}],"name":"generateTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_beneficiary","type":"address"}],"name":"buyPresale","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"isFinalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxReached","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kyc","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_mainsale","type":"address"}],"name":"finalizePresale","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"beneficiaryFunded","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"}],"name":"blockAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PRE_BONUS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"increaseWeiRaised","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_target","type":"address"},{"name":"_newOwner","type":"address"}],"name":"changeOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"presaleMinPurchase","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_amount","type":"uint256"}],"name":"destroyTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"BONUS_COEFF","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"vault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_token","type":"address"},{"name":"_kyc","type":"address"},{"name":"_vault","type":"address"},{"name":"_payment","type":"address"},{"name":"_fuzexAccount","type":"address"},{"name":"_startTime","type":"uint64"},{"name":"_endTime","type":"uint64"},{"name":"_privateEtherFunded","type":"uint256"},{"name":"_privateMaxEtherCap","type":"uint256"},{"name":"_presaleMaxEtherCap","type":"uint256"},{"name":"_presaleMinPurchase","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_purchaser","type":"address"},{"indexed":true,"name":"_beneficiary","type":"address"},{"indexed":false,"name":"toFund","type":"uint256"},{"indexed":false,"name":"tokens","type":"uint256"}],"name":"PresaleTokenPurchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_saleType","type":"uint8"},{"indexed":true,"name":"_beneficiary","type":"address"},{"indexed":false,"name":"_tokens","type":"uint256"}],"name":"MintByBTC","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_sudoEnabled","type":"bool"}],"name":"SudoEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]