// File: contracts/interfaces/IAuthority.sol
pragma solidity ^0.4.24;
contract IAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
// File: contracts/DSAuth.sol
pragma solidity ^0.4.24;
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
/**
* @title DSAuth
* @dev The DSAuth contract is reference implement of https://github.com/dapphub/ds-auth
* But in the isAuthorized method, the src from address(this) is remove for safty concern.
*/
contract DSAuth is DSAuthEvents {
IAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(IAuthority authority_)
public
auth
{
authority = authority_;
emit LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == owner) {
return true;
} else if (authority == IAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
// File: contracts/PausableDSAuth.sol
pragma solidity ^0.4.24;
/**
* @title Pausable
* @dev Base contract which allows children to implement an emergency stop mechanism.
*/
contract PausableDSAuth is DSAuth {
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() public onlyOwner whenNotPaused {
paused = true;
emit Pause();
}
/**
* @dev called by the owner to unpause, returns to normal state
*/
function unpause() public onlyOwner whenPaused {
paused = false;
emit Unpause();
}
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
pragma solidity ^0.4.24;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* See https://github.com/ethereum/EIPs/issues/179
*/
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);
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
pragma solidity ^0.4.24;
/**
* @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
);
}
// File: contracts/interfaces/IBurnableERC20.sol
pragma solidity ^0.4.23;
contract IBurnableERC20 {
function burn(address _from, uint _value) public;
}
// File: contracts/interfaces/ISettingsRegistry.sol
pragma solidity ^0.4.24;
contract ISettingsRegistry {
enum SettingsValueTypes { NONE, UINT, STRING, ADDRESS, BYTES, BOOL, INT }
function uintOf(bytes32 _propertyName) public view returns (uint256);
function stringOf(bytes32 _propertyName) public view returns (string);
function addressOf(bytes32 _propertyName) public view returns (address);
function bytesOf(bytes32 _propertyName) public view returns (bytes);
function boolOf(bytes32 _propertyName) public view returns (bool);
function intOf(bytes32 _propertyName) public view returns (int);
function setUintProperty(bytes32 _propertyName, uint _value) public;
function setStringProperty(bytes32 _propertyName, string _value) public;
function setAddressProperty(bytes32 _propertyName, address _value) public;
function setBytesProperty(bytes32 _propertyName, bytes _value) public;
function setBoolProperty(bytes32 _propertyName, bool _value) public;
function setIntProperty(bytes32 _propertyName, int _value) public;
function getValueTypeOf(bytes32 _propertyName) public view returns (uint /* SettingsValueTypes */ );
event ChangeProperty(bytes32 indexed _propertyName, uint256 _type);
}
// File: contracts/Issuing.sol
pragma solidity ^0.4.24;
contract Issuing is PausableDSAuth {
// claimedToken event
event ClaimedTokens(
address indexed token,
address indexed owner,
uint256 amount
);
event BurnAndRedeem(
address indexed token,
address indexed from,
uint256 amount,
bytes receiver
);
ISettingsRegistry public registry;
mapping(address => bool) public supportedTokens;
constructor(address _registry) public{
registry = ISettingsRegistry(_registry);
}
/**
* @dev ERC223 fallback function, make sure to check the msg.sender is from target token contracts
* @param _from - person who transfer token in for deposits or claim deposit with penalty KTON.
* @param _amount - amount of token.
* @param _data - data which indicate the operations.
*/
function tokenFallback(
address _from,
uint256 _amount,
bytes _data
) public whenNotPaused {
bytes32 darwiniaAddress;
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
darwiniaAddress := mload(add(ptr, 132))
}
// Only supported tokens can be called
require(supportedTokens[msg.sender], "Permission denied");
require(
_data.length == 32,
"The address (Darwinia Network) must be in a 32 bytes hexadecimal format"
);
require(
darwiniaAddress != bytes32(0),
"Darwinia Network Address can't be empty"
);
// SettingIds.UINT_BRIDGE_FEE
uint256 bridgeFee = registry.uintOf(
0x55494e545f4252494447455f4645450000000000000000000000000000000000
);
// SettingIds.CONTRACT_BRIDGE_POOL
address bridgePool = registry.addressOf(
0x434f4e54524143545f4252494447455f504f4f4c000000000000000000000000
);
// SettingIds.CONTRACT_RING_ERC20_TOKEN
address ring = registry.addressOf(
0x434f4e54524143545f52494e475f45524332305f544f4b454e00000000000000
);
// BridgeFee will be paid to the relayer
if (bridgeFee > 0) {
require(
ERC20(ring).transferFrom(_from, bridgePool, bridgeFee),
"Error when paying transaction fees"
);
}
IBurnableERC20(msg.sender).burn(address(this), _amount);
emit BurnAndRedeem(msg.sender, _from, _amount, _data);
}
function addSupportedTokens(address _token) public auth {
supportedTokens[_token] = true;
}
function removeSupportedTokens(address _token) public auth {
supportedTokens[_token] = false;
}
/// @notice This method can be used by the owner to extract mistakenly
/// sent tokens to this contract.
/// @param _token The address of the token contract that you want to recover
/// set to 0 in case you want to extract ether.
function claimTokens(address _token) public auth {
if (_token == 0x0) {
owner.transfer(address(this).balance);
return;
}
ERC20 token = ERC20(_token);
uint256 balance = token.balanceOf(address(this));
token.transfer(owner, balance);
emit ClaimedTokens(_token, owner, balance);
}
}
{
"compilationTarget": {
"Issuing.sol": "Issuing"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[{"name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"addSupportedTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"supportedTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"registry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"removeSupportedTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"tokenFallback","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"claimTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_registry","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":true,"name":"owner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"ClaimedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":true,"name":"from","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"receiver","type":"bytes"}],"name":"BurnAndRedeem","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"}]