Transaction Hash:
Block:
8987478 at Nov-23-2019 04:46:38 PM +UTC
Transaction Fee:
0.00134653125 ETH
$2.66
Gas Used:
215,445 Gas / 6.25 Gwei
Emitted Events:
| 78 |
DSToken.Transfer( from=MatchingMarket, to=[Receiver] 0x6e85448d1e6ea2b68ed87ece0cd764d1c88705fd, value=3500000000000000000 )
|
| 79 |
MatchingMarket.LogItemUpdate( id=608783 )
|
| 80 |
MatchingMarket.LogKill( id=0000000000000000000000000000000000000000000000000000000000094A0F, pair=7509DEDA9E17580C94915865C0C0C56190CC733E6C835A6CA2E497C1E4A50A5D, maker=[Receiver] 0x6e85448d1e6ea2b68ed87ece0cd764d1c88705fd, pay_gem=DSToken, buy_gem=DSToken, pay_amt=3500000000000000000, buy_amt=1952356794326471746500, timestamp=1574527598 )
|
| 81 |
DSToken.Transfer( from=[Receiver] 0x6e85448d1e6ea2b68ed87ece0cd764d1c88705fd, to=MatchingMarket, value=3500000000000000000 )
|
| 82 |
MatchingMarket.LogItemUpdate( id=608787 )
|
| 83 |
MatchingMarket.LogMake( id=0000000000000000000000000000000000000000000000000000000000094A13, pair=7509DEDA9E17580C94915865C0C0C56190CC733E6C835A6CA2E497C1E4A50A5D, maker=[Receiver] 0x6e85448d1e6ea2b68ed87ece0cd764d1c88705fd, pay_gem=DSToken, buy_gem=DSToken, pay_amt=3500000000000000000, buy_amt=1952356759326472096500, timestamp=1574527598 )
|
| 84 |
MatchingMarket.LogSortedOffer( id=608787 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x00000000...438691c04 | |||||
| 0x27D4b653...b929F14fa |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 0
| |||
| 0x2D70f303...F6eb39bB1 |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 0
| |||
| 0x39755357...a409AE24e | (Eth2Dai: Old Contract) | ||||
| 0x47F2e5DC...f367e3773 |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 0
| |||
| 0x6696487A...F2Eb4BBfC |
0.987379784682001003 Eth
Nonce: 6511
|
0.986033253432001003 Eth
Nonce: 6512
| 0.00134653125 | ||
| 0x6E85448D...1c88705fd | |||||
| 0x913Dc9a0...349B07ce5 |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 0
| |||
| 0xb6a17ca6...D30c16795 |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 0
| |||
| 0xcdd7Ee0f...A12f44bBB |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 0
| |||
| 0xDa24ED42...edb65b13A |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 0
| |||
| 0xDD0e9040...9D56fB146 |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 0
| |||
|
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 441.551508615083035931 Eth | 441.552855146333035931 Eth | 0.00134653125 |
Execution Trace
0x6e85448d1e6ea2b68ed87ece0cd764d1c88705fd.3bca2f45( )
-
MatchingMarket.getBestOffer( sell_gem=0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2, buy_gem=0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359 ) => ( 608785 ) -
MatchingMarket.isActive( id=608783 ) => ( active=True ) -
DSToken.balanceOf( src=0x6E85448D1E6eA2B68ed87eCE0cd764D1c88705fd ) => ( 7016935319638947616 )
MatchingMarket.offer( pay_amt=3500000000000000000, pay_gem=0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2, buy_amt=1952356759326472096500, buy_gem=0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359, pos=608785 ) => ( 608787 )-
DSToken.transferFrom( src=0x6E85448D1E6eA2B68ed87eCE0cd764D1c88705fd, dst=0x39755357759cE0d7f32dC8dC45414CCa409AE24e, wad=3500000000000000000 ) => ( True )
-
-
DSToken.balanceOf( src=0x6E85448D1E6eA2B68ed87eCE0cd764D1c88705fd ) => ( 2769531860936347029 )
GasToken2.freeFromUpTo( from=0x15Fda64fCdbcA27a60Aa8c6ca882Aa3e1DE4Ea41, value=8 ) => ( freed=8 )
0x27d4b653e871d3a0376da52747902e6b929f14fa.CALL( )-
GasToken2.SELFDESTRUCT( )
-
0x913dc9a02712ba23769eabf9c496003349b07ce5.CALL( )-
GasToken2.SELFDESTRUCT( )
-
0x2d70f3038755025861e19f3b623745ff6eb39bb1.CALL( )-
GasToken2.SELFDESTRUCT( )
-
0xdd0e904077bd0d37829f365b31a88b69d56fb146.CALL( )-
GasToken2.SELFDESTRUCT( )
-
0x47f2e5dc5c34aac0112ce97dcb84906f367e3773.CALL( )-
GasToken2.SELFDESTRUCT( )
-
0xcdd7ee0ff976d5f659cb5dc4be304a8a12f44bbb.CALL( )-
GasToken2.SELFDESTRUCT( )
-
0xda24ed4296d40171b512302b9c26899edb65b13a.CALL( )-
GasToken2.SELFDESTRUCT( )
-
0xb6a17ca6d51bc8243eb722696f50554d30c16795.CALL( )-
GasToken2.SELFDESTRUCT( )
-
File 1 of 4: MatchingMarket
File 2 of 4: DSToken
File 3 of 4: DSToken
File 4 of 4: GasToken2
/// matching_market.sol
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.4.18;
/// expiring_market.sol
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.4.18;
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.4.13;
contract DSAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
contract DSAuth is DSAuthEvents {
DSAuthority public authority;
address public owner;
function DSAuth() public {
owner = msg.sender;
LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
LogSetOwner(owner);
}
function setAuthority(DSAuthority authority_)
public
auth
{
authority = authority_;
LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == address(this)) {
return true;
} else if (src == owner) {
return true;
} else if (authority == DSAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
/// simple_market.sol
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.4.18;
/// math.sol -- mixin for inline numerical wizardry
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.4.13;
contract DSMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x);
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x);
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x);
}
function min(uint x, uint y) internal pure returns (uint z) {
return x <= y ? x : y;
}
function max(uint x, uint y) internal pure returns (uint z) {
return x >= y ? x : y;
}
function imin(int x, int y) internal pure returns (int z) {
return x <= y ? x : y;
}
function imax(int x, int y) internal pure returns (int z) {
return x >= y ? x : y;
}
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
function wmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, WAD), y / 2) / y;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, RAY), y / 2) / y;
}
// This famous algorithm is called "exponentiation by squaring"
// and calculates x^n with x as fixed-point and n as regular unsigned.
//
// It's O(log n), instead of O(n) for naive repeated multiplication.
//
// These facts are why it works:
//
// If n is even, then x^n = (x^2)^(n/2).
// If n is odd, then x^n = x * x^(n-1),
// and applying the equation for even x gives
// x^n = x * (x^2)^((n-1) / 2).
//
// Also, EVM division is flooring and
// floor[(n-1) / 2] = floor[n / 2].
//
function rpow(uint x, uint n) internal pure returns (uint z) {
z = n % 2 != 0 ? x : RAY;
for (n /= 2; n != 0; n /= 2) {
x = rmul(x, x);
if (n % 2 != 0) {
z = rmul(z, x);
}
}
}
}
/// erc20.sol -- API for the ERC20 token standard
// See <https://github.com/ethereum/EIPs/issues/20>.
// This file likely does not meet the threshold of originality
// required for copyright to apply. As a result, this is free and
// unencumbered software belonging to the public domain.
pragma solidity ^0.4.8;
contract ERC20Events {
event Approval(address indexed src, address indexed guy, uint wad);
event Transfer(address indexed src, address indexed dst, uint wad);
}
contract ERC20 is ERC20Events {
function totalSupply() public view returns (uint);
function balanceOf(address guy) public view returns (uint);
function allowance(address src, address guy) public view returns (uint);
function approve(address guy, uint wad) public returns (bool);
function transfer(address dst, uint wad) public returns (bool);
function transferFrom(
address src, address dst, uint wad
) public returns (bool);
}
contract EventfulMarket {
event LogItemUpdate(uint id);
event LogTrade(uint pay_amt, address indexed pay_gem,
uint 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
);
}
contract SimpleMarket is EventfulMarket, DSMath {
uint public last_offer_id;
mapping (uint => OfferInfo) public offers;
bool locked;
struct OfferInfo {
uint pay_amt;
ERC20 pay_gem;
uint buy_amt;
ERC20 buy_gem;
address owner;
uint64 timestamp;
}
modifier can_buy(uint id) {
require(isActive(id));
_;
}
modifier can_cancel(uint id) {
require(isActive(id));
require(getOwner(id) == msg.sender);
_;
}
modifier can_offer {
_;
}
modifier synchronized {
require(!locked);
locked = true;
_;
locked = false;
}
function isActive(uint id) public constant returns (bool active) {
return offers[id].timestamp > 0;
}
function getOwner(uint id) public constant returns (address owner) {
return offers[id].owner;
}
function getOffer(uint id) public constant returns (uint, ERC20, uint, ERC20) {
var offer = offers[id];
return (offer.pay_amt, offer.pay_gem,
offer.buy_amt, offer.buy_gem);
}
// ---- Public entrypoints ---- //
function bump(bytes32 id_)
public
can_buy(uint256(id_))
{
var id = uint256(id_);
LogBump(
id_,
keccak256(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
);
}
// Accept given `quantity` of an offer. Transfers funds from caller to
// offer maker, and from market to caller.
function buy(uint id, uint quantity)
public
can_buy(id)
synchronized
returns (bool)
{
OfferInfo memory offer = offers[id];
uint spend = mul(quantity, offer.buy_amt) / offer.pay_amt;
require(uint128(spend) == spend);
require(uint128(quantity) == quantity);
// For backwards semantic compatibility.
if (quantity == 0 || spend == 0 ||
quantity > offer.pay_amt || spend > offer.buy_amt)
{
return false;
}
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) );
require( offer.pay_gem.transfer(msg.sender, quantity) );
LogItemUpdate(id);
LogTake(
bytes32(id),
keccak256(offer.pay_gem, offer.buy_gem),
offer.owner,
offer.pay_gem,
offer.buy_gem,
msg.sender,
uint128(quantity),
uint128(spend),
uint64(now)
);
LogTrade(quantity, offer.pay_gem, spend, offer.buy_gem);
if (offers[id].pay_amt == 0) {
delete offers[id];
}
return true;
}
// Cancel an offer. Refunds offer maker.
function cancel(uint id)
public
can_cancel(id)
synchronized
returns (bool success)
{
// read-only offer. Modify an offer by directly accessing offers[id]
OfferInfo memory offer = offers[id];
delete offers[id];
require( offer.pay_gem.transfer(offer.owner, offer.pay_amt) );
LogItemUpdate(id);
LogKill(
bytes32(id),
keccak256(offer.pay_gem, offer.buy_gem),
offer.owner,
offer.pay_gem,
offer.buy_gem,
uint128(offer.pay_amt),
uint128(offer.buy_amt),
uint64(now)
);
success = true;
}
function kill(bytes32 id)
public
{
require(cancel(uint256(id)));
}
function make(
ERC20 pay_gem,
ERC20 buy_gem,
uint128 pay_amt,
uint128 buy_amt
)
public
returns (bytes32 id)
{
return bytes32(offer(pay_amt, pay_gem, buy_amt, buy_gem));
}
// Make a new offer. Takes funds from the caller into market escrow.
function offer(uint pay_amt, ERC20 pay_gem, uint buy_amt, ERC20 buy_gem)
public
can_offer
synchronized
returns (uint 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(now);
id = _next_id();
offers[id] = info;
require( pay_gem.transferFrom(msg.sender, this, pay_amt) );
LogItemUpdate(id);
LogMake(
bytes32(id),
keccak256(pay_gem, buy_gem),
msg.sender,
pay_gem,
buy_gem,
uint128(pay_amt),
uint128(buy_amt),
uint64(now)
);
}
function take(bytes32 id, uint128 maxTakeAmount)
public
{
require(buy(uint256(id), maxTakeAmount));
}
function _next_id()
internal
returns (uint)
{
last_offer_id++; return last_offer_id;
}
}
// Simple Market with a market lifetime. When the close_time has been reached,
// offers can only be cancelled (offer and buy will throw).
contract ExpiringMarket is DSAuth, SimpleMarket {
uint64 public close_time;
bool public stopped;
// after close_time has been reached, no new offers are allowed
modifier can_offer {
require(!isClosed());
_;
}
// after close, no new buys are allowed
modifier can_buy(uint id) {
require(isActive(id));
require(!isClosed());
_;
}
// after close, anyone can cancel an offer
modifier can_cancel(uint id) {
require(isActive(id));
require((msg.sender == getOwner(id)) || isClosed());
_;
}
function ExpiringMarket(uint64 _close_time)
public
{
close_time = _close_time;
}
function isClosed() public constant returns (bool closed) {
return stopped || getTime() > close_time;
}
function getTime() public constant returns (uint64) {
return uint64(now);
}
function stop() public auth {
stopped = true;
}
}
/// note.sol -- the `note' modifier, for logging calls as events
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.4.13;
contract DSNote {
event LogNote(
bytes4 indexed sig,
address indexed guy,
bytes32 indexed foo,
bytes32 indexed bar,
uint wad,
bytes fax
) anonymous;
modifier note {
bytes32 foo;
bytes32 bar;
assembly {
foo := calldataload(4)
bar := calldataload(36)
}
LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
_;
}
}
contract MatchingEvents {
event LogBuyEnabled(bool isEnabled);
event LogMinSell(address pay_gem, uint min_amount);
event LogMatchingEnabled(bool isEnabled);
event LogUnsortedOffer(uint id);
event LogSortedOffer(uint id);
event LogInsert(address keeper, uint id);
event LogDelete(address keeper, uint id);
}
contract MatchingMarket is MatchingEvents, ExpiringMarket, DSNote {
bool public buyEnabled = true; //buy enabled
bool public matchingEnabled = true; //true: enable matching,
//false: revert to expiring market
struct sortInfo {
uint next; //points to id of next higher offer
uint prev; //points to id of previous lower offer
uint delb; //the blocknumber where this entry was marked for delete
}
mapping(uint => sortInfo) public _rank; //doubly linked lists of sorted offer ids
mapping(address => mapping(address => uint)) public _best; //id of the highest offer for a token pair
mapping(address => mapping(address => uint)) public _span; //number of offers stored for token pair in sorted orderbook
mapping(address => uint) public _dust; //minimum sell amount for a token to avoid dust offers
mapping(uint => uint) public _near; //next unsorted offer id
uint _head; //first unsorted offer id
uint public dustId; // id of the latest offer marked as dust
function MatchingMarket(uint64 close_time) ExpiringMarket(close_time) public {
}
// After close, anyone can cancel an offer
modifier can_cancel(uint id) {
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
returns (bytes32)
{
return bytes32(offer(pay_amt, pay_gem, buy_amt, buy_gem));
}
function take(bytes32 id, uint128 maxTakeAmount) public {
require(buy(uint256(id), maxTakeAmount));
}
function kill(bytes32 id) public {
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(
uint pay_amt, //maker (ask) sell how much
ERC20 pay_gem, //maker (ask) sell which token
uint buy_amt, //taker (ask) buy how much
ERC20 buy_gem //taker (ask) buy which token
)
public
returns (uint)
{
require(!locked, "Reentrancy attempt");
var 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(
uint pay_amt, //maker (ask) sell how much
ERC20 pay_gem, //maker (ask) sell which token
uint buy_amt, //maker (ask) buy how much
ERC20 buy_gem, //maker (ask) buy which token
uint pos //position to insert offer, 0 should be used if unknown
)
public
can_offer
returns (uint)
{
return offer(pay_amt, pay_gem, buy_amt, buy_gem, pos, true);
}
function offer(
uint pay_amt, //maker (ask) sell how much
ERC20 pay_gem, //maker (ask) sell which token
uint buy_amt, //maker (ask) buy how much
ERC20 buy_gem, //maker (ask) buy which token
uint pos, //position to insert offer, 0 should be used if unknown
bool rounding //match "close enough" orders?
)
public
can_offer
returns (uint)
{
require(!locked, "Reentrancy attempt");
require(_dust[pay_gem] <= pay_amt);
if (matchingEnabled) {
return _matcho(pay_amt, pay_gem, buy_amt, buy_gem, pos, rounding);
}
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(uint id, uint amount)
public
can_buy(id)
returns (bool)
{
require(!locked, "Reentrancy attempt");
var fn = matchingEnabled ? _buys : super.buy;
return fn(id, amount);
}
// Cancel an offer. Refunds offer maker.
function cancel(uint id)
public
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(
uint id, //maker (ask) id
uint 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
LogInsert(msg.sender, id);
return true;
}
//deletes _rank [id]
// Function should be called by keepers.
function del_rank(uint id)
public
returns (bool)
{
require(!locked, "Reentrancy attempt");
require(!isActive(id) && _rank[id].delb != 0 && _rank[id].delb < block.number - 10);
delete _rank[id];
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
uint dust //maker (ask) minimum sell amount
)
public
auth
note
returns (bool)
{
_dust[pay_gem] = dust;
LogMinSell(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
)
public
constant
returns (uint)
{
return _dust[pay_gem];
}
//set buy functionality enabled/disabled
function setBuyEnabled(bool buyEnabled_) public auth returns (bool) {
buyEnabled = buyEnabled_;
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 MatchingMarket is reverted to ExpiringMarket,
// and matching is not done, and sorted lists are disabled.
function setMatchingEnabled(bool matchingEnabled_) public auth returns (bool) {
matchingEnabled = matchingEnabled_;
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 constant returns(uint) {
return _best[sell_gem][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(uint id) public constant returns(uint) {
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(uint id) public constant returns(uint) {
return _rank[id].next;
}
//return the amount of better offers for a token pair
function getOfferCount(ERC20 sell_gem, ERC20 buy_gem) public constant returns(uint) {
return _span[sell_gem][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 constant returns(uint) {
return _head;
}
//get the next unsorted offer
// Can be used to cycle through all the unsorted offers.
function getNextUnsortedOffer(uint id) public constant returns(uint) {
return _near[id];
}
function isOfferSorted(uint id) public constant returns(bool) {
return _rank[id].next != 0
|| _rank[id].prev != 0
|| _best[offers[id].pay_gem][offers[id].buy_gem] == id;
}
function sellAllAmount(ERC20 pay_gem, uint pay_amt, ERC20 buy_gem, uint min_fill_amount)
public
returns (uint fill_amt)
{
require(!locked, "Reentrancy attempt");
uint 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
var 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, uint buy_amt, ERC20 pay_gem, uint max_fill_amount)
public
returns (uint fill_amt)
{
require(!locked, "Reentrancy attempt");
uint 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, uint pay_amt) public constant returns (uint fill_amt) {
var 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, uint buy_amt) public constant returns (uint fill_amt) {
var 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(uint id, uint 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[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(uint id)
internal
view
returns (uint)
{
require( id > 0 );
address buy_gem = address(offers[id].buy_gem);
address pay_gem = address(offers[id].pay_gem);
uint top = _best[pay_gem][buy_gem];
uint 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(uint id, uint pos)
internal
view
returns (uint)
{
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)) {
uint 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(
uint low, //lower priced offer's id
uint 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(
uint t_pay_amt, //taker sell how much
ERC20 t_pay_gem, //taker sell which token
uint t_buy_amt, //taker buy how much
ERC20 t_buy_gem, //taker buy which token
uint pos, //position id
bool rounding //match "close enough" orders?
)
internal
returns (uint id)
{
uint best_maker_id; //highest maker id
uint t_buy_amt_old; //taker buy how much saved
uint m_buy_amt; //maker offer wants to buy this much token
uint m_pay_amt; //maker offer wants to sell this much token
// there is at least one offer stored for token pair
while (_best[t_buy_gem][t_pay_gem] > 0) {
best_maker_id = _best[t_buy_gem][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));
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[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.
// ****Available to authorized contracts only!**********
// Keepers should call insert(id,pos) to put offer in the sorted list.
function _offeru(
uint pay_amt, //maker (ask) sell how much
ERC20 pay_gem, //maker (ask) sell which token
uint buy_amt, //maker (ask) buy how much
ERC20 buy_gem //maker (ask) buy which token
)
internal
returns (uint id)
{
require(_dust[pay_gem] <= pay_amt);
id = super.offer(pay_amt, pay_gem, buy_amt, buy_gem);
_near[id] = _head;
_head = id;
LogUnsortedOffer(id);
}
//put offer into the sorted list
function _sort(
uint id, //maker (ask) id
uint pos //position to insert into
)
internal
{
require(isActive(id));
address buy_gem = address(offers[id].buy_gem);
address pay_gem = address(offers[id].pay_gem);
uint 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[pay_gem][buy_gem];
_best[pay_gem][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[pay_gem][buy_gem]++;
LogSortedOffer(id);
}
// Remove offer from the sorted list (does not cancel offer)
function _unsort(
uint 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(
uint id //id of maker offer to remove from unsorted list
)
internal
returns (bool)
{
uint uid = _head; //id of an offer in unsorted offers list
uint 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;
}
}File 2 of 4: DSToken
// MKR Token
// hevm: flattened sources of src/mkr-499.sol
pragma solidity ^0.4.15;
////// lib/ds-roles/lib/ds-auth/src/auth.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
contract DSAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
contract DSAuth is DSAuthEvents {
DSAuthority public authority;
address public owner;
function DSAuth() public {
owner = msg.sender;
LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
LogSetOwner(owner);
}
function setAuthority(DSAuthority authority_)
public
auth
{
authority = authority_;
LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == address(this)) {
return true;
} else if (src == owner) {
return true;
} else if (authority == DSAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
////// lib/ds-thing/lib/ds-math/src/math.sol
/// math.sol -- mixin for inline numerical wizardry
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
contract DSMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x);
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x);
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x);
}
function min(uint x, uint y) internal pure returns (uint z) {
return x <= y ? x : y;
}
function max(uint x, uint y) internal pure returns (uint z) {
return x >= y ? x : y;
}
function imin(int x, int y) internal pure returns (int z) {
return x <= y ? x : y;
}
function imax(int x, int y) internal pure returns (int z) {
return x >= y ? x : y;
}
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
function wmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, WAD), y / 2) / y;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, RAY), y / 2) / y;
}
// This famous algorithm is called "exponentiation by squaring"
// and calculates x^n with x as fixed-point and n as regular unsigned.
//
// It's O(log n), instead of O(n) for naive repeated multiplication.
//
// These facts are why it works:
//
// If n is even, then x^n = (x^2)^(n/2).
// If n is odd, then x^n = x * x^(n-1),
// and applying the equation for even x gives
// x^n = x * (x^2)^((n-1) / 2).
//
// Also, EVM division is flooring and
// floor[(n-1) / 2] = floor[n / 2].
//
function rpow(uint x, uint n) internal pure returns (uint z) {
z = n % 2 != 0 ? x : RAY;
for (n /= 2; n != 0; n /= 2) {
x = rmul(x, x);
if (n % 2 != 0) {
z = rmul(z, x);
}
}
}
}
////// lib/ds-thing/lib/ds-note/src/note.sol
/// note.sol -- the `note' modifier, for logging calls as events
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
contract DSNote {
event LogNote(
bytes4 indexed sig,
address indexed guy,
bytes32 indexed foo,
bytes32 indexed bar,
uint wad,
bytes fax
) anonymous;
modifier note {
bytes32 foo;
bytes32 bar;
assembly {
foo := calldataload(4)
bar := calldataload(36)
}
LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
_;
}
}
////// lib/ds-thing/src/thing.sol
// thing.sol - `auth` with handy mixins. your things should be DSThings
// Copyright (C) 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
/* import 'ds-auth/auth.sol'; */
/* import 'ds-note/note.sol'; */
/* import 'ds-math/math.sol'; */
contract DSThing is DSAuth, DSNote, DSMath {
}
////// lib/ds-token/lib/ds-stop/src/stop.sol
/// stop.sol -- mixin for enable/disable functionality
// Copyright (C) 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
/* import "ds-auth/auth.sol"; */
/* import "ds-note/note.sol"; */
contract DSStop is DSNote, DSAuth {
bool public stopped;
modifier stoppable {
require(!stopped);
_;
}
function stop() public auth note {
stopped = true;
}
function start() public auth note {
stopped = false;
}
}
////// lib/ds-token/lib/erc20/src/erc20.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.8; */
// Token standard API
// https://github.com/ethereum/EIPs/issues/20
contract ERC20 {
function totalSupply() public view returns (uint supply);
function balanceOf( address who ) public view returns (uint value);
function allowance( address owner, address spender ) public view returns (uint _allowance);
function transfer( address to, uint value) public returns (bool ok);
function transferFrom( address from, address to, uint value) public returns (bool ok);
function approve( address spender, uint value ) public returns (bool ok);
event Transfer( address indexed from, address indexed to, uint value);
event Approval( address indexed owner, address indexed spender, uint value);
}
////// lib/ds-token/src/base.sol
/// base.sol -- basic ERC20 implementation
// Copyright (C) 2015, 2016, 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
/* import "erc20/erc20.sol"; */
/* import "ds-math/math.sol"; */
contract DSTokenBase is ERC20, DSMath {
uint256 _supply;
mapping (address => uint256) _balances;
mapping (address => mapping (address => uint256)) _approvals;
function DSTokenBase(uint supply) public {
_balances[msg.sender] = supply;
_supply = supply;
}
function totalSupply() public view returns (uint) {
return _supply;
}
function balanceOf(address src) public view returns (uint) {
return _balances[src];
}
function allowance(address src, address guy) public view returns (uint) {
return _approvals[src][guy];
}
function transfer(address dst, uint wad) public returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad)
public
returns (bool)
{
if (src != msg.sender) {
_approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
}
_balances[src] = sub(_balances[src], wad);
_balances[dst] = add(_balances[dst], wad);
Transfer(src, dst, wad);
return true;
}
function approve(address guy, uint wad) public returns (bool) {
_approvals[msg.sender][guy] = wad;
Approval(msg.sender, guy, wad);
return true;
}
}
////// lib/ds-token/src/token.sol
/// token.sol -- ERC20 implementation with minting and burning
// Copyright (C) 2015, 2016, 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
/* import "ds-stop/stop.sol"; */
/* import "./base.sol"; */
contract DSToken is DSTokenBase(0), DSStop {
bytes32 public symbol;
uint256 public decimals = 18; // standard token precision. override to customize
function DSToken(bytes32 symbol_) public {
symbol = symbol_;
}
event Mint(address indexed guy, uint wad);
event Burn(address indexed guy, uint wad);
function approve(address guy) public stoppable returns (bool) {
return super.approve(guy, uint(-1));
}
function approve(address guy, uint wad) public stoppable returns (bool) {
return super.approve(guy, wad);
}
function transferFrom(address src, address dst, uint wad)
public
stoppable
returns (bool)
{
if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) {
_approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
}
_balances[src] = sub(_balances[src], wad);
_balances[dst] = add(_balances[dst], wad);
Transfer(src, dst, wad);
return true;
}
function push(address dst, uint wad) public {
transferFrom(msg.sender, dst, wad);
}
function pull(address src, uint wad) public {
transferFrom(src, msg.sender, wad);
}
function move(address src, address dst, uint wad) public {
transferFrom(src, dst, wad);
}
function mint(uint wad) public {
mint(msg.sender, wad);
}
function burn(uint wad) public {
burn(msg.sender, wad);
}
function mint(address guy, uint wad) public auth stoppable {
_balances[guy] = add(_balances[guy], wad);
_supply = add(_supply, wad);
Mint(guy, wad);
}
function burn(address guy, uint wad) public auth stoppable {
if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) {
_approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
}
_balances[guy] = sub(_balances[guy], wad);
_supply = sub(_supply, wad);
Burn(guy, wad);
}
// Optional token name
bytes32 public name = "";
function setName(bytes32 name_) public auth {
name = name_;
}
}File 3 of 4: DSToken
pragma solidity ^0.4.13;
////// lib/ds-math/src/math.sol
/// math.sol -- mixin for inline numerical wizardry
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
contract DSMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x);
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x);
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x);
}
function min(uint x, uint y) internal pure returns (uint z) {
return x <= y ? x : y;
}
function max(uint x, uint y) internal pure returns (uint z) {
return x >= y ? x : y;
}
function imin(int x, int y) internal pure returns (int z) {
return x <= y ? x : y;
}
function imax(int x, int y) internal pure returns (int z) {
return x >= y ? x : y;
}
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
function wmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, WAD), y / 2) / y;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, RAY), y / 2) / y;
}
// This famous algorithm is called "exponentiation by squaring"
// and calculates x^n with x as fixed-point and n as regular unsigned.
//
// It's O(log n), instead of O(n) for naive repeated multiplication.
//
// These facts are why it works:
//
// If n is even, then x^n = (x^2)^(n/2).
// If n is odd, then x^n = x * x^(n-1),
// and applying the equation for even x gives
// x^n = x * (x^2)^((n-1) / 2).
//
// Also, EVM division is flooring and
// floor[(n-1) / 2] = floor[n / 2].
//
function rpow(uint x, uint n) internal pure returns (uint z) {
z = n % 2 != 0 ? x : RAY;
for (n /= 2; n != 0; n /= 2) {
x = rmul(x, x);
if (n % 2 != 0) {
z = rmul(z, x);
}
}
}
}
////// lib/ds-stop/lib/ds-auth/src/auth.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
contract DSAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
contract DSAuth is DSAuthEvents {
DSAuthority public authority;
address public owner;
function DSAuth() public {
owner = msg.sender;
LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
LogSetOwner(owner);
}
function setAuthority(DSAuthority authority_)
public
auth
{
authority = authority_;
LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == address(this)) {
return true;
} else if (src == owner) {
return true;
} else if (authority == DSAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
////// lib/ds-stop/lib/ds-note/src/note.sol
/// note.sol -- the `note' modifier, for logging calls as events
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
contract DSNote {
event LogNote(
bytes4 indexed sig,
address indexed guy,
bytes32 indexed foo,
bytes32 indexed bar,
uint wad,
bytes fax
) anonymous;
modifier note {
bytes32 foo;
bytes32 bar;
assembly {
foo := calldataload(4)
bar := calldataload(36)
}
LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
_;
}
}
////// lib/ds-stop/src/stop.sol
/// stop.sol -- mixin for enable/disable functionality
// Copyright (C) 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
/* import "ds-auth/auth.sol"; */
/* import "ds-note/note.sol"; */
contract DSStop is DSNote, DSAuth {
bool public stopped;
modifier stoppable {
require(!stopped);
_;
}
function stop() public auth note {
stopped = true;
}
function start() public auth note {
stopped = false;
}
}
////// lib/erc20/src/erc20.sol
/// erc20.sol -- API for the ERC20 token standard
// See <https://github.com/ethereum/EIPs/issues/20>.
// This file likely does not meet the threshold of originality
// required for copyright to apply. As a result, this is free and
// unencumbered software belonging to the public domain.
/* pragma solidity ^0.4.8; */
contract ERC20Events {
event Approval(address indexed src, address indexed guy, uint wad);
event Transfer(address indexed src, address indexed dst, uint wad);
}
contract ERC20 is ERC20Events {
function totalSupply() public view returns (uint);
function balanceOf(address guy) public view returns (uint);
function allowance(address src, address guy) public view returns (uint);
function approve(address guy, uint wad) public returns (bool);
function transfer(address dst, uint wad) public returns (bool);
function transferFrom(
address src, address dst, uint wad
) public returns (bool);
}
////// src/base.sol
/// base.sol -- basic ERC20 implementation
// Copyright (C) 2015, 2016, 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
/* import "erc20/erc20.sol"; */
/* import "ds-math/math.sol"; */
contract DSTokenBase is ERC20, DSMath {
uint256 _supply;
mapping (address => uint256) _balances;
mapping (address => mapping (address => uint256)) _approvals;
function DSTokenBase(uint supply) public {
_balances[msg.sender] = supply;
_supply = supply;
}
function totalSupply() public view returns (uint) {
return _supply;
}
function balanceOf(address src) public view returns (uint) {
return _balances[src];
}
function allowance(address src, address guy) public view returns (uint) {
return _approvals[src][guy];
}
function transfer(address dst, uint wad) public returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad)
public
returns (bool)
{
if (src != msg.sender) {
_approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
}
_balances[src] = sub(_balances[src], wad);
_balances[dst] = add(_balances[dst], wad);
Transfer(src, dst, wad);
return true;
}
function approve(address guy, uint wad) public returns (bool) {
_approvals[msg.sender][guy] = wad;
Approval(msg.sender, guy, wad);
return true;
}
}
////// src/token.sol
/// token.sol -- ERC20 implementation with minting and burning
// Copyright (C) 2015, 2016, 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* pragma solidity ^0.4.13; */
/* import "ds-stop/stop.sol"; */
/* import "./base.sol"; */
contract DSToken is DSTokenBase(0), DSStop {
bytes32 public symbol;
uint256 public decimals = 18; // standard token precision. override to customize
function DSToken(bytes32 symbol_) public {
symbol = symbol_;
}
event Mint(address indexed guy, uint wad);
event Burn(address indexed guy, uint wad);
function approve(address guy) public stoppable returns (bool) {
return super.approve(guy, uint(-1));
}
function approve(address guy, uint wad) public stoppable returns (bool) {
return super.approve(guy, wad);
}
function transferFrom(address src, address dst, uint wad)
public
stoppable
returns (bool)
{
if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) {
_approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
}
_balances[src] = sub(_balances[src], wad);
_balances[dst] = add(_balances[dst], wad);
Transfer(src, dst, wad);
return true;
}
function push(address dst, uint wad) public {
transferFrom(msg.sender, dst, wad);
}
function pull(address src, uint wad) public {
transferFrom(src, msg.sender, wad);
}
function move(address src, address dst, uint wad) public {
transferFrom(src, dst, wad);
}
function mint(uint wad) public {
mint(msg.sender, wad);
}
function burn(uint wad) public {
burn(msg.sender, wad);
}
function mint(address guy, uint wad) public auth stoppable {
_balances[guy] = add(_balances[guy], wad);
_supply = add(_supply, wad);
Mint(guy, wad);
}
function burn(address guy, uint wad) public auth stoppable {
if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) {
_approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
}
_balances[guy] = sub(_balances[guy], wad);
_supply = sub(_supply, wad);
Burn(guy, wad);
}
// Optional token name
bytes32 public name = "";
function setName(bytes32 name_) public auth {
name = name_;
}
}File 4 of 4: GasToken2
pragma solidity ^0.4.10;
contract GasToken2 {
//////////////////////////////////////////////////////////////////////////
// RLP.sol
// Due to some unexplained bug, we get a slightly different bytecode if
// we use an import, and are then unable to verify the code in Etherscan
//////////////////////////////////////////////////////////////////////////
uint256 constant ADDRESS_BYTES = 20;
uint256 constant MAX_SINGLE_BYTE = 128;
uint256 constant MAX_NONCE = 256**9 - 1;
// count number of bytes required to represent an unsigned integer
function count_bytes(uint256 n) constant internal returns (uint256 c) {
uint i = 0;
uint mask = 1;
while (n >= mask) {
i += 1;
mask *= 256;
}
return i;
}
function mk_contract_address(address a, uint256 n) constant internal returns (address rlp) {
/*
* make sure the RLP encoding fits in one word:
* total_length 1 byte
* address_length 1 byte
* address 20 bytes
* nonce_length 1 byte (or 0)
* nonce 1-9 bytes
* ==========
* 24-32 bytes
*/
require(n <= MAX_NONCE);
// number of bytes required to write down the nonce
uint256 nonce_bytes;
// length in bytes of the RLP encoding of the nonce
uint256 nonce_rlp_len;
if (0 < n && n < MAX_SINGLE_BYTE) {
// nonce fits in a single byte
// RLP(nonce) = nonce
nonce_bytes = 1;
nonce_rlp_len = 1;
} else {
// RLP(nonce) = [num_bytes_in_nonce nonce]
nonce_bytes = count_bytes(n);
nonce_rlp_len = nonce_bytes + 1;
}
// [address_length(1) address(20) nonce_length(0 or 1) nonce(1-9)]
uint256 tot_bytes = 1 + ADDRESS_BYTES + nonce_rlp_len;
// concatenate all parts of the RLP encoding in the leading bytes of
// one 32-byte word
uint256 word = ((192 + tot_bytes) * 256**31) +
((128 + ADDRESS_BYTES) * 256**30) +
(uint256(a) * 256**10);
if (0 < n && n < MAX_SINGLE_BYTE) {
word += n * 256**9;
} else {
word += (128 + nonce_bytes) * 256**9;
word += n * 256**(9 - nonce_bytes);
}
uint256 hash;
assembly {
let mem_start := mload(0x40) // get a pointer to free memory
mstore(0x40, add(mem_start, 0x20)) // update the pointer
mstore(mem_start, word) // store the rlp encoding
hash := sha3(mem_start,
add(tot_bytes, 1)) // hash the rlp encoding
}
// interpret hash as address (20 least significant bytes)
return address(hash);
}
//////////////////////////////////////////////////////////////////////////
// Generic ERC20
//////////////////////////////////////////////////////////////////////////
// owner -> amount
mapping(address => uint256) s_balances;
// owner -> spender -> max amount
mapping(address => mapping(address => uint256)) s_allowances;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
// Spec: Get the account balance of another account with address `owner`
function balanceOf(address owner) public constant returns (uint256 balance) {
return s_balances[owner];
}
function internalTransfer(address from, address to, uint256 value) internal returns (bool success) {
if (value <= s_balances[from]) {
s_balances[from] -= value;
s_balances[to] += value;
Transfer(from, to, value);
return true;
} else {
return false;
}
}
// Spec: Send `value` amount of tokens to address `to`
function transfer(address to, uint256 value) public returns (bool success) {
address from = msg.sender;
return internalTransfer(from, to, value);
}
// Spec: Send `value` amount of tokens from address `from` to address `to`
function transferFrom(address from, address to, uint256 value) public returns (bool success) {
address spender = msg.sender;
if(value <= s_allowances[from][spender] && internalTransfer(from, to, value)) {
s_allowances[from][spender] -= value;
return true;
} else {
return false;
}
}
// Spec: Allow `spender` to withdraw from your account, multiple times, up
// to the `value` amount. If this function is called again it overwrites the
// current allowance with `value`.
function approve(address spender, uint256 value) public returns (bool success) {
address owner = msg.sender;
if (value != 0 && s_allowances[owner][spender] != 0) {
return false;
}
s_allowances[owner][spender] = value;
Approval(owner, spender, value);
return true;
}
// Spec: Returns the `amount` which `spender` is still allowed to withdraw
// from `owner`.
// What if the allowance is higher than the balance of the `owner`?
// Callers should be careful to use min(allowance, balanceOf) to make sure
// that the allowance is actually present in the account!
function allowance(address owner, address spender) public constant returns (uint256 remaining) {
return s_allowances[owner][spender];
}
//////////////////////////////////////////////////////////////////////////
// GasToken specifics
//////////////////////////////////////////////////////////////////////////
uint8 constant public decimals = 2;
string constant public name = "Gastoken.io";
string constant public symbol = "GST2";
// We build a queue of nonces at which child contracts are stored. s_head is
// the nonce at the head of the queue, s_tail is the nonce behind the tail
// of the queue. The queue grows at the head and shrinks from the tail.
// Note that when and only when a contract CREATEs another contract, the
// creating contract's nonce is incremented.
// The first child contract is created with nonce == 1, the second child
// contract is created with nonce == 2, and so on...
// For example, if there are child contracts at nonces [2,3,4],
// then s_head == 4 and s_tail == 1. If there are no child contracts,
// s_head == s_tail.
uint256 s_head;
uint256 s_tail;
// totalSupply gives the number of tokens currently in existence
// Each token corresponds to one child contract that can be SELFDESTRUCTed
// for a gas refund.
function totalSupply() public constant returns (uint256 supply) {
return s_head - s_tail;
}
// Creates a child contract that can only be destroyed by this contract.
function makeChild() internal returns (address addr) {
assembly {
// EVM assembler of runtime portion of child contract:
// ;; Pseudocode: if (msg.sender != 0x0000000000b3f879cb30fe243b4dfee438691c04) { throw; }
// ;; suicide(msg.sender)
// PUSH15 0xb3f879cb30fe243b4dfee438691c04 ;; hardcoded address of this contract
// CALLER
// XOR
// PC
// JUMPI
// CALLER
// SELFDESTRUCT
// Or in binary: 6eb3f879cb30fe243b4dfee438691c043318585733ff
// Since the binary is so short (22 bytes), we can get away
// with a very simple initcode:
// PUSH22 0x6eb3f879cb30fe243b4dfee438691c043318585733ff
// PUSH1 0
// MSTORE ;; at this point, memory locations mem[10] through
// ;; mem[31] contain the runtime portion of the child
// ;; contract. all that's left to do is to RETURN this
// ;; chunk of memory.
// PUSH1 22 ;; length
// PUSH1 10 ;; offset
// RETURN
// Or in binary: 756eb3f879cb30fe243b4dfee438691c043318585733ff6000526016600af3
// Almost done! All we have to do is put this short (31 bytes) blob into
// memory and call CREATE with the appropriate offsets.
let solidity_free_mem_ptr := mload(0x40)
mstore(solidity_free_mem_ptr, 0x00756eb3f879cb30fe243b4dfee438691c043318585733ff6000526016600af3)
addr := create(0, add(solidity_free_mem_ptr, 1), 31)
}
}
// Mints `value` new sub-tokens (e.g. cents, pennies, ...) by creating `value`
// new child contracts. The minted tokens are owned by the caller of this
// function.
function mint(uint256 value) public {
for (uint256 i = 0; i < value; i++) {
makeChild();
}
s_head += value;
s_balances[msg.sender] += value;
}
// Destroys `value` child contracts and updates s_tail.
//
// This function is affected by an issue in solc: https://github.com/ethereum/solidity/issues/2999
// The `mk_contract_address(this, i).call();` doesn't forward all available gas, but only GAS - 25710.
// As a result, when this line is executed with e.g. 30000 gas, the callee will have less than 5000 gas
// available and its SELFDESTRUCT operation will fail leading to no gas refund occurring.
// The remaining ~29000 gas left after the call is enough to update s_tail and the caller's balance.
// Hence tokens will have been destroyed without a commensurate gas refund.
// Fortunately, there is a simple workaround:
// Whenever you call free, freeUpTo, freeFrom, or freeUpToFrom, ensure that you pass at least
// 25710 + `value` * (1148 + 5722 + 150) gas. (It won't all be used)
function destroyChildren(uint256 value) internal {
uint256 tail = s_tail;
// tail points to slot behind the last contract in the queue
for (uint256 i = tail + 1; i <= tail + value; i++) {
mk_contract_address(this, i).call();
}
s_tail = tail + value;
}
// Frees `value` sub-tokens (e.g. cents, pennies, ...) belonging to the
// caller of this function by destroying `value` child contracts, which
// will trigger a partial gas refund.
// You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas
// when calling this function. For details, see the comment above `destroyChilden`.
function free(uint256 value) public returns (bool success) {
uint256 from_balance = s_balances[msg.sender];
if (value > from_balance) {
return false;
}
destroyChildren(value);
s_balances[msg.sender] = from_balance - value;
return true;
}
// Frees up to `value` sub-tokens. Returns how many tokens were freed.
// Otherwise, identical to free.
// You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas
// when calling this function. For details, see the comment above `destroyChilden`.
function freeUpTo(uint256 value) public returns (uint256 freed) {
uint256 from_balance = s_balances[msg.sender];
if (value > from_balance) {
value = from_balance;
}
destroyChildren(value);
s_balances[msg.sender] = from_balance - value;
return value;
}
// Frees `value` sub-tokens owned by address `from`. Requires that `msg.sender`
// has been approved by `from`.
// You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas
// when calling this function. For details, see the comment above `destroyChilden`.
function freeFrom(address from, uint256 value) public returns (bool success) {
address spender = msg.sender;
uint256 from_balance = s_balances[from];
if (value > from_balance) {
return false;
}
mapping(address => uint256) from_allowances = s_allowances[from];
uint256 spender_allowance = from_allowances[spender];
if (value > spender_allowance) {
return false;
}
destroyChildren(value);
s_balances[from] = from_balance - value;
from_allowances[spender] = spender_allowance - value;
return true;
}
// Frees up to `value` sub-tokens owned by address `from`. Returns how many tokens were freed.
// Otherwise, identical to `freeFrom`.
// You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas
// when calling this function. For details, see the comment above `destroyChilden`.
function freeFromUpTo(address from, uint256 value) public returns (uint256 freed) {
address spender = msg.sender;
uint256 from_balance = s_balances[from];
if (value > from_balance) {
value = from_balance;
}
mapping(address => uint256) from_allowances = s_allowances[from];
uint256 spender_allowance = from_allowances[spender];
if (value > spender_allowance) {
value = spender_allowance;
}
destroyChildren(value);
s_balances[from] = from_balance - value;
from_allowances[spender] = spender_allowance - value;
return value;
}
}