// File: contracts/token/interfaces/IERC20Token.sol
pragma solidity 0.4.26;
/*
ERC20 Standard Token interface
*/
contract IERC20Token {
// these functions aren't abstract since the compiler emits automatically generated getter functions as external
function name() public view returns (string) {this;}
function symbol() public view returns (string) {this;}
function decimals() public view returns (uint8) {this;}
function totalSupply() public view returns (uint256) {this;}
function balanceOf(address _owner) public view returns (uint256) {_owner; this;}
function allowance(address _owner, address _spender) public view returns (uint256) {_owner; _spender; this;}
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
}
// File: contracts/IBancorNetwork.sol
pragma solidity 0.4.26;
/*
Bancor Network interface
*/
contract IBancorNetwork {
function convert2(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _affiliateAccount,
uint256 _affiliateFee
) public payable returns (uint256);
function claimAndConvert2(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _affiliateAccount,
uint256 _affiliateFee
) public returns (uint256);
function convertFor2(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for,
address _affiliateAccount,
uint256 _affiliateFee
) public payable returns (uint256);
function claimAndConvertFor2(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for,
address _affiliateAccount,
uint256 _affiliateFee
) public returns (uint256);
// deprecated, backward compatibility
function convert(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn
) public payable returns (uint256);
// deprecated, backward compatibility
function claimAndConvert(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn
) public returns (uint256);
// deprecated, backward compatibility
function convertFor(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for
) public payable returns (uint256);
// deprecated, backward compatibility
function claimAndConvertFor(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for
) public returns (uint256);
// deprecated, backward compatibility
function convertForPrioritized4(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for,
uint256[] memory _signature,
address _affiliateAccount,
uint256 _affiliateFee
) public payable returns (uint256);
// deprecated, backward compatibility
function convertForPrioritized3(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for,
uint256 _customVal,
uint256 _block,
uint8 _v,
bytes32 _r,
bytes32 _s
) public payable returns (uint256);
// deprecated, backward compatibility
function convertForPrioritized2(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for,
uint256 _block,
uint8 _v,
bytes32 _r,
bytes32 _s
) public payable returns (uint256);
// deprecated, backward compatibility
function convertForPrioritized(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for,
uint256 _block,
uint256 _nonce,
uint8 _v,
bytes32 _r,
bytes32 _s
) public payable returns (uint256);
}
// File: contracts/utility/interfaces/IOwned.sol
pragma solidity 0.4.26;
/*
Owned contract interface
*/
contract IOwned {
// this function isn't abstract since the compiler emits automatically generated getter functions as external
function owner() public view returns (address) {this;}
function transferOwnership(address _newOwner) public;
function acceptOwnership() public;
}
// File: contracts/utility/Owned.sol
pragma solidity 0.4.26;
/**
* @dev Provides support and utilities for contract ownership
*/
contract Owned is IOwned {
address public owner;
address public newOwner;
/**
* @dev triggered when the owner is updated
*
* @param _prevOwner previous owner
* @param _newOwner new owner
*/
event OwnerUpdate(address indexed _prevOwner, address indexed _newOwner);
/**
* @dev initializes a new Owned instance
*/
constructor() public {
owner = msg.sender;
}
// allows execution by the owner only
modifier ownerOnly {
require(msg.sender == owner);
_;
}
/**
* @dev allows transferring the contract ownership
* the new owner still needs to accept the transfer
* can only be called by the contract owner
*
* @param _newOwner new contract owner
*/
function transferOwnership(address _newOwner) public ownerOnly {
require(_newOwner != owner);
newOwner = _newOwner;
}
/**
* @dev used by a new owner to accept an ownership transfer
*/
function acceptOwnership() public {
require(msg.sender == newOwner);
emit OwnerUpdate(owner, newOwner);
owner = newOwner;
newOwner = address(0);
}
}
// File: contracts/utility/Utils.sol
pragma solidity 0.4.26;
/**
* @dev Utilities & Common Modifiers
*/
contract Utils {
/**
* constructor
*/
constructor() public {
}
// verifies that an amount is greater than zero
modifier greaterThanZero(uint256 _amount) {
require(_amount > 0);
_;
}
// validates an address - currently only checks that it isn't null
modifier validAddress(address _address) {
require(_address != address(0));
_;
}
// verifies that the address is different than this contract address
modifier notThis(address _address) {
require(_address != address(this));
_;
}
}
// File: contracts/utility/interfaces/IContractRegistry.sol
pragma solidity 0.4.26;
/*
Contract Registry interface
*/
contract IContractRegistry {
function addressOf(bytes32 _contractName) public view returns (address);
// deprecated, backward compatibility
function getAddress(bytes32 _contractName) public view returns (address);
}
// File: contracts/utility/ContractRegistryClient.sol
pragma solidity 0.4.26;
/**
* @dev Base contract for ContractRegistry clients
*/
contract ContractRegistryClient is Owned, Utils {
bytes32 internal constant CONTRACT_FEATURES = "ContractFeatures";
bytes32 internal constant CONTRACT_REGISTRY = "ContractRegistry";
bytes32 internal constant BANCOR_NETWORK = "BancorNetwork";
bytes32 internal constant BANCOR_FORMULA = "BancorFormula";
bytes32 internal constant BANCOR_CONVERTER_FACTORY = "BancorConverterFactory";
bytes32 internal constant BANCOR_CONVERTER_UPGRADER = "BancorConverterUpgrader";
bytes32 internal constant BANCOR_CONVERTER_REGISTRY = "BancorConverterRegistry";
bytes32 internal constant BANCOR_CONVERTER_REGISTRY_DATA = "BancorConverterRegistryData";
bytes32 internal constant BNT_TOKEN = "BNTToken";
bytes32 internal constant BANCOR_X = "BancorX";
bytes32 internal constant BANCOR_X_UPGRADER = "BancorXUpgrader";
IContractRegistry public registry; // address of the current contract-registry
IContractRegistry public prevRegistry; // address of the previous contract-registry
bool public onlyOwnerCanUpdateRegistry; // only an owner can update the contract-registry
/**
* @dev verifies that the caller is mapped to the given contract name
*
* @param _contractName contract name
*/
modifier only(bytes32 _contractName) {
require(msg.sender == addressOf(_contractName));
_;
}
/**
* @dev initializes a new ContractRegistryClient instance
*
* @param _registry address of a contract-registry contract
*/
constructor(IContractRegistry _registry) internal validAddress(_registry) {
registry = IContractRegistry(_registry);
prevRegistry = IContractRegistry(_registry);
}
/**
* @dev updates to the new contract-registry
*/
function updateRegistry() public {
// verify that this function is permitted
require(msg.sender == owner || !onlyOwnerCanUpdateRegistry);
// get the new contract-registry
address newRegistry = addressOf(CONTRACT_REGISTRY);
// verify that the new contract-registry is different and not zero
require(newRegistry != address(registry) && newRegistry != address(0));
// verify that the new contract-registry is pointing to a non-zero contract-registry
require(IContractRegistry(newRegistry).addressOf(CONTRACT_REGISTRY) != address(0));
// save a backup of the current contract-registry before replacing it
prevRegistry = registry;
// replace the current contract-registry with the new contract-registry
registry = IContractRegistry(newRegistry);
}
/**
* @dev restores the previous contract-registry
*/
function restoreRegistry() public ownerOnly {
// restore the previous contract-registry
registry = prevRegistry;
}
/**
* @dev restricts the permission to update the contract-registry
*
* @param _onlyOwnerCanUpdateRegistry indicates whether or not permission is restricted to owner only
*/
function restrictRegistryUpdate(bool _onlyOwnerCanUpdateRegistry) ownerOnly public {
// change the permission to update the contract-registry
onlyOwnerCanUpdateRegistry = _onlyOwnerCanUpdateRegistry;
}
/**
* @dev returns the address associated with the given contract name
*
* @param _contractName contract name
*
* @return contract address
*/
function addressOf(bytes32 _contractName) internal view returns (address) {
return registry.addressOf(_contractName);
}
}
// File: contracts/bancorx/interfaces/IBancorX.sol
pragma solidity 0.4.26;
contract IBancorX {
function xTransfer(bytes32 _toBlockchain, bytes32 _to, uint256 _amount, uint256 _id) public;
function getXTransferAmount(uint256 _xTransferId, address _for) public view returns (uint256);
}
// File: contracts/converter/BancorXHelper.sol
pragma solidity 0.4.26;
/**
* @dev BancorX Helper
*
*/
contract BancorXHelper is ContractRegistryClient {
constructor(IContractRegistry _registry) ContractRegistryClient(_registry) public {
}
/**
* @dev converts any other token to BNT in the bancor network
* by following a predefined conversion path and transfers the resulting
* tokens to BancorX.
* note that the contract should already have been given allowance for the source token (if not ETH)
*
* @param _path conversion path, see conversion path format above
* @param _amount amount to convert from (in the initial source token)
* @param _minReturn if the conversion results in an amount smaller than the minimum return - it is cancelled, must be nonzero
* @param _toBlockchain blockchain BNT will be issued on
* @param _to address/account on _toBlockchain to send the BNT to
* @param _conversionId pre-determined unique (if non zero) id which refers to this transaction
* @param _affiliateAccount affiliate account
* @param _affiliateFee affiliate fee in PPM
*
* @return the amount of BNT received from this conversion
*/
function xConvert(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
bytes32 _toBlockchain,
bytes32 _to,
uint256 _conversionId,
address _affiliateAccount,
uint256 _affiliateFee
)
public
payable
returns (uint256)
{
IBancorX bancorX = IBancorX(addressOf(BANCOR_X));
IBancorNetwork bancorNetwork = IBancorNetwork(addressOf(BANCOR_NETWORK));
IERC20Token targetToken = _path[_path.length - 1];
// verify that the destination token is BNT
require(targetToken == addressOf(BNT_TOKEN));
// we need to transfer the source tokens from the caller to the BancorNetwork contract,
// so it can execute the conversion on behalf of the caller
// not ETH, transfer the tokens directly to the BancorNetwork contract
if (msg.value == 0)
require(_path[0].transferFrom(msg.sender, bancorNetwork, _amount));
// execute the conversion and pass on the ETH with the call
uint256 result = bancorNetwork.convertFor2.value(msg.value)(_path, _amount, _minReturn, this, _affiliateAccount, _affiliateFee);
// grant BancorX allowance
ensureAllowance(targetToken, bancorX, result);
// transfer the resulting amount to BancorX
IBancorX(bancorX).xTransfer(_toBlockchain, _to, result, _conversionId);
return result;
}
/**
* @dev allows a user to convert BNT that was sent from another blockchain into any other
* token on the Bancor Network without specifying the amount of BNT to be converted, but
* rather by providing the xTransferId which allows us to get the amount from BancorX.
*
* @param _path conversion path, see conversion path format in the BancorNetwork contract
* @param _minReturn if the conversion results in an amount smaller than the minimum return - it is cancelled, must be nonzero
* @param _conversionId pre-determined unique (if non zero) id which refers to this transaction
*
* @return tokens issued in return
*/
function completeXConversion(IERC20Token[] _path, uint256 _minReturn, uint256 _conversionId) public returns (uint256) {
IBancorX bancorX = IBancorX(addressOf(BANCOR_X));
IBancorNetwork bancorNetwork = IBancorNetwork(addressOf(BANCOR_NETWORK));
// verify that the source token is BNT
require(_path[0] == addressOf(BNT_TOKEN));
// get conversion amount from BancorX contract
uint256 amount = bancorX.getXTransferAmount(_conversionId, msg.sender);
// transfer the tokens directly to the BancorNetwork contract
require(_path[0].transferFrom(msg.sender, bancorNetwork, amount));
// execute the conversion and transfer the result back to the sender
return bancorNetwork.convertFor2(_path, amount, _minReturn, msg.sender, address(0), 0);
}
/**
* @dev utility, checks whether allowance for the given spender exists and approves one if it doesn't.
* Note that we use the non standard erc-20 interface in which `approve` has no return value so that
* this function will work for both standard and non standard tokens
*
* @param _token token to check the allowance in
* @param _spender approved address
* @param _value allowance amount
*/
function ensureAllowance(IERC20Token _token, address _spender, uint256 _value) private {
uint256 allowance = _token.allowance(this, _spender);
if (allowance < _value) {
if (allowance > 0)
require(_token.approve(_spender, 0));
require(_token.approve(_spender, _value));
}
}
}
{
"compilationTarget": {
"BancorXHelper.sol": "BancorXHelper"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[{"name":"_onlyOwnerCanUpdateRegistry","type":"bool"}],"name":"restrictRegistryUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"onlyOwnerCanUpdateRegistry","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"updateRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_path","type":"address[]"},{"name":"_amount","type":"uint256"},{"name":"_minReturn","type":"uint256"},{"name":"_toBlockchain","type":"bytes32"},{"name":"_to","type":"bytes32"},{"name":"_conversionId","type":"uint256"},{"name":"_affiliateAccount","type":"address"},{"name":"_affiliateFee","type":"uint256"}],"name":"xConvert","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"prevRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","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":"_path","type":"address[]"},{"name":"_minReturn","type":"uint256"},{"name":"_conversionId","type":"uint256"}],"name":"completeXConversion","outputs":[{"name":"","type":"uint256"}],"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":"restoreRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"newOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_registry","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_prevOwner","type":"address"},{"indexed":true,"name":"_newOwner","type":"address"}],"name":"OwnerUpdate","type":"event"}]