Contract
0x45969104EF4561cEe269B334d8CB7a99206a09e5
1
Contract Overview
[ Download CSV Export ]
Contract Source Code Verified (Genesis Bytecode Match Only)
Contract Name:
RubiconRouter
Compiler Version
v0.7.6
Optimization Enabled:
Yes with 1 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 /// @author Benjamin Hughes - Rubicon /// @notice This contract is a router to interact with the low-level functions present in RubiconMarket and Pools pragma solidity =0.7.6; import "./RubiconMarket.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "./peripheral_contracts/ABDKMath64x64.sol"; ///@dev this contract is a high-level router that utilizes Rubicon smart contracts to provide /// added convenience when interacting with the Rubicon protocol contract RubiconRouter { using SafeMath for uint256; address public RubiconMarketAddress; //uint256 MAX_INT = 2**256 - 1 event LogNote(string, uint256); constructor(address _rM) { RubiconMarketAddress = _rM; } /// @dev this function returns the best offer for a pair's id and info function getBestOfferAndInfo(address asset, address quote) public view returns ( uint256, //id uint256, ERC20, uint256, ERC20 ) { address _market = RubiconMarketAddress; uint256 offer = RubiconMarket(_market).getBestOffer( ERC20(asset), ERC20(quote) ); ( uint256 pay_amt, ERC20 pay_gem, uint256 buy_amt, ERC20 buy_gem ) = RubiconMarket(_market).getOffer(offer); return (offer, pay_amt, pay_gem, buy_amt, buy_gem); } // function for infinite approvals of Rubicon Market function approveAssetOnMarket(address toApprove) public { // Approve exchange ERC20(toApprove).approve(RubiconMarketAddress, 2**256 - 1); } /// @dev this function takes the same parameters of swap and returns the expected amount function getExpectedSwapFill( uint256 pay_amt, uint256 buy_amt_min, address[] calldata route, // First address is what is being payed, Last address is what is being bought uint256 expectedMarketFeeBPS //20 ) public view returns (uint256 fill_amt) { address _market = RubiconMarketAddress; uint256 currentAmount = 0; for (uint256 i = 0; i < route.length - 1; i++) { (address input, address output) = (route[i], route[i + 1]); uint256 _pay = i == 0 ? pay_amt : ( currentAmount.sub( currentAmount.mul(expectedMarketFeeBPS).div(10000) ) ); uint256 wouldBeFillAmount = RubiconMarket(_market).getBuyAmount( ERC20(output), ERC20(input), _pay ); currentAmount = wouldBeFillAmount; } require(currentAmount >= buy_amt_min, "didnt clear buy_amt_min"); // Return the wouldbe resulting swap amount return (currentAmount); } /// @dev This function lets a user swap from route[0] -> route[last] at some minimum expected rate /// @dev pay_amt - amount to be swapped away from msg.sender of *first address in path* /// @dev buy_amt_min - target minimum received of *last address in path* function swap( uint256 pay_amt, uint256 buy_amt_min, address[] calldata route, // First address is what is being payed, Last address is what is being bought uint256 expectedMarketFeeBPS //20 ) public { //User must approve this contract first //transfer needed amount here first ERC20(route[0]).transferFrom( msg.sender, address(this), pay_amt.add(pay_amt.mul(expectedMarketFeeBPS).div(10000)) ); address _market = RubiconMarketAddress; uint256 currentAmount = 0; for (uint256 i = 0; i < route.length - 1; i++) { (address input, address output) = (route[i], route[i + 1]); uint256 _pay = i == 0 ? pay_amt : ( currentAmount.sub( currentAmount.mul(expectedMarketFeeBPS).div(10000) ) ); if (ERC20(input).allowance(address(this), _market) == 0) { approveAssetOnMarket(input); } uint256 fillAmount = RubiconMarket(_market).sellAllAmount( ERC20(input), _pay, ERC20(output), 0 //naively assume no fill_amt here for loop purposes? ); currentAmount = fillAmount; } require(currentAmount >= buy_amt_min, "didnt clear buy_amt_min"); // send tokens back to sender ERC20(route[route.length - 1]).transfer(msg.sender, currentAmount); } }
/// SPDX-License-Identifier: Apache-2.0 /// This contract is a derivative work of the open-source work of Oasis DEX: https://github.com/OasisDEX/oasis /// @title RubiconMarket.sol /// @notice Please see the repository for this code at https://github.com/RubiconDeFi/rubicon_protocol; pragma solidity =0.7.6; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; /// @notice DSAuth events for authentication schema contract DSAuthEvents { event LogSetAuthority(address indexed authority); event LogSetOwner(address indexed owner); } /// @notice DSAuth library for setting owner of the contract /// @dev Provides the auth modifier for authenticated function calls contract DSAuth is DSAuthEvents { address public owner; function setOwner(address owner_) external auth { owner = owner_; emit LogSetOwner(owner); } modifier auth { require(isAuthorized(msg.sender), "ds-auth-unauthorized"); _; } function isAuthorized(address src) internal view returns (bool) { if (src == address(this)) { return true; } else if (src == owner) { return true; } else { return false; } } } /// @notice DSMath library for safe math without integer overflow/underflow contract DSMath { function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, "ds-math-add-overflow"); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x, "ds-math-sub-underflow"); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } function min(uint256 x, uint256 y) internal pure returns (uint256 z) { return x <= y ? x : y; } function max(uint256 x, uint256 y) internal pure returns (uint256 z) { return x >= y ? x : y; } function imin(int256 x, int256 y) internal pure returns (int256 z) { return x <= y ? x : y; } function imax(int256 x, int256 y) internal pure returns (int256 z) { return x >= y ? x : y; } uint256 constant WAD = 10**18; uint256 constant RAY = 10**27; function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, y), WAD / 2) / WAD; } function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, y), RAY / 2) / RAY; } function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, WAD), y / 2) / y; } function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = add(mul(x, RAY), y / 2) / y; } } // /// @notice ERC-20 interface as derived from EIP-20 // contract ERC20 { // function totalSupply() public view returns (uint256); // function balanceOf(address guy) public view returns (uint256); // function allowance(address src, address guy) public view returns (uint256); // function approve(address guy, uint256 wad) public returns (bool); // function transfer(address dst, uint256 wad) public returns (bool); // function transferFrom( // address src, // address dst, // uint256 wad // ) public returns (bool); // } /// @notice Events contract for logging trade activity on Rubicon Market /// @dev Provides the key event logs that are used in all core functionality of exchanging on the Rubicon Market contract EventfulMarket { event LogItemUpdate(uint256 id); event LogTrade( uint256 pay_amt, address indexed pay_gem, uint256 buy_amt, address indexed buy_gem ); event LogMake( bytes32 indexed id, bytes32 indexed pair, address indexed maker, ERC20 pay_gem, ERC20 buy_gem, uint128 pay_amt, uint128 buy_amt, uint64 timestamp ); event LogBump( bytes32 indexed id, bytes32 indexed pair, address indexed maker, ERC20 pay_gem, ERC20 buy_gem, uint128 pay_amt, uint128 buy_amt, uint64 timestamp ); event LogTake( bytes32 id, bytes32 indexed pair, address indexed maker, ERC20 pay_gem, ERC20 buy_gem, address indexed taker, uint128 take_amt, uint128 give_amt, uint64 timestamp ); event LogKill( bytes32 indexed id, bytes32 indexed pair, address indexed maker, ERC20 pay_gem, ERC20 buy_gem, uint128 pay_amt, uint128 buy_amt, uint64 timestamp ); event LogInt(string lol, uint256 input); event FeeTake( bytes32 id, bytes32 indexed pair, ERC20 asset, address indexed taker, address feeTo, uint256 feeAmt, uint64 timestamp ); event OfferDeleted(uint256 id); } /// @notice Core trading logic for ERC-20 pairs, an orderbook, and transacting of tokens /// @dev This contract holds the core ERC-20 / ERC-20 offer, buy, and cancel logic contract SimpleMarket is EventfulMarket, DSMath { uint256 public last_offer_id; /// @dev The mapping that makes up the core orderbook of the exchange mapping(uint256 => OfferInfo) public offers; bool locked; /// @dev This parameter is in basis points uint256 internal feeBPS; /// @dev This parameter provides the address to which fees are sent address internal feeTo; struct OfferInfo { uint256 pay_amt; ERC20 pay_gem; uint256 buy_amt; ERC20 buy_gem; address owner; uint64 timestamp; } /// @notice Modifier that insures an order exists and is properly in the orderbook modifier can_buy(uint256 id) virtual { require(isActive(id)); _; } /// @notice Modifier that checks the user to make sure they own the offer and its valid before they attempt to cancel it modifier can_cancel(uint256 id) virtual { require(isActive(id)); require(getOwner(id) == msg.sender); _; } modifier can_offer virtual { _; } modifier synchronized { require(!locked); locked = true; _; locked = false; } function isActive(uint256 id) public view returns (bool active) { return offers[id].timestamp > 0; } function getOwner(uint256 id) public view returns (address owner) { return offers[id].owner; } function getOffer(uint256 id) public view returns ( uint256, ERC20, uint256, ERC20 ) { OfferInfo memory _offer = offers[id]; return (_offer.pay_amt, _offer.pay_gem, _offer.buy_amt, _offer.buy_gem); } /// @notice Below are the main public entrypoints function bump(bytes32 id_) external can_buy(uint256(id_)) { uint256 id = uint256(id_); emit LogBump( id_, keccak256(abi.encodePacked(offers[id].pay_gem, offers[id].buy_gem)), offers[id].owner, offers[id].pay_gem, offers[id].buy_gem, uint128(offers[id].pay_amt), uint128(offers[id].buy_amt), offers[id].timestamp ); } /// @notice Accept a given `quantity` of an offer. Transfers funds from caller/taker to offer maker, and from market to caller/taker. /// @notice The fee for taker trades is paid in this function. function buy(uint256 id, uint256 quantity) public virtual can_buy(id) synchronized returns (bool) { OfferInfo memory _offer = offers[id]; uint256 spend = mul(quantity, _offer.buy_amt) / _offer.pay_amt; require(uint128(spend) == spend, "spend is not an int"); require(uint128(quantity) == quantity, "quantity is not an int"); ///@dev For backwards semantic compatibility. if ( quantity == 0 || spend == 0 || quantity > _offer.pay_amt || spend > _offer.buy_amt ) { return false; } uint256 fee = mul(spend, feeBPS) / 10000; require( _offer.buy_gem.transferFrom(msg.sender, feeTo, fee), "Insufficient funds to cover fee" ); offers[id].pay_amt = sub(_offer.pay_amt, quantity); offers[id].buy_amt = sub(_offer.buy_amt, spend); require( _offer.buy_gem.transferFrom(msg.sender, _offer.owner, spend), "_offer.buy_gem.transferFrom(msg.sender, _offer.owner, spend) failed - check that you can pay the fee" ); require( _offer.pay_gem.transfer(msg.sender, quantity), "_offer.pay_gem.transfer(msg.sender, quantity) failed" ); emit LogItemUpdate(id); emit LogTake( bytes32(id), keccak256(abi.encodePacked(_offer.pay_gem, _offer.buy_gem)), _offer.owner, _offer.pay_gem, _offer.buy_gem, msg.sender, uint128(quantity), uint128(spend), uint64(block.timestamp) ); emit FeeTake( bytes32(id), keccak256(abi.encodePacked(_offer.pay_gem, _offer.buy_gem)), _offer.buy_gem, msg.sender, feeTo, fee, uint64(block.timestamp) ); emit LogTrade( quantity, address(_offer.pay_gem), spend, address(_offer.buy_gem) ); if (offers[id].pay_amt == 0) { delete offers[id]; emit OfferDeleted(id); } return true; } /// @notice Allows the caller to cancel the offer if it is their own. /// @notice This function refunds the offer to the maker. function cancel(uint256 id) public virtual can_cancel(id) synchronized returns (bool success) { OfferInfo memory _offer = offers[id]; delete offers[id]; require(_offer.pay_gem.transfer(_offer.owner, _offer.pay_amt)); emit LogItemUpdate(id); emit LogKill( bytes32(id), keccak256(abi.encodePacked(_offer.pay_gem, _offer.buy_gem)), _offer.owner, _offer.pay_gem, _offer.buy_gem, uint128(_offer.pay_amt), uint128(_offer.buy_amt), uint64(block.timestamp) ); success = true; } function kill(bytes32 id) external virtual { require(cancel(uint256(id))); } function make( ERC20 pay_gem, ERC20 buy_gem, uint128 pay_amt, uint128 buy_amt ) external virtual returns (bytes32 id) { return bytes32(offer(pay_amt, pay_gem, buy_amt, buy_gem)); } /// @notice Key function to make a new offer. Takes funds from the caller into market escrow. function offer( uint256 pay_amt, ERC20 pay_gem, uint256 buy_amt, ERC20 buy_gem ) public virtual can_offer synchronized returns (uint256 id) { require(uint128(pay_amt) == pay_amt); require(uint128(buy_amt) == buy_amt); require(pay_amt > 0); require(pay_gem != ERC20(0x0)); require(buy_amt > 0); require(buy_gem != ERC20(0x0)); require(pay_gem != buy_gem); OfferInfo memory info; info.pay_amt = pay_amt; info.pay_gem = pay_gem; info.buy_amt = buy_amt; info.buy_gem = buy_gem; info.owner = msg.sender; info.timestamp = uint64(block.timestamp); id = _next_id(); offers[id] = info; require(pay_gem.transferFrom(msg.sender, address(this), pay_amt)); emit LogItemUpdate(id); emit LogMake( bytes32(id), keccak256(abi.encodePacked(pay_gem, buy_gem)), msg.sender, pay_gem, buy_gem, uint128(pay_amt), uint128(buy_amt), uint64(block.timestamp) ); } function take(bytes32 id, uint128 maxTakeAmount) external virtual { require(buy(uint256(id), maxTakeAmount)); } function _next_id() internal returns (uint256) { last_offer_id++; return last_offer_id; } // Fee logic function getFeeBPS() internal view returns (uint256) { return feeBPS; } } /// @notice Expiring market is a Simple Market with a market lifetime. /// @dev When the close_time has been reached, offers can only be cancelled (offer and buy will throw). contract ExpiringMarket is DSAuth, SimpleMarket { bool public stopped; /// @dev After close_time has been reached, no new offers are allowed. modifier can_offer override { require(!isClosed()); _; } /// @dev After close, no new buys are allowed. modifier can_buy(uint256 id) override { require(isActive(id)); require(!isClosed()); _; } /// @dev After close, anyone can cancel an offer. modifier can_cancel(uint256 id) virtual override { require(isActive(id)); require((msg.sender == getOwner(id)) || isClosed()); _; } function isClosed() public pure returns (bool closed) { return false; } function getTime() public view returns (uint64) { return uint64(block.timestamp); } function stop() external auth { stopped = true; } } contract DSNote { event LogNote( bytes4 indexed sig, address indexed guy, bytes32 indexed foo, bytes32 indexed bar, uint256 wad, bytes fax ) anonymous; modifier note { bytes32 foo; bytes32 bar; uint256 wad; assembly { foo := calldataload(4) bar := calldataload(36) wad := callvalue() } emit LogNote(msg.sig, msg.sender, foo, bar, wad, msg.data); _; } } contract MatchingEvents { event LogBuyEnabled(bool isEnabled); event LogMinSell(address pay_gem, uint256 min_amount); event LogMatchingEnabled(bool isEnabled); event LogUnsortedOffer(uint256 id); event LogSortedOffer(uint256 id); event LogInsert(address keeper, uint256 id); event LogDelete(address keeper, uint256 id); event LogMatch(uint256 id, uint256 amount); } /// @notice The core Rubicon Market smart contract /// @notice This contract is based on the original open-source work done by OasisDEX under the Apache License 2.0 /// @dev This contract inherits the key trading functionality from SimpleMarket contract RubiconMarket is MatchingEvents, ExpiringMarket, DSNote { bool public buyEnabled = true; //buy enabled bool public matchingEnabled = true; //true: enable matching, //false: revert to expiring market /// @dev Below is variable to allow for a proxy-friendly constructor bool public initialized; bool public AqueductDistributionLive; address public AqueductAddress; struct sortInfo { uint256 next; //points to id of next higher offer uint256 prev; //points to id of previous lower offer uint256 delb; //the blocknumber where this entry was marked for delete } mapping(uint256 => sortInfo) public _rank; //doubly linked lists of sorted offer ids mapping(address => mapping(address => uint256)) public _best; //id of the highest offer for a token pair mapping(address => mapping(address => uint256)) public _span; //number of offers stored for token pair in sorted orderbook mapping(address => uint256) public _dust; //minimum sell amount for a token to avoid dust offers mapping(uint256 => uint256) public _near; //next unsorted offer id uint256 public _head; //first unsorted offer id uint256 public dustId; // id of the latest offer marked as dust /// @dev Proxy-safe initialization of storage function initialize(bool _live, address _feeTo) public { // require(msg.sender == ___deployer____); require(!initialized, "contract is already initialized"); AqueductDistributionLive = _live; feeTo = _feeTo; owner = msg.sender; emit LogSetOwner(msg.sender); /// @notice The starting fee on taker trades in basis points feeBPS = 20; initialized = true; matchingEnabled = true; buyEnabled = true; } // After close, anyone can cancel an offer modifier can_cancel(uint256 id) override { require(isActive(id), "Offer was deleted or taken, or never existed."); require( isClosed() || msg.sender == getOwner(id) || id == dustId, "Offer can not be cancelled because user is not owner, and market is open, and offer sells required amount of tokens." ); _; } // ---- Public entrypoints ---- // function make( ERC20 pay_gem, ERC20 buy_gem, uint128 pay_amt, uint128 buy_amt ) public override returns (bytes32) { return bytes32(offer(pay_amt, pay_gem, buy_amt, buy_gem)); } function take(bytes32 id, uint128 maxTakeAmount) public override { require(buy(uint256(id), maxTakeAmount)); } function kill(bytes32 id) external override { require(cancel(uint256(id))); } // Make a new offer. Takes funds from the caller into market escrow. // // If matching is enabled: // * creates new offer without putting it in // the sorted list. // * available to authorized contracts only! // * keepers should call insert(id,pos) // to put offer in the sorted list. // // If matching is disabled: // * calls expiring market's offer(). // * available to everyone without authorization. // * no sorting is done. // function offer( uint256 pay_amt, //maker (ask) sell how much ERC20 pay_gem, //maker (ask) sell which token uint256 buy_amt, //taker (ask) buy how much ERC20 buy_gem //taker (ask) buy which token ) public override returns (uint256) { require(!locked, "Reentrancy attempt"); function(uint256, ERC20, uint256, ERC20) returns (uint256) fn = matchingEnabled ? _offeru : super.offer; return fn(pay_amt, pay_gem, buy_amt, buy_gem); } // Make a new offer. Takes funds from the caller into market escrow. function offer( uint256 pay_amt, //maker (ask) sell how much ERC20 pay_gem, //maker (ask) sell which token uint256 buy_amt, //maker (ask) buy how much ERC20 buy_gem, //maker (ask) buy which token uint256 pos //position to insert offer, 0 should be used if unknown ) external can_offer returns (uint256) { return offer(pay_amt, pay_gem, buy_amt, buy_gem, pos, true); } function offer( uint256 pay_amt, //maker (ask) sell how much ERC20 pay_gem, //maker (ask) sell which token uint256 buy_amt, //maker (ask) buy how much ERC20 buy_gem, //maker (ask) buy which token uint256 pos, //position to insert offer, 0 should be used if unknown bool matching //match "close enough" orders? ) public can_offer returns (uint256) { require(!locked, "Reentrancy attempt"); require(_dust[address(pay_gem)] <= pay_amt); if (matchingEnabled) { return _matcho(pay_amt, pay_gem, buy_amt, buy_gem, pos, matching); } return super.offer(pay_amt, pay_gem, buy_amt, buy_gem); } //Transfers funds from caller to offer maker, and from market to caller. function buy(uint256 id, uint256 amount) public override can_buy(id) returns (bool) { require(!locked, "Reentrancy attempt"); //Optional distribution on trade if (AqueductDistributionLive) { IAqueduct(AqueductAddress).distributeToMakerAndTaker( getOwner(id), msg.sender ); } function(uint256, uint256) returns (bool) fn = matchingEnabled ? _buys : super.buy; return fn(id, amount); } // Cancel an offer. Refunds offer maker. function cancel(uint256 id) public override can_cancel(id) returns (bool success) { require(!locked, "Reentrancy attempt"); if (matchingEnabled) { if (isOfferSorted(id)) { require(_unsort(id)); } else { require(_hide(id)); } } return super.cancel(id); //delete the offer. } //insert offer into the sorted list //keepers need to use this function function insert( uint256 id, //maker (ask) id uint256 pos //position to insert into ) public returns (bool) { require(!locked, "Reentrancy attempt"); require(!isOfferSorted(id)); //make sure offers[id] is not yet sorted require(isActive(id)); //make sure offers[id] is active _hide(id); //remove offer from unsorted offers list _sort(id, pos); //put offer into the sorted offers list emit LogInsert(msg.sender, id); return true; } //deletes _rank [id] // Function should be called by keepers. function del_rank(uint256 id) external returns (bool) { require(!locked, "Reentrancy attempt"); require( !isActive(id) && _rank[id].delb != 0 && _rank[id].delb < block.number - 10 ); delete _rank[id]; emit LogDelete(msg.sender, id); return true; } //set the minimum sell amount for a token // Function is used to avoid "dust offers" that have // very small amount of tokens to sell, and it would // cost more gas to accept the offer, than the value // of tokens received. function setMinSell( ERC20 pay_gem, //token to assign minimum sell amount to uint256 dust //maker (ask) minimum sell amount ) external auth note returns (bool) { _dust[address(pay_gem)] = dust; emit LogMinSell(address(pay_gem), dust); return true; } //returns the minimum sell amount for an offer function getMinSell( ERC20 pay_gem //token for which minimum sell amount is queried ) external view returns (uint256) { return _dust[address(pay_gem)]; } //set buy functionality enabled/disabled function setBuyEnabled(bool buyEnabled_) external auth returns (bool) { buyEnabled = buyEnabled_; emit LogBuyEnabled(buyEnabled); return true; } //set matching enabled/disabled // If matchingEnabled true(default), then inserted offers are matched. // Except the ones inserted by contracts, because those end up // in the unsorted list of offers, that must be later sorted by // keepers using insert(). // If matchingEnabled is false then RubiconMarket is reverted to ExpiringMarket, // and matching is not done, and sorted lists are disabled. function setMatchingEnabled(bool matchingEnabled_) external auth returns (bool) { matchingEnabled = matchingEnabled_; emit LogMatchingEnabled(matchingEnabled); return true; } //return the best offer for a token pair // the best offer is the lowest one if it's an ask, // and highest one if it's a bid offer function getBestOffer(ERC20 sell_gem, ERC20 buy_gem) public view returns (uint256) { return _best[address(sell_gem)][address(buy_gem)]; } //return the next worse offer in the sorted list // the worse offer is the higher one if its an ask, // a lower one if its a bid offer, // and in both cases the newer one if they're equal. function getWorseOffer(uint256 id) public view returns (uint256) { return _rank[id].prev; } //return the next better offer in the sorted list // the better offer is in the lower priced one if its an ask, // the next higher priced one if its a bid offer // and in both cases the older one if they're equal. function getBetterOffer(uint256 id) external view returns (uint256) { return _rank[id].next; } //return the amount of better offers for a token pair function getOfferCount(ERC20 sell_gem, ERC20 buy_gem) public view returns (uint256) { return _span[address(sell_gem)][address(buy_gem)]; } //get the first unsorted offer that was inserted by a contract // Contracts can't calculate the insertion position of their offer because it is not an O(1) operation. // Their offers get put in the unsorted list of offers. // Keepers can calculate the insertion position offchain and pass it to the insert() function to insert // the unsorted offer into the sorted list. Unsorted offers will not be matched, but can be bought with buy(). function getFirstUnsortedOffer() public view returns (uint256) { return _head; } //get the next unsorted offer // Can be used to cycle through all the unsorted offers. function getNextUnsortedOffer(uint256 id) public view returns (uint256) { return _near[id]; } function isOfferSorted(uint256 id) public view returns (bool) { return _rank[id].next != 0 || _rank[id].prev != 0 || _best[address(offers[id].pay_gem)][address(offers[id].buy_gem)] == id; } function sellAllAmount( ERC20 pay_gem, uint256 pay_amt, ERC20 buy_gem, uint256 min_fill_amount ) external returns (uint256 fill_amt) { require(!locked, "Reentrancy attempt"); uint256 offerId; while (pay_amt > 0) { //while there is amount to sell offerId = getBestOffer(buy_gem, pay_gem); //Get the best offer for the token pair require(offerId != 0); //Fails if there are not more offers // There is a chance that pay_amt is smaller than 1 wei of the other token if ( pay_amt * 1 ether < wdiv(offers[offerId].buy_amt, offers[offerId].pay_amt) ) { break; //We consider that all amount is sold } if (pay_amt >= offers[offerId].buy_amt) { //If amount to sell is higher or equal than current offer amount to buy fill_amt = add(fill_amt, offers[offerId].pay_amt); //Add amount bought to acumulator pay_amt = sub(pay_amt, offers[offerId].buy_amt); //Decrease amount to sell take(bytes32(offerId), uint128(offers[offerId].pay_amt)); //We take the whole offer } else { // if lower uint256 baux = rmul( pay_amt * 10**9, rdiv(offers[offerId].pay_amt, offers[offerId].buy_amt) ) / 10**9; fill_amt = add(fill_amt, baux); //Add amount bought to acumulator take(bytes32(offerId), uint128(baux)); //We take the portion of the offer that we need pay_amt = 0; //All amount is sold } } require(fill_amt >= min_fill_amount); } function buyAllAmount( ERC20 buy_gem, uint256 buy_amt, ERC20 pay_gem, uint256 max_fill_amount ) external returns (uint256 fill_amt) { require(!locked, "Reentrancy attempt"); uint256 offerId; while (buy_amt > 0) { //Meanwhile there is amount to buy offerId = getBestOffer(buy_gem, pay_gem); //Get the best offer for the token pair require(offerId != 0); // There is a chance that buy_amt is smaller than 1 wei of the other token if ( buy_amt * 1 ether < wdiv(offers[offerId].pay_amt, offers[offerId].buy_amt) ) { break; //We consider that all amount is sold } if (buy_amt >= offers[offerId].pay_amt) { //If amount to buy is higher or equal than current offer amount to sell fill_amt = add(fill_amt, offers[offerId].buy_amt); //Add amount sold to acumulator buy_amt = sub(buy_amt, offers[offerId].pay_amt); //Decrease amount to buy take(bytes32(offerId), uint128(offers[offerId].pay_amt)); //We take the whole offer } else { //if lower fill_amt = add( fill_amt, rmul( buy_amt * 10**9, rdiv(offers[offerId].buy_amt, offers[offerId].pay_amt) ) / 10**9 ); //Add amount sold to acumulator take(bytes32(offerId), uint128(buy_amt)); //We take the portion of the offer that we need buy_amt = 0; //All amount is bought } } require(fill_amt <= max_fill_amount); } function getBuyAmount( ERC20 buy_gem, ERC20 pay_gem, uint256 pay_amt ) external view returns (uint256 fill_amt) { uint256 offerId = getBestOffer(buy_gem, pay_gem); //Get best offer for the token pair while (pay_amt > offers[offerId].buy_amt) { fill_amt = add(fill_amt, offers[offerId].pay_amt); //Add amount to buy accumulator pay_amt = sub(pay_amt, offers[offerId].buy_amt); //Decrease amount to pay if (pay_amt > 0) { //If we still need more offers offerId = getWorseOffer(offerId); //We look for the next best offer require(offerId != 0); //Fails if there are not enough offers to complete } } fill_amt = add( fill_amt, rmul( pay_amt * 10**9, rdiv(offers[offerId].pay_amt, offers[offerId].buy_amt) ) / 10**9 ); //Add proportional amount of last offer to buy accumulator } function getPayAmount( ERC20 pay_gem, ERC20 buy_gem, uint256 buy_amt ) external view returns (uint256 fill_amt) { uint256 offerId = getBestOffer(buy_gem, pay_gem); //Get best offer for the token pair while (buy_amt > offers[offerId].pay_amt) { fill_amt = add(fill_amt, offers[offerId].buy_amt); //Add amount to pay accumulator buy_amt = sub(buy_amt, offers[offerId].pay_amt); //Decrease amount to buy if (buy_amt > 0) { //If we still need more offers offerId = getWorseOffer(offerId); //We look for the next best offer require(offerId != 0); //Fails if there are not enough offers to complete } } fill_amt = add( fill_amt, rmul( buy_amt * 10**9, rdiv(offers[offerId].buy_amt, offers[offerId].pay_amt) ) / 10**9 ); //Add proportional amount of last offer to pay accumulator } // ---- Internal Functions ---- // function _buys(uint256 id, uint256 amount) internal returns (bool) { require(buyEnabled); if (amount == offers[id].pay_amt) { if (isOfferSorted(id)) { //offers[id] must be removed from sorted list because all of it is bought _unsort(id); } else { _hide(id); } } require(super.buy(id, amount)); // If offer has become dust during buy, we cancel it if ( isActive(id) && offers[id].pay_amt < _dust[address(offers[id].pay_gem)] ) { dustId = id; //enable current msg.sender to call cancel(id) cancel(id); } return true; } //find the id of the next higher offer after offers[id] function _find(uint256 id) internal view returns (uint256) { require(id > 0); address buy_gem = address(offers[id].buy_gem); address pay_gem = address(offers[id].pay_gem); uint256 top = _best[pay_gem][buy_gem]; uint256 old_top = 0; // Find the larger-than-id order whose successor is less-than-id. while (top != 0 && _isPricedLtOrEq(id, top)) { old_top = top; top = _rank[top].prev; } return old_top; } //find the id of the next higher offer after offers[id] function _findpos(uint256 id, uint256 pos) internal view returns (uint256) { require(id > 0); // Look for an active order. while (pos != 0 && !isActive(pos)) { pos = _rank[pos].prev; } if (pos == 0) { //if we got to the end of list without a single active offer return _find(id); } else { // if we did find a nearby active offer // Walk the order book down from there... if (_isPricedLtOrEq(id, pos)) { uint256 old_pos; // Guaranteed to run at least once because of // the prior if statements. while (pos != 0 && _isPricedLtOrEq(id, pos)) { old_pos = pos; pos = _rank[pos].prev; } return old_pos; // ...or walk it up. } else { while (pos != 0 && !_isPricedLtOrEq(id, pos)) { pos = _rank[pos].next; } return pos; } } } //return true if offers[low] priced less than or equal to offers[high] function _isPricedLtOrEq( uint256 low, //lower priced offer's id uint256 high //higher priced offer's id ) internal view returns (bool) { return mul(offers[low].buy_amt, offers[high].pay_amt) >= mul(offers[high].buy_amt, offers[low].pay_amt); } //these variables are global only because of solidity local variable limit //match offers with taker offer, and execute token transactions function _matcho( uint256 t_pay_amt, //taker sell how much ERC20 t_pay_gem, //taker sell which token uint256 t_buy_amt, //taker buy how much ERC20 t_buy_gem, //taker buy which token uint256 pos, //position id bool rounding //match "close enough" orders? ) internal returns (uint256 id) { uint256 best_maker_id; //highest maker id uint256 t_buy_amt_old; //taker buy how much saved uint256 m_buy_amt; //maker offer wants to buy this much token uint256 m_pay_amt; //maker offer wants to sell this much token // there is at least one offer stored for token pair while (_best[address(t_buy_gem)][address(t_pay_gem)] > 0) { best_maker_id = _best[address(t_buy_gem)][address(t_pay_gem)]; m_buy_amt = offers[best_maker_id].buy_amt; m_pay_amt = offers[best_maker_id].pay_amt; // Ugly hack to work around rounding errors. Based on the idea that // the furthest the amounts can stray from their "true" values is 1. // Ergo the worst case has t_pay_amt and m_pay_amt at +1 away from // their "correct" values and m_buy_amt and t_buy_amt at -1. // Since (c - 1) * (d - 1) > (a + 1) * (b + 1) is equivalent to // c * d > a * b + a + b + c + d, we write... if ( mul(m_buy_amt, t_buy_amt) > mul(t_pay_amt, m_pay_amt) + ( rounding ? m_buy_amt + t_buy_amt + t_pay_amt + m_pay_amt : 0 ) ) { break; } // ^ The `rounding` parameter is a compromise borne of a couple days // of discussion. buy(best_maker_id, min(m_pay_amt, t_buy_amt)); emit LogMatch(id, min(m_pay_amt, t_buy_amt)); t_buy_amt_old = t_buy_amt; t_buy_amt = sub(t_buy_amt, min(m_pay_amt, t_buy_amt)); t_pay_amt = mul(t_buy_amt, t_pay_amt) / t_buy_amt_old; if (t_pay_amt == 0 || t_buy_amt == 0) { break; } } if ( t_buy_amt > 0 && t_pay_amt > 0 && t_pay_amt >= _dust[address(t_pay_gem)] ) { //new offer should be created id = super.offer(t_pay_amt, t_pay_gem, t_buy_amt, t_buy_gem); //insert offer into the sorted list _sort(id, pos); } } // Make a new offer without putting it in the sorted list. // Takes funds from the caller into market escrow. // Keepers should call insert(id,pos) to put offer in the sorted list. function _offeru( uint256 pay_amt, //maker (ask) sell how much ERC20 pay_gem, //maker (ask) sell which token uint256 buy_amt, //maker (ask) buy how much ERC20 buy_gem //maker (ask) buy which token ) internal returns (uint256 id) { require(_dust[address(pay_gem)] <= pay_amt); id = super.offer(pay_amt, pay_gem, buy_amt, buy_gem); _near[id] = _head; _head = id; emit LogUnsortedOffer(id); } //put offer into the sorted list function _sort( uint256 id, //maker (ask) id uint256 pos //position to insert into ) internal { require(isActive(id)); ERC20 buy_gem = offers[id].buy_gem; ERC20 pay_gem = offers[id].pay_gem; uint256 prev_id; //maker (ask) id pos = pos == 0 || offers[pos].pay_gem != pay_gem || offers[pos].buy_gem != buy_gem || !isOfferSorted(pos) ? _find(id) : _findpos(id, pos); if (pos != 0) { //offers[id] is not the highest offer //requirement below is satisfied by statements above //require(_isPricedLtOrEq(id, pos)); prev_id = _rank[pos].prev; _rank[pos].prev = id; _rank[id].next = pos; } else { //offers[id] is the highest offer prev_id = _best[address(pay_gem)][address(buy_gem)]; _best[address(pay_gem)][address(buy_gem)] = id; } if (prev_id != 0) { //if lower offer does exist //requirement below is satisfied by statements above //require(!_isPricedLtOrEq(id, prev_id)); _rank[prev_id].next = id; _rank[id].prev = prev_id; } _span[address(pay_gem)][address(buy_gem)]++; emit LogSortedOffer(id); } // Remove offer from the sorted list (does not cancel offer) function _unsort( uint256 id //id of maker (ask) offer to remove from sorted list ) internal returns (bool) { address buy_gem = address(offers[id].buy_gem); address pay_gem = address(offers[id].pay_gem); require(_span[pay_gem][buy_gem] > 0); require( _rank[id].delb == 0 && //assert id is in the sorted list isOfferSorted(id) ); if (id != _best[pay_gem][buy_gem]) { // offers[id] is not the highest offer require(_rank[_rank[id].next].prev == id); _rank[_rank[id].next].prev = _rank[id].prev; } else { //offers[id] is the highest offer _best[pay_gem][buy_gem] = _rank[id].prev; } if (_rank[id].prev != 0) { //offers[id] is not the lowest offer require(_rank[_rank[id].prev].next == id); _rank[_rank[id].prev].next = _rank[id].next; } _span[pay_gem][buy_gem]--; _rank[id].delb = block.number; //mark _rank[id] for deletion return true; } //Hide offer from the unsorted order book (does not cancel offer) function _hide( uint256 id //id of maker offer to remove from unsorted list ) internal returns (bool) { uint256 uid = _head; //id of an offer in unsorted offers list uint256 pre = uid; //id of previous offer in unsorted offers list require(!isOfferSorted(id)); //make sure offer id is not in sorted offers list if (_head == id) { //check if offer is first offer in unsorted offers list _head = _near[id]; //set head to new first unsorted offer _near[id] = 0; //delete order from unsorted order list return true; } while (uid > 0 && uid != id) { //find offer in unsorted order list pre = uid; uid = _near[uid]; } if (uid != id) { //did not find offer id in unsorted offers list return false; } _near[pre] = _near[id]; //set previous unsorted offer to point to offer after offer id _near[id] = 0; //delete order from unsorted order list return true; } function setFeeBPS(uint256 _newFeeBPS) external auth returns (bool) { feeBPS = _newFeeBPS; return true; } function setAqueductDistributionLive(bool live) external auth returns (bool) { AqueductDistributionLive = live; return true; } function setAqueductAddress(address _Aqueduct) external auth returns (bool) { AqueductAddress = _Aqueduct; return true; } function setFeeTo(address newFeeTo) external auth returns (bool) { feeTo = newFeeTo; return true; } } interface IWETH { function deposit() external payable; function transfer(address to, uint256 value) external returns (bool); function withdraw(uint256) external; function approve(address guy, uint256 wad) external returns (bool); } interface IAqueduct { function distributeToMakerAndTaker(address maker, address taker) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: 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 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: BSD-4-Clause /* * ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting. * Author: Mikhail Vladimirov <[email protected]> */ pragma solidity =0.7.6; //<0.6.0-0||>=0.6.0 <0.7.0-0||>=0.7.0 <0.8.0-0; /** * Smart contract library of mathematical functions operating with signed * 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is * basically a simple fraction whose numerator is signed 128-bit integer and * denominator is 2^64. As long as denominator is always the same, there is no * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are * represented by int128 type holding only the numerator. */ library ABDKMath64x64 { /* * Minimum value signed 64.64-bit fixed point number may have. */ int128 private constant MIN_64x64 = -0x80000000000000000000000000000000; /* * Maximum value signed 64.64-bit fixed point number may have. */ int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; /** * Convert signed 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromInt(int256 x) internal pure returns (int128) { require(x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF); return int128(x << 64); } /** * Convert signed 64.64 fixed point number into signed 64-bit integer number * rounding down. * * @param x signed 64.64-bit fixed point number * @return signed 64-bit integer number */ function toInt(int128 x) internal pure returns (int64) { return int64(x >> 64); } /** * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromUInt(uint256 x) internal pure returns (int128) { require(x <= 0x7FFFFFFFFFFFFFFF); return int128(x << 64); } /** * Convert signed 64.64 fixed point number into unsigned 64-bit integer * number rounding down. Revert on underflow. * * @param x signed 64.64-bit fixed point number * @return unsigned 64-bit integer number */ function toUInt(int128 x) internal pure returns (uint64) { require(x >= 0); return uint64(x >> 64); } /** * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point * number rounding down. Revert on overflow. * * @param x signed 128.128-bin fixed point number * @return signed 64.64-bit fixed point number */ function from128x128(int256 x) internal pure returns (int128) { int256 result = x >> 64; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } /** * Convert signed 64.64 fixed point number into signed 128.128 fixed point * number. * * @param x signed 64.64-bit fixed point number * @return signed 128.128 fixed point number */ function to128x128(int128 x) internal pure returns (int256) { return int256(x) << 64; } /** * Calculate x + y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function add(int128 x, int128 y) internal pure returns (int128) { int256 result = int256(x) + y; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } /** * Calculate x - y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sub(int128 x, int128 y) internal pure returns (int128) { int256 result = int256(x) - y; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } /** * Calculate x * y rounding down. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function mul(int128 x, int128 y) internal pure returns (int128) { int256 result = (int256(x) * y) >> 64; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } /** * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point * number and y is signed 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y signed 256-bit integer number * @return signed 256-bit integer number */ function muli(int128 x, int256 y) internal pure returns (int256) { if (x == MIN_64x64) { require( y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF && y <= 0x1000000000000000000000000000000000000000000000000 ); return -y << 63; } else { bool negativeResult = false; if (x < 0) { x = -x; negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint256 absoluteResult = mulu(x, uint256(y)); if (negativeResult) { require( absoluteResult <= 0x8000000000000000000000000000000000000000000000000000000000000000 ); return -int256(absoluteResult); // We rely on overflow behavior here } else { require( absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ); return int256(absoluteResult); } } } /** * Calculate x * y rounding down, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y unsigned 256-bit integer number * @return unsigned 256-bit integer number */ function mulu(int128 x, uint256 y) internal pure returns (uint256) { if (y == 0) return 0; require(x >= 0); uint256 lo = (uint256(x) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64; uint256 hi = uint256(x) * (y >> 128); require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); hi <<= 64; require( hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo ); return hi + lo; } /** * Calculate x / y rounding towards zero. Revert on overflow or when y is * zero. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function div(int128 x, int128 y) internal pure returns (int128) { require(y != 0); int256 result = (int256(x) << 64) / y; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } /** * Calculate x / y rounding towards zero, where x and y are signed 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x signed 256-bit integer number * @param y signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function divi(int256 x, int256 y) internal pure returns (int128) { require(y != 0); bool negativeResult = false; if (x < 0) { x = -x; // We rely on overflow behavior here negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint128 absoluteResult = divuu(uint256(x), uint256(y)); if (negativeResult) { require(absoluteResult <= 0x80000000000000000000000000000000); return -int128(absoluteResult); // We rely on overflow behavior here } else { require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int128(absoluteResult); // We rely on overflow behavior here } } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function divu(uint256 x, uint256 y) internal pure returns (int128) { require(y != 0); uint128 result = divuu(x, y); require(result <= uint128(MAX_64x64)); return int128(result); } /** * Calculate -x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function neg(int128 x) internal pure returns (int128) { require(x != MIN_64x64); return -x; } /** * Calculate |x|. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function abs(int128 x) internal pure returns (int128) { require(x != MIN_64x64); return x < 0 ? -x : x; } /** * Calculate 1 / x rounding towards zero. Revert on overflow or when x is * zero. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function inv(int128 x) internal pure returns (int128) { require(x != 0); int256 result = int256(0x100000000000000000000000000000000) / x; require(result >= MIN_64x64 && result <= MAX_64x64); return int128(result); } /** * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function avg(int128 x, int128 y) internal pure returns (int128) { return int128((int256(x) + int256(y)) >> 1); } /** * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down. * Revert on overflow or in case x * y is negative. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function gavg(int128 x, int128 y) internal pure returns (int128) { int256 m = int256(x) * int256(y); require(m >= 0); require( m < 0x4000000000000000000000000000000000000000000000000000000000000000 ); return int128(sqrtu(uint256(m))); } /** * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y uint256 value * @return signed 64.64-bit fixed point number */ function pow(int128 x, uint256 y) internal pure returns (int128) { uint256 absoluteResult; bool negativeResult = false; if (x >= 0) { absoluteResult = powu(uint256(x) << 63, y); } else { // We rely on overflow behavior here absoluteResult = powu(uint256(uint128(-x)) << 63, y); negativeResult = y & 1 > 0; } absoluteResult >>= 63; if (negativeResult) { require(absoluteResult <= 0x80000000000000000000000000000000); return -int128(absoluteResult); // We rely on overflow behavior here } else { require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int128(absoluteResult); // We rely on overflow behavior here } } /** * Calculate sqrt (x) rounding down. Revert if x < 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sqrt(int128 x) internal pure returns (int128) { require(x >= 0); return int128(sqrtu(uint256(x) << 64)); } /** * Calculate binary logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function log_2(int128 x) internal pure returns (int128) { require(x > 0); int256 msb = 0; int256 xc = x; if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; } if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore int256 result = (msb - 64) << 64; uint256 ux = uint256(x) << uint256(127 - msb); for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) { ux *= ux; uint256 b = ux >> 255; ux >>= 127 + b; result += bit * int256(b); } return int128(result); } /** * Calculate natural logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function ln(int128 x) internal pure returns (int128) { require(x > 0); return int128( (uint256(log_2(x)) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF) >> 128 ); } /** * Calculate binary exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp_2(int128 x) internal pure returns (int128) { require(x < 0x400000000000000000); // Overflow if (x < -0x400000000000000000) return 0; // Underflow uint256 result = 0x80000000000000000000000000000000; if (x & 0x8000000000000000 > 0) result = (result * 0x16A09E667F3BCC908B2FB1366EA957D3E) >> 128; if (x & 0x4000000000000000 > 0) result = (result * 0x1306FE0A31B7152DE8D5A46305C85EDEC) >> 128; if (x & 0x2000000000000000 > 0) result = (result * 0x1172B83C7D517ADCDF7C8C50EB14A791F) >> 128; if (x & 0x1000000000000000 > 0) result = (result * 0x10B5586CF9890F6298B92B71842A98363) >> 128; if (x & 0x800000000000000 > 0) result = (result * 0x1059B0D31585743AE7C548EB68CA417FD) >> 128; if (x & 0x400000000000000 > 0) result = (result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8) >> 128; if (x & 0x200000000000000 > 0) result = (result * 0x10163DA9FB33356D84A66AE336DCDFA3F) >> 128; if (x & 0x100000000000000 > 0) result = (result * 0x100B1AFA5ABCBED6129AB13EC11DC9543) >> 128; if (x & 0x80000000000000 > 0) result = (result * 0x10058C86DA1C09EA1FF19D294CF2F679B) >> 128; if (x & 0x40000000000000 > 0) result = (result * 0x1002C605E2E8CEC506D21BFC89A23A00F) >> 128; if (x & 0x20000000000000 > 0) result = (result * 0x100162F3904051FA128BCA9C55C31E5DF) >> 128; if (x & 0x10000000000000 > 0) result = (result * 0x1000B175EFFDC76BA38E31671CA939725) >> 128; if (x & 0x8000000000000 > 0) result = (result * 0x100058BA01FB9F96D6CACD4B180917C3D) >> 128; if (x & 0x4000000000000 > 0) result = (result * 0x10002C5CC37DA9491D0985C348C68E7B3) >> 128; if (x & 0x2000000000000 > 0) result = (result * 0x1000162E525EE054754457D5995292026) >> 128; if (x & 0x1000000000000 > 0) result = (result * 0x10000B17255775C040618BF4A4ADE83FC) >> 128; if (x & 0x800000000000 > 0) result = (result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB) >> 128; if (x & 0x400000000000 > 0) result = (result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9) >> 128; if (x & 0x200000000000 > 0) result = (result * 0x10000162E43F4F831060E02D839A9D16D) >> 128; if (x & 0x100000000000 > 0) result = (result * 0x100000B1721BCFC99D9F890EA06911763) >> 128; if (x & 0x80000000000 > 0) result = (result * 0x10000058B90CF1E6D97F9CA14DBCC1628) >> 128; if (x & 0x40000000000 > 0) result = (result * 0x1000002C5C863B73F016468F6BAC5CA2B) >> 128; if (x & 0x20000000000 > 0) result = (result * 0x100000162E430E5A18F6119E3C02282A5) >> 128; if (x & 0x10000000000 > 0) result = (result * 0x1000000B1721835514B86E6D96EFD1BFE) >> 128; if (x & 0x8000000000 > 0) result = (result * 0x100000058B90C0B48C6BE5DF846C5B2EF) >> 128; if (x & 0x4000000000 > 0) result = (result * 0x10000002C5C8601CC6B9E94213C72737A) >> 128; if (x & 0x2000000000 > 0) result = (result * 0x1000000162E42FFF037DF38AA2B219F06) >> 128; if (x & 0x1000000000 > 0) result = (result * 0x10000000B17217FBA9C739AA5819F44F9) >> 128; if (x & 0x800000000 > 0) result = (result * 0x1000000058B90BFCDEE5ACD3C1CEDC823) >> 128; if (x & 0x400000000 > 0) result = (result * 0x100000002C5C85FE31F35A6A30DA1BE50) >> 128; if (x & 0x200000000 > 0) result = (result * 0x10000000162E42FF0999CE3541B9FFFCF) >> 128; if (x & 0x100000000 > 0) result = (result * 0x100000000B17217F80F4EF5AADDA45554) >> 128; if (x & 0x80000000 > 0) result = (result * 0x10000000058B90BFBF8479BD5A81B51AD) >> 128; if (x & 0x40000000 > 0) result = (result * 0x1000000002C5C85FDF84BD62AE30A74CC) >> 128; if (x & 0x20000000 > 0) result = (result * 0x100000000162E42FEFB2FED257559BDAA) >> 128; if (x & 0x10000000 > 0) result = (result * 0x1000000000B17217F7D5A7716BBA4A9AE) >> 128; if (x & 0x8000000 > 0) result = (result * 0x100000000058B90BFBE9DDBAC5E109CCE) >> 128; if (x & 0x4000000 > 0) result = (result * 0x10000000002C5C85FDF4B15DE6F17EB0D) >> 128; if (x & 0x2000000 > 0) result = (result * 0x1000000000162E42FEFA494F1478FDE05) >> 128; if (x & 0x1000000 > 0) result = (result * 0x10000000000B17217F7D20CF927C8E94C) >> 128; if (x & 0x800000 > 0) result = (result * 0x1000000000058B90BFBE8F71CB4E4B33D) >> 128; if (x & 0x400000 > 0) result = (result * 0x100000000002C5C85FDF477B662B26945) >> 128; if (x & 0x200000 > 0) result = (result * 0x10000000000162E42FEFA3AE53369388C) >> 128; if (x & 0x100000 > 0) result = (result * 0x100000000000B17217F7D1D351A389D40) >> 128; if (x & 0x80000 > 0) result = (result * 0x10000000000058B90BFBE8E8B2D3D4EDE) >> 128; if (x & 0x40000 > 0) result = (result * 0x1000000000002C5C85FDF4741BEA6E77E) >> 128; if (x & 0x20000 > 0) result = (result * 0x100000000000162E42FEFA39FE95583C2) >> 128; if (x & 0x10000 > 0) result = (result * 0x1000000000000B17217F7D1CFB72B45E1) >> 128; if (x & 0x8000 > 0) result = (result * 0x100000000000058B90BFBE8E7CC35C3F0) >> 128; if (x & 0x4000 > 0) result = (result * 0x10000000000002C5C85FDF473E242EA38) >> 128; if (x & 0x2000 > 0) result = (result * 0x1000000000000162E42FEFA39F02B772C) >> 128; if (x & 0x1000 > 0) result = (result * 0x10000000000000B17217F7D1CF7D83C1A) >> 128; if (x & 0x800 > 0) result = (result * 0x1000000000000058B90BFBE8E7BDCBE2E) >> 128; if (x & 0x400 > 0) result = (result * 0x100000000000002C5C85FDF473DEA871F) >> 128; if (x & 0x200 > 0) result = (result * 0x10000000000000162E42FEFA39EF44D91) >> 128; if (x & 0x100 > 0) result = (result * 0x100000000000000B17217F7D1CF79E949) >> 128; if (x & 0x80 > 0) result = (result * 0x10000000000000058B90BFBE8E7BCE544) >> 128; if (x & 0x40 > 0) result = (result * 0x1000000000000002C5C85FDF473DE6ECA) >> 128; if (x & 0x20 > 0) result = (result * 0x100000000000000162E42FEFA39EF366F) >> 128; if (x & 0x10 > 0) result = (result * 0x1000000000000000B17217F7D1CF79AFA) >> 128; if (x & 0x8 > 0) result = (result * 0x100000000000000058B90BFBE8E7BCD6D) >> 128; if (x & 0x4 > 0) result = (result * 0x10000000000000002C5C85FDF473DE6B2) >> 128; if (x & 0x2 > 0) result = (result * 0x1000000000000000162E42FEFA39EF358) >> 128; if (x & 0x1 > 0) result = (result * 0x10000000000000000B17217F7D1CF79AB) >> 128; result >>= uint256(63 - (x >> 64)); require(result <= uint256(MAX_64x64)); return int128(result); } /** * Calculate natural exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp(int128 x) internal pure returns (int128) { require(x < 0x400000000000000000); // Overflow if (x < -0x400000000000000000) return 0; // Underflow return exp_2( int128((int256(x) * 0x171547652B82FE1777D0FFDA0D23A7D12) >> 128) ); } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return unsigned 64.64-bit fixed point number */ function divuu(uint256 x, uint256 y) private pure returns (uint128) { require(y != 0); uint256 result; if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) result = (x << 64) / y; else { uint256 msb = 192; uint256 xc = x >> 192; if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore result = (x << (255 - msb)) / (((y - 1) >> (msb - 191)) + 1); require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); uint256 hi = result * (y >> 128); uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); uint256 xh = x >> 192; uint256 xl = x << 64; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here lo = hi << 128; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here assert(xh == hi >> 128); result += xl / y; } require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return uint128(result); } /** * Calculate x^y assuming 0^0 is 1, where x is unsigned 129.127 fixed point * number and y is unsigned 256-bit integer number. Revert on overflow. * * @param x unsigned 129.127-bit fixed point number * @param y uint256 value * @return unsigned 129.127-bit fixed point number */ function powu(uint256 x, uint256 y) private pure returns (uint256) { if (y == 0) return 0x80000000000000000000000000000000; else if (x == 0) return 0; else { int256 msb = 0; uint256 xc = x; if (xc >= 0x100000000000000000000000000000000) { xc >>= 128; msb += 128; } if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; } if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore int256 xe = msb - 127; if (xe > 0) x >>= uint256(xe); else x <<= uint256(-xe); uint256 result = 0x80000000000000000000000000000000; int256 re = 0; while (y > 0) { if (y & 1 > 0) { result = result * x; y -= 1; re += xe; if ( result >= 0x8000000000000000000000000000000000000000000000000000000000000000 ) { result >>= 128; re += 1; } else result >>= 127; if (re < -127) return 0; // Underflow require(re < 128); // Overflow } else { x = x * x; y >>= 1; xe <<= 1; if ( x >= 0x8000000000000000000000000000000000000000000000000000000000000000 ) { x >>= 128; xe += 1; } else x >>= 127; if (xe < -127) return 0; // Underflow require(xe < 128); // Overflow } } if (re > 0) result <<= uint256(re); else if (re < 0) result >>= uint256(-re); return result; } } /** * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer * number. * * @param x unsigned 256-bit integer number * @return unsigned 128-bit integer number */ function sqrtu(uint256 x) private pure returns (uint128) { if (x == 0) return 0; else { uint256 xx = x; uint256 r = 1; if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } if (xx >= 0x10000) { xx >>= 16; r <<= 8; } if (xx >= 0x100) { xx >>= 8; r <<= 4; } if (xx >= 0x10) { xx >>= 4; r <<= 2; } if (xx >= 0x8) { r <<= 1; } r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; // Seven iterations should be enough uint256 r1 = x / r; return uint128(r < r1 ? r : r1); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../../utils/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name_, string memory symbol_, uint8 blazeIt) public { _name = name_; _symbol = symbol_; _setupDecimals(blazeIt); } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal virtual { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
{ "optimizer": { "enabled": true, "runs": 1 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_rM","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"","type":"string"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"LogNote","type":"event"},{"inputs":[],"name":"RubiconMarketAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"toApprove","type":"address"}],"name":"approveAssetOnMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"getBestOfferAndInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"contract ERC20","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"uint256","name":"buy_amt_min","type":"uint256"},{"internalType":"address[]","name":"route","type":"address[]"},{"internalType":"uint256","name":"expectedMarketFeeBPS","type":"uint256"}],"name":"getExpectedSwapFill","outputs":[{"internalType":"uint256","name":"fill_amt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"uint256","name":"buy_amt_min","type":"uint256"},{"internalType":"address[]","name":"route","type":"address[]"},{"internalType":"uint256","name":"expectedMarketFeeBPS","type":"uint256"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001c576000806200001962000097565b50505b506040516200130138038062001301833981810160405260208110156200004d576000806200004a62000097565b50505b8101908080519250829150600090506001816200006962000104565b816001600160a01b0302191690836001600160a01b03160217906200008d62000166565b50505050620001b5565b632a2a7adb598160e01b8152600481016020815285602082015260005b86811015620000d1578086015182820160400152602001620000b4565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b6040811015620001615760008282015260200162000148565b505050565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b60008152602062000148565b61113c80620001c56000396000f3fe608060405234801561001957600080610016610e0c565b50505b50600436106100605760003560e01c806343be86991461006e5780636074c2401461009f57806360f71b241461011a578063c24e61171461013e578063f10f1f58146101ee575b60008061006b610e0c565b50505b61009d6004803603602081101561008d5760008061008a610e0c565b50505b50356001600160a01b031661028c565b005b6100d6600480360360408110156100be576000806100bb610e0c565b50505b506001600160a01b0381358116916020013516610365565b60405180868152602001858152602001846001600160a01b03168152602001838152602001826001600160a01b031681526020019550505050505060405180910390f35b61012261053e565b6040516001600160a01b03909116815260200160405180910390f35b6101dc6004803603608081101561015d5760008061015a610e0c565b50505b813591602081013591810190606081016040820135600160201b81111561018c57600080610189610e0c565b50505b8201836020820111156101a7576000806101a4610e0c565b50505b803590602001918460208302840111600160201b831117156101d1576000806101ce610e0c565b50505b91935091503561055c565b60405190815260200160405180910390f35b61009d6004803603608081101561020d5760008061020a610e0c565b50505b813591602081013591810190606081016040820135600160201b81111561023c57600080610239610e0c565b50505b82018360208201111561025757600080610254610e0c565b50505b803590602001918460208302840111600160201b831117156102815760008061027e610e0c565b50505b91935091503561073b565b806001600160a01b031663095ea7b36000806102a6610e77565b906101000a90046001600160a01b03166000196040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087806102fa610ed7565b15801561030f5760008061030c610e0c565b50505b505a610319610f23565b505050505050158015610339573d6000803e3d6000610336610e0c565b50505b505050506040513d602081101561035857600080610355610e0c565b50505b8101908080515050505050565b600080600080600080600080610379610e77565b906101000a90046001600160a01b031690506000816001600160a01b0316630374fc6f8a8a6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160206040518083038186806103df610ed7565b1580156103f4576000806103f1610e0c565b50505b505a6103fe61100e565b505050505015801561041d573d6000803e3d600061041a610e0c565b50505b505050506040513d602081101561043c57600080610439610e0c565b50505b810190808051935060009250829150819050806001600160a01b038616634579268a866040516001600160e01b031960e084901b16815260048101919091526024016080604051808303818680610491610ed7565b1580156104a6576000806104a3610e0c565b50505b505a6104b061100e565b50505050501580156104cf573d6000803e3d60006104cc610e0c565b50505b505050506040513d60808110156104ee576000806104eb610e0c565b50505b8101908080519291906020018051929190602001805192919060200180519060200190929190505050935093509350935084848484849a509a509a509a509a505050505050509295509295909350565b600080610549610e77565b906101000a90046001600160a01b031681565b60008060008061056a610e77565b906101000a90046001600160a01b031690506000805b60001986018110156106d85760008088888481811061059b57fe5b905060200201356001600160a01b03168989856001018181106105ba57fe5b905060200201356001600160a01b0316915091506000836000146105fd576105f86105f16127106105eb888c610c77565b90610ce2565b8690610d4e565b6105ff565b8b5b90506000866001600160a01b031663144a27528486856040516001600160e01b031960e086901b1681526001600160a01b03938416600482015291909216602482015260448101919091526064016020604051808303818680610660610ed7565b15801561067557600080610672610e0c565b50505b505a61067f61100e565b505050505015801561069e573d6000803e3d600061069b610e0c565b50505b505050506040513d60208110156106bd576000806106ba610e0c565b50505b81019080805198505060019096019550610580945050505050565b50868110156107305760405162461bcd60e51b81526020600482015260176024820152763234b2373a1031b632b0b910313abcafb0b6ba2fb6b4b760491b60448201526064016040518091039061072d610e0c565b50505b979650505050505050565b8282600081811061074857fe5b905060200201356001600160a01b03166001600160a01b03166323b872dd5a61076f6110d4565b5a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b60408110156107c5576000828201526020016107ae565b506107e491506107dd90506127106105eb8c89610c77565b8a90610db3565b6040516001600160e01b031960e086901b1681526001600160a01b039384166004820152919092166024820152604481019190915260640160206040518083038160008780610831610ed7565b15801561084657600080610843610e0c565b50505b505a610850610f23565b505050505050158015610870573d6000803e3d600061086d610e0c565b50505b505050506040513d602081101561088f5760008061088c610e0c565b50505b81019080805150600092508291508190506108a8610e77565b906101000a90046001600160a01b031690506000805b6000198501811015610b35576000808787848181106108d957fe5b905060200201356001600160a01b03168888856001018181106108f857fe5b905060200201356001600160a01b03169150915060008360001461092e576109296105f16127106105eb888b610c77565b610930565b8a5b9050826001600160a01b031663dd62ed3e5a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b604081101561099757600082820152602001610980565b505050886040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160206040518083038186806109dc610ed7565b1580156109f1576000806109ee610e0c565b50505b505a6109fb61100e565b5050505050158015610a1a573d6000803e3d6000610a17610e0c565b50505b505050506040513d6020811015610a3957600080610a36610e0c565b50505b81019080805115159250610a5391505057610a538361028c565b6000866001600160a01b0316630621b4f685848660006040516001600160e01b031960e087901b1681526001600160a01b039485166004820152602481019390935292166044820152606481019190915260840160206040518083038160008780610abc610ed7565b158015610ad157600080610ace610e0c565b50505b505a610adb610f23565b505050505050158015610afb573d6000803e3d6000610af8610e0c565b50505b505050506040513d6020811015610b1a57600080610b17610e0c565b50505b810190808051985050600190960195506108be945050505050565b5085811015610b8d5760405162461bcd60e51b81526020600482015260176024820152763234b2373a1031b632b0b910313abcafb0b6ba2fb6b4b760491b604482015260640160405180910390610b8a610e0c565b50505b84846000198101818110610b9d57fe5b905060200201356001600160a01b03166001600160a01b031663a9059cbb5a610bc46110d4565b836040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160206040518083038160008780610c06610ed7565b158015610c1b57600080610c18610e0c565b50505b505a610c25610f23565b505050505050158015610c45573d6000803e3d6000610c42610e0c565b50505b505050506040513d6020811015610c6457600080610c61610e0c565b50505b8101908080515050505050505050505050565b600082610c8657506000610cdc565b82820282848281610c9357fe5b0414610cd95760405162461bcd60e51b815260040180806020018281038252602181526020018061111b6021913960400191505060405180910390610cd6610e0c565b50505b90505b92915050565b6000808211610d3d5760405162461bcd60e51b815260206004820152601a602482015279536166654d6174683a206469766973696f6e206279207a65726f60301b604482015260640160405180910390610d3a610e0c565b50505b818381610d4657fe5b049392505050565b600082821115610dad5760405162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015260640160405180910390610daa610e0c565b50505b50900390565b600082820183811015610cd95760405162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604482015260640160405180910390610cd65b632a2a7adb598160e01b8152600481016020815285602082015260005b86811015610e44578086015182820160400152602001610e29565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b6040811015610ed257600082820152602001610ebb565b505050565b638435035b598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b80516000825293506020610ebb565b6385979f76598160e01b8152610f54565b8080831115610cdc575090919050565b8080831015610cdc575090919050565b836004820152846024820152606060448201528760648201526084810160005b89811015610f8c578089015182820152602001610f74565b506060828a60a40184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b815160408301513d6000853e8c8c82606087013350600060045af15059610fe18e3d610f44565b8d01610fed8187610f34565b5b828110156110025760008152602001610fee565b50929d50505050505050565b638540661f598160e01b8152836004820152846024820152606060448201528660648201526084810160005b8881101561105257808801518282015260200161103a565b506060828960a40184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b815160408301513d6000853e8b8b82606087013350600060045af150596110a78d3d610f44565b8c016110b38187610f34565b5b828110156110c857600081526020016110b4565b50929c50505050505050565b6373509064598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b80516000825293506020610ebb56fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f770000000000000000000000007a512d3609211e719737e82c7bb7271ec05da70d
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007a512d3609211e719737e82c7bb7271ec05da70d
-----Decoded View---------------
Arg [0] : _rM (address): 0x7a512d3609211e719737e82c7bb7271ec05da70d
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000007a512d3609211e719737e82c7bb7271ec05da70d
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.