ETH Price: $1,889.68 (+1.26%)

Transaction Decoder

Block:
13103434 at Aug-26-2021 09:23:08 PM +UTC
Transaction Fee:
0.008639386 ETH $16.33
Gas Used:
88,157 Gas / 98 Gwei

Emitted Events:

218 Vat.0xbb35783b00000000000000000000000000000000000000000000000000000000( 0xbb35783b00000000000000000000000000000000000000000000000000000000, 0x00000000000000000000000075eadf2c1fa13d518da647c6ee08d8bc2c36d693, 0x0000000000000000000000009759a6ac90977b93b58547b4a71c78317f391a28, 0x000000000000000000000022361d8afcc93343e962029a7edab2000000000000, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, bb35783b00000000000000000000000075eadf2c1fa13d518da647c6ee08d8bc, 2c36d6930000000000000000000000009759a6ac90977b93b58547b4a71c7831, 7f391a28000000000000000000000022361d8afcc93343e962029a7edab20000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
219 Dai.Transfer( src=0x0000000000000000000000000000000000000000, dst=[Sender] 0x75eadf2c1fa13d518da647c6ee08d8bc2c36d693, wad=50000000000000000000000 )
220 DaiJoin.0xef693bed00000000000000000000000000000000000000000000000000000000( 0xef693bed00000000000000000000000000000000000000000000000000000000, 0x00000000000000000000000075eadf2c1fa13d518da647c6ee08d8bc2c36d693, 0x00000000000000000000000075eadf2c1fa13d518da647c6ee08d8bc2c36d693, 0x000000000000000000000000000000000000000000000a968163f0a57b400000, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, ef693bed00000000000000000000000075eadf2c1fa13d518da647c6ee08d8bc, 2c36d693000000000000000000000000000000000000000000000a968163f0a5, 7b40000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x35D1b3F3...259A0492B
(Sky: MCD Vat)
0x6B175474...495271d0F
0x75Eadf2C...c2c36D693
1.37397224542530341 Eth
Nonce: 31
1.36533285942530341 Eth
Nonce: 32
0.008639386
(Babel Pool)
11,876.305755516948008427 Eth11,876.306765389897355497 Eth0.00100987294934707

Execution Trace

DaiJoin.exit( usr=0x75Eadf2C1fA13D518DA647c6EE08d8Bc2c36D693, wad=50000000000000000000000 )
  • Vat.move( src=0x75Eadf2C1fA13D518DA647c6EE08d8Bc2c36D693, dst=0x9759A6Ac90977b93B58547b4A71c78317f391A28, rad=50000000000000000000000000000000000000000000000000 )
  • Dai.mint( usr=0x75Eadf2C1fA13D518DA647c6EE08d8Bc2c36D693, wad=50000000000000000000000 )
    File 1 of 3: DaiJoin
    // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/join.sol
    pragma solidity =0.5.12;
    
    ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.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.5.12; */
    
    contract LibNote {
        event LogNote(
            bytes4   indexed  sig,
            address  indexed  usr,
            bytes32  indexed  arg1,
            bytes32  indexed  arg2,
            bytes             data
        ) anonymous;
    
        modifier note {
            _;
            assembly {
                // log an 'anonymous' event with a constant 6 words of calldata
                // and four indexed topics: selector, caller, arg1 and arg2
                let mark := msize                         // end of memory ensures zero
                mstore(0x40, add(mark, 288))              // update free memory pointer
                mstore(mark, 0x20)                        // bytes type data offset
                mstore(add(mark, 0x20), 224)              // bytes size (padded)
                calldatacopy(add(mark, 0x40), 0, 224)     // bytes payload
                log4(mark, 288,                           // calldata
                     shl(224, shr(224, calldataload(0))), // msg.sig
                     caller,                              // msg.sender
                     calldataload(4),                     // arg1
                     calldataload(36)                     // arg2
                    )
            }
        }
    }
    
    ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/join.sol
    /// join.sol -- Basic token adapters
    
    // Copyright (C) 2018 Rain <[email protected]>
    //
    // 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.5.12; */
    
    /* import "./lib.sol"; */
    
    contract GemLike {
        function decimals() public view returns (uint);
        function transfer(address,uint) external returns (bool);
        function transferFrom(address,address,uint) external returns (bool);
    }
    
    contract DSTokenLike {
        function mint(address,uint) external;
        function burn(address,uint) external;
    }
    
    contract VatLike {
        function slip(bytes32,address,int) external;
        function move(address,address,uint) external;
    }
    
    /*
        Here we provide *adapters* to connect the Vat to arbitrary external
        token implementations, creating a bounded context for the Vat. The
        adapters here are provided as working examples:
    
          - `GemJoin`: For well behaved ERC20 tokens, with simple transfer
                       semantics.
    
          - `ETHJoin`: For native Ether.
    
          - `DaiJoin`: For connecting internal Dai balances to an external
                       `DSToken` implementation.
    
        In practice, adapter implementations will be varied and specific to
        individual collateral types, accounting for different transfer
        semantics and token standards.
    
        Adapters need to implement two basic methods:
    
          - `join`: enter collateral into the system
          - `exit`: remove collateral from the system
    
    */
    
    contract GemJoin is LibNote {
        // --- Auth ---
        mapping (address => uint) public wards;
        function rely(address usr) external note auth { wards[usr] = 1; }
        function deny(address usr) external note auth { wards[usr] = 0; }
        modifier auth {
            require(wards[msg.sender] == 1, "GemJoin/not-authorized");
            _;
        }
    
        VatLike public vat;
        bytes32 public ilk;
        GemLike public gem;
        uint    public dec;
        uint    public live;  // Access Flag
    
        constructor(address vat_, bytes32 ilk_, address gem_) public {
            wards[msg.sender] = 1;
            live = 1;
            vat = VatLike(vat_);
            ilk = ilk_;
            gem = GemLike(gem_);
            dec = gem.decimals();
        }
        function cage() external note auth {
            live = 0;
        }
        function join(address usr, uint wad) external note {
            require(live == 1, "GemJoin/not-live");
            require(int(wad) >= 0, "GemJoin/overflow");
            vat.slip(ilk, usr, int(wad));
            require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin/failed-transfer");
        }
        function exit(address usr, uint wad) external note {
            require(wad <= 2 ** 255, "GemJoin/overflow");
            vat.slip(ilk, msg.sender, -int(wad));
            require(gem.transfer(usr, wad), "GemJoin/failed-transfer");
        }
    }
    
    contract ETHJoin is LibNote {
        // --- Auth ---
        mapping (address => uint) public wards;
        function rely(address usr) external note auth { wards[usr] = 1; }
        function deny(address usr) external note auth { wards[usr] = 0; }
        modifier auth {
            require(wards[msg.sender] == 1, "ETHJoin/not-authorized");
            _;
        }
    
        VatLike public vat;
        bytes32 public ilk;
        uint    public live;  // Access Flag
    
        constructor(address vat_, bytes32 ilk_) public {
            wards[msg.sender] = 1;
            live = 1;
            vat = VatLike(vat_);
            ilk = ilk_;
        }
        function cage() external note auth {
            live = 0;
        }
        function join(address usr) external payable note {
            require(live == 1, "ETHJoin/not-live");
            require(int(msg.value) >= 0, "ETHJoin/overflow");
            vat.slip(ilk, usr, int(msg.value));
        }
        function exit(address payable usr, uint wad) external note {
            require(int(wad) >= 0, "ETHJoin/overflow");
            vat.slip(ilk, msg.sender, -int(wad));
            usr.transfer(wad);
        }
    }
    
    contract DaiJoin is LibNote {
        // --- Auth ---
        mapping (address => uint) public wards;
        function rely(address usr) external note auth { wards[usr] = 1; }
        function deny(address usr) external note auth { wards[usr] = 0; }
        modifier auth {
            require(wards[msg.sender] == 1, "DaiJoin/not-authorized");
            _;
        }
    
        VatLike public vat;
        DSTokenLike public dai;
        uint    public live;  // Access Flag
    
        constructor(address vat_, address dai_) public {
            wards[msg.sender] = 1;
            live = 1;
            vat = VatLike(vat_);
            dai = DSTokenLike(dai_);
        }
        function cage() external note auth {
            live = 0;
        }
        uint constant ONE = 10 ** 27;
        function mul(uint x, uint y) internal pure returns (uint z) {
            require(y == 0 || (z = x * y) / y == x);
        }
        function join(address usr, uint wad) external note {
            vat.move(address(this), usr, mul(ONE, wad));
            dai.burn(msg.sender, wad);
        }
        function exit(address usr, uint wad) external note {
            require(live == 1, "DaiJoin/not-live");
            vat.move(msg.sender, address(this), mul(ONE, wad));
            dai.mint(usr, wad);
        }
    }

    File 2 of 3: Vat
    // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/vat.sol
    pragma solidity =0.5.12;
    
    ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/vat.sol
    /// vat.sol -- Dai CDP database
    
    // Copyright (C) 2018 Rain <[email protected]>
    //
    // 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.5.12; */
    
    contract Vat {
        // --- Auth ---
        mapping (address => uint) public wards;
        function rely(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 1; }
        function deny(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 0; }
        modifier auth {
            require(wards[msg.sender] == 1, "Vat/not-authorized");
            _;
        }
    
        mapping(address => mapping (address => uint)) public can;
        function hope(address usr) external note { can[msg.sender][usr] = 1; }
        function nope(address usr) external note { can[msg.sender][usr] = 0; }
        function wish(address bit, address usr) internal view returns (bool) {
            return either(bit == usr, can[bit][usr] == 1);
        }
    
        // --- Data ---
        struct Ilk {
            uint256 Art;   // Total Normalised Debt     [wad]
            uint256 rate;  // Accumulated Rates         [ray]
            uint256 spot;  // Price with Safety Margin  [ray]
            uint256 line;  // Debt Ceiling              [rad]
            uint256 dust;  // Urn Debt Floor            [rad]
        }
        struct Urn {
            uint256 ink;   // Locked Collateral  [wad]
            uint256 art;   // Normalised Debt    [wad]
        }
    
        mapping (bytes32 => Ilk)                       public ilks;
        mapping (bytes32 => mapping (address => Urn )) public urns;
        mapping (bytes32 => mapping (address => uint)) public gem;  // [wad]
        mapping (address => uint256)                   public dai;  // [rad]
        mapping (address => uint256)                   public sin;  // [rad]
    
        uint256 public debt;  // Total Dai Issued    [rad]
        uint256 public vice;  // Total Unbacked Dai  [rad]
        uint256 public Line;  // Total Debt Ceiling  [rad]
        uint256 public live;  // Access Flag
    
        // --- Logs ---
        event LogNote(
            bytes4   indexed  sig,
            bytes32  indexed  arg1,
            bytes32  indexed  arg2,
            bytes32  indexed  arg3,
            bytes             data
        ) anonymous;
    
        modifier note {
            _;
            assembly {
                // log an 'anonymous' event with a constant 6 words of calldata
                // and four indexed topics: the selector and the first three args
                let mark := msize                         // end of memory ensures zero
                mstore(0x40, add(mark, 288))              // update free memory pointer
                mstore(mark, 0x20)                        // bytes type data offset
                mstore(add(mark, 0x20), 224)              // bytes size (padded)
                calldatacopy(add(mark, 0x40), 0, 224)     // bytes payload
                log4(mark, 288,                           // calldata
                     shl(224, shr(224, calldataload(0))), // msg.sig
                     calldataload(4),                     // arg1
                     calldataload(36),                    // arg2
                     calldataload(68)                     // arg3
                    )
            }
        }
    
        // --- Init ---
        constructor() public {
            wards[msg.sender] = 1;
            live = 1;
        }
    
        // --- Math ---
        function add(uint x, int y) internal pure returns (uint z) {
            z = x + uint(y);
            require(y >= 0 || z <= x);
            require(y <= 0 || z >= x);
        }
        function sub(uint x, int y) internal pure returns (uint z) {
            z = x - uint(y);
            require(y <= 0 || z <= x);
            require(y >= 0 || z >= x);
        }
        function mul(uint x, int y) internal pure returns (int z) {
            z = int(x) * y;
            require(int(x) >= 0);
            require(y == 0 || z / y == int(x));
        }
        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);
        }
    
        // --- Administration ---
        function init(bytes32 ilk) external note auth {
            require(ilks[ilk].rate == 0, "Vat/ilk-already-init");
            ilks[ilk].rate = 10 ** 27;
        }
        function file(bytes32 what, uint data) external note auth {
            require(live == 1, "Vat/not-live");
            if (what == "Line") Line = data;
            else revert("Vat/file-unrecognized-param");
        }
        function file(bytes32 ilk, bytes32 what, uint data) external note auth {
            require(live == 1, "Vat/not-live");
            if (what == "spot") ilks[ilk].spot = data;
            else if (what == "line") ilks[ilk].line = data;
            else if (what == "dust") ilks[ilk].dust = data;
            else revert("Vat/file-unrecognized-param");
        }
        function cage() external note auth {
            live = 0;
        }
    
        // --- Fungibility ---
        function slip(bytes32 ilk, address usr, int256 wad) external note auth {
            gem[ilk][usr] = add(gem[ilk][usr], wad);
        }
        function flux(bytes32 ilk, address src, address dst, uint256 wad) external note {
            require(wish(src, msg.sender), "Vat/not-allowed");
            gem[ilk][src] = sub(gem[ilk][src], wad);
            gem[ilk][dst] = add(gem[ilk][dst], wad);
        }
        function move(address src, address dst, uint256 rad) external note {
            require(wish(src, msg.sender), "Vat/not-allowed");
            dai[src] = sub(dai[src], rad);
            dai[dst] = add(dai[dst], rad);
        }
    
        function either(bool x, bool y) internal pure returns (bool z) {
            assembly{ z := or(x, y)}
        }
        function both(bool x, bool y) internal pure returns (bool z) {
            assembly{ z := and(x, y)}
        }
    
        // --- CDP Manipulation ---
        function frob(bytes32 i, address u, address v, address w, int dink, int dart) external note {
            // system is live
            require(live == 1, "Vat/not-live");
    
            Urn memory urn = urns[i][u];
            Ilk memory ilk = ilks[i];
            // ilk has been initialised
            require(ilk.rate != 0, "Vat/ilk-not-init");
    
            urn.ink = add(urn.ink, dink);
            urn.art = add(urn.art, dart);
            ilk.Art = add(ilk.Art, dart);
    
            int dtab = mul(ilk.rate, dart);
            uint tab = mul(ilk.rate, urn.art);
            debt     = add(debt, dtab);
    
            // either debt has decreased, or debt ceilings are not exceeded
            require(either(dart <= 0, both(mul(ilk.Art, ilk.rate) <= ilk.line, debt <= Line)), "Vat/ceiling-exceeded");
            // urn is either less risky than before, or it is safe
            require(either(both(dart <= 0, dink >= 0), tab <= mul(urn.ink, ilk.spot)), "Vat/not-safe");
    
            // urn is either more safe, or the owner consents
            require(either(both(dart <= 0, dink >= 0), wish(u, msg.sender)), "Vat/not-allowed-u");
            // collateral src consents
            require(either(dink <= 0, wish(v, msg.sender)), "Vat/not-allowed-v");
            // debt dst consents
            require(either(dart >= 0, wish(w, msg.sender)), "Vat/not-allowed-w");
    
            // urn has no debt, or a non-dusty amount
            require(either(urn.art == 0, tab >= ilk.dust), "Vat/dust");
    
            gem[i][v] = sub(gem[i][v], dink);
            dai[w]    = add(dai[w],    dtab);
    
            urns[i][u] = urn;
            ilks[i]    = ilk;
        }
        // --- CDP Fungibility ---
        function fork(bytes32 ilk, address src, address dst, int dink, int dart) external note {
            Urn storage u = urns[ilk][src];
            Urn storage v = urns[ilk][dst];
            Ilk storage i = ilks[ilk];
    
            u.ink = sub(u.ink, dink);
            u.art = sub(u.art, dart);
            v.ink = add(v.ink, dink);
            v.art = add(v.art, dart);
    
            uint utab = mul(u.art, i.rate);
            uint vtab = mul(v.art, i.rate);
    
            // both sides consent
            require(both(wish(src, msg.sender), wish(dst, msg.sender)), "Vat/not-allowed");
    
            // both sides safe
            require(utab <= mul(u.ink, i.spot), "Vat/not-safe-src");
            require(vtab <= mul(v.ink, i.spot), "Vat/not-safe-dst");
    
            // both sides non-dusty
            require(either(utab >= i.dust, u.art == 0), "Vat/dust-src");
            require(either(vtab >= i.dust, v.art == 0), "Vat/dust-dst");
        }
        // --- CDP Confiscation ---
        function grab(bytes32 i, address u, address v, address w, int dink, int dart) external note auth {
            Urn storage urn = urns[i][u];
            Ilk storage ilk = ilks[i];
    
            urn.ink = add(urn.ink, dink);
            urn.art = add(urn.art, dart);
            ilk.Art = add(ilk.Art, dart);
    
            int dtab = mul(ilk.rate, dart);
    
            gem[i][v] = sub(gem[i][v], dink);
            sin[w]    = sub(sin[w],    dtab);
            vice      = sub(vice,      dtab);
        }
    
        // --- Settlement ---
        function heal(uint rad) external note {
            address u = msg.sender;
            sin[u] = sub(sin[u], rad);
            dai[u] = sub(dai[u], rad);
            vice   = sub(vice,   rad);
            debt   = sub(debt,   rad);
        }
        function suck(address u, address v, uint rad) external note auth {
            sin[u] = add(sin[u], rad);
            dai[v] = add(dai[v], rad);
            vice   = add(vice,   rad);
            debt   = add(debt,   rad);
        }
    
        // --- Rates ---
        function fold(bytes32 i, address u, int rate) external note auth {
            require(live == 1, "Vat/not-live");
            Ilk storage ilk = ilks[i];
            ilk.rate = add(ilk.rate, rate);
            int rad  = mul(ilk.Art, rate);
            dai[u]   = add(dai[u], rad);
            debt     = add(debt,   rad);
        }
    }

    File 3 of 3: Dai
    // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol
    pragma solidity =0.5.12;
    
    ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.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.5.12; */
    
    contract LibNote {
        event LogNote(
            bytes4   indexed  sig,
            address  indexed  usr,
            bytes32  indexed  arg1,
            bytes32  indexed  arg2,
            bytes             data
        ) anonymous;
    
        modifier note {
            _;
            assembly {
                // log an 'anonymous' event with a constant 6 words of calldata
                // and four indexed topics: selector, caller, arg1 and arg2
                let mark := msize                         // end of memory ensures zero
                mstore(0x40, add(mark, 288))              // update free memory pointer
                mstore(mark, 0x20)                        // bytes type data offset
                mstore(add(mark, 0x20), 224)              // bytes size (padded)
                calldatacopy(add(mark, 0x40), 0, 224)     // bytes payload
                log4(mark, 288,                           // calldata
                     shl(224, shr(224, calldataload(0))), // msg.sig
                     caller,                              // msg.sender
                     calldataload(4),                     // arg1
                     calldataload(36)                     // arg2
                    )
            }
        }
    }
    
    ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol
    // Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico
    
    // 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.5.12; */
    
    /* import "./lib.sol"; */
    
    contract Dai is LibNote {
        // --- Auth ---
        mapping (address => uint) public wards;
        function rely(address guy) external note auth { wards[guy] = 1; }
        function deny(address guy) external note auth { wards[guy] = 0; }
        modifier auth {
            require(wards[msg.sender] == 1, "Dai/not-authorized");
            _;
        }
    
        // --- ERC20 Data ---
        string  public constant name     = "Dai Stablecoin";
        string  public constant symbol   = "DAI";
        string  public constant version  = "1";
        uint8   public constant decimals = 18;
        uint256 public totalSupply;
    
        mapping (address => uint)                      public balanceOf;
        mapping (address => mapping (address => uint)) public allowance;
        mapping (address => uint)                      public nonces;
    
        event Approval(address indexed src, address indexed guy, uint wad);
        event Transfer(address indexed src, address indexed dst, uint wad);
    
        // --- Math ---
        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);
        }
    
        // --- EIP712 niceties ---
        bytes32 public DOMAIN_SEPARATOR;
        // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)");
        bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb;
    
        constructor(uint256 chainId_) public {
            wards[msg.sender] = 1;
            DOMAIN_SEPARATOR = keccak256(abi.encode(
                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                keccak256(bytes(name)),
                keccak256(bytes(version)),
                chainId_,
                address(this)
            ));
        }
    
        // --- Token ---
        function transfer(address dst, uint wad) external returns (bool) {
            return transferFrom(msg.sender, dst, wad);
        }
        function transferFrom(address src, address dst, uint wad)
            public returns (bool)
        {
            require(balanceOf[src] >= wad, "Dai/insufficient-balance");
            if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
                require(allowance[src][msg.sender] >= wad, "Dai/insufficient-allowance");
                allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
            }
            balanceOf[src] = sub(balanceOf[src], wad);
            balanceOf[dst] = add(balanceOf[dst], wad);
            emit Transfer(src, dst, wad);
            return true;
        }
        function mint(address usr, uint wad) external auth {
            balanceOf[usr] = add(balanceOf[usr], wad);
            totalSupply    = add(totalSupply, wad);
            emit Transfer(address(0), usr, wad);
        }
        function burn(address usr, uint wad) external {
            require(balanceOf[usr] >= wad, "Dai/insufficient-balance");
            if (usr != msg.sender && allowance[usr][msg.sender] != uint(-1)) {
                require(allowance[usr][msg.sender] >= wad, "Dai/insufficient-allowance");
                allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad);
            }
            balanceOf[usr] = sub(balanceOf[usr], wad);
            totalSupply    = sub(totalSupply, wad);
            emit Transfer(usr, address(0), wad);
        }
        function approve(address usr, uint wad) external returns (bool) {
            allowance[msg.sender][usr] = wad;
            emit Approval(msg.sender, usr, wad);
            return true;
        }
    
        // --- Alias ---
        function push(address usr, uint wad) external {
            transferFrom(msg.sender, usr, wad);
        }
        function pull(address usr, uint wad) external {
            transferFrom(usr, msg.sender, wad);
        }
        function move(address src, address dst, uint wad) external {
            transferFrom(src, dst, wad);
        }
    
        // --- Approve by signature ---
        function permit(address holder, address spender, uint256 nonce, uint256 expiry,
                        bool allowed, uint8 v, bytes32 r, bytes32 s) external
        {
            bytes32 digest =
                keccak256(abi.encodePacked(
                    "\x19\x01",
                    DOMAIN_SEPARATOR,
                    keccak256(abi.encode(PERMIT_TYPEHASH,
                                         holder,
                                         spender,
                                         nonce,
                                         expiry,
                                         allowed))
            ));
    
            require(holder != address(0), "Dai/invalid-address-0");
            require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit");
            require(expiry == 0 || now <= expiry, "Dai/permit-expired");
            require(nonce == nonces[holder]++, "Dai/invalid-nonce");
            uint wad = allowed ? uint(-1) : 0;
            allowance[holder][spender] = wad;
            emit Approval(holder, spender, wad);
        }
    }