Transaction Hash:
Block:
19585347 at Apr-04-2024 10:23:11 PM +UTC
Transaction Fee:
0.003041208555094406 ETH
$7.56
Gas Used:
162,842 Gas / 18.675824143 Gwei
Emitted Events:
307 |
Vat.0xf24e23eb00000000000000000000000000000000000000000000000000000000( 0xf24e23eb00000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000a950524441892a31ebddf91d3ceefa04bf454466, 0x000000000000000000000000197e90f9fad81970ba7976f33cbd77088e5d7cf7, 0x000000000000000000000001146c5d279e9eaa88145a336cbb9c8b4f4dd91b54, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, f24e23eb000000000000000000000000a950524441892a31ebddf91d3ceefa04, bf454466000000000000000000000000197e90f9fad81970ba7976f33cbd7708, 8e5d7cf7000000000000000000000001146c5d279e9eaa88145a336cbb9c8b4f, 4dd91b5400000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
308 |
Pot.0x9f678cca00000000000000000000000000000000000000000000000000000000( 0x9f678cca00000000000000000000000000000000000000000000000000000000, 0x00000000000000000000000083f20f44975d03b1b09e64809b757c47f942beea, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 9f678cca00000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
309 |
Vat.0xbb35783b00000000000000000000000000000000000000000000000000000000( 0xbb35783b00000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000197e90f9fad81970ba7976f33cbd77088e5d7cf7, 0x00000000000000000000000083f20f44975d03b1b09e64809b757c47f942beea, 0x000000000000000000000130e39b2aaa9154605a4cb4ab6c9ced0136d1080dfe, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, bb35783b000000000000000000000000197e90f9fad81970ba7976f33cbd7708, 8e5d7cf700000000000000000000000083f20f44975d03b1b09e64809b757c47, f942beea000000000000000000000130e39b2aaa9154605a4cb4ab6c9ced0136, d1080dfe00000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
310 |
Pot.0x7f8661a100000000000000000000000000000000000000000000000000000000( 0x7f8661a100000000000000000000000000000000000000000000000000000000, 0x00000000000000000000000083f20f44975d03b1b09e64809b757c47f942beea, 0x00000000000000000000000000000000000000000000583fff864b2431f2f2ba, 0x0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 7f8661a100000000000000000000000000000000000000000000583fff864b24, 31f2f2ba00000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
311 |
Vat.0xbb35783b00000000000000000000000000000000000000000000000000000000( 0xbb35783b00000000000000000000000000000000000000000000000000000000, 0x00000000000000000000000083f20f44975d03b1b09e64809b757c47f942beea, 0x0000000000000000000000009759a6ac90977b93b58547b4a71c78317f391a28, 0x000000000000000000000130e39b2aaa9154605a4b2c47a1bb2ea8f820000000, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, bb35783b00000000000000000000000083f20f44975d03b1b09e64809b757c47, f942beea0000000000000000000000009759a6ac90977b93b58547b4a71c7831, 7f391a28000000000000000000000130e39b2aaa9154605a4b2c47a1bb2ea8f8, 2000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
312 |
Dai.Transfer( src=0x0000000000000000000000000000000000000000, dst=[Sender] 0xd7925984736824b4aecf8301c9aee211cd976494, wad=445595898985834458629588 )
|
313 |
DaiJoin.0xef693bed00000000000000000000000000000000000000000000000000000000( 0xef693bed00000000000000000000000000000000000000000000000000000000, 0x00000000000000000000000083f20f44975d03b1b09e64809b757c47f942beea, 0x000000000000000000000000d7925984736824b4aecf8301c9aee211cd976494, 0x000000000000000000000000000000000000000000005e5bcd558b5c828fc5d4, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, ef693bed000000000000000000000000d7925984736824b4aecf8301c9aee211, cd976494000000000000000000000000000000000000000000005e5bcd558b5c, 828fc5d400000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
314 |
SavingsDai.Withdraw( sender=[Sender] 0xd7925984736824b4aecf8301c9aee211cd976494, receiver=[Sender] 0xd7925984736824b4aecf8301c9aee211cd976494, owner=[Sender] 0xd7925984736824b4aecf8301c9aee211cd976494, assets=445595898985834458629588, shares=416748807855917860319930 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x197E90f9...88E5D7cf7 | (Sky: MCD Pot) | ||||
0x35D1b3F3...259A0492B | (Sky: MCD Vat) | ||||
0x6B175474...495271d0F | |||||
0x83F20F44...7f942BEeA | |||||
0x95222290...5CC4BAfe5
Miner
| (beaverbuild) | 9.937239822552872642 Eth | 9.937251712272605922 Eth | 0.00001188971973328 | |
0xD7925984...1Cd976494 |
1.2438254185821555 Eth
Nonce: 2052
|
1.240784210027061094 Eth
Nonce: 2053
| 0.003041208555094406 |
Execution Trace
SavingsDai.redeem( shares=416748807855917860319930, receiver=0xD7925984736824B4Aecf8301c9aEE211Cd976494, owner=0xD7925984736824B4Aecf8301c9aEE211Cd976494 ) => ( assets=445595898985834458629588 )
File 1 of 5: SavingsDai
File 2 of 5: Vat
File 3 of 5: Pot
File 4 of 5: Dai
File 5 of 5: DaiJoin
// SPDX-License-Identifier: AGPL-3.0-or-later /// SavingsDai.sol -- A tokenized representation DAI in the DSR (pot) // Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico // Copyright (C) 2021-2022 Dai Foundation // // 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.8.17; interface IERC1271 { function isValidSignature( bytes32, bytes memory ) external view returns (bytes4); } interface VatLike { function hope(address) external; } interface PotLike { function chi() external view returns (uint256); function rho() external view returns (uint256); function dsr() external view returns (uint256); function drip() external returns (uint256); function join(uint256) external; function exit(uint256) external; } interface DaiJoinLike { function vat() external view returns (address); function dai() external view returns (address); function join(address, uint256) external; function exit(address, uint256) external; } interface DaiLike { function transferFrom(address, address, uint256) external returns (bool); function approve(address, uint256) external returns (bool); } contract SavingsDai { // --- ERC20 Data --- string public constant name = "Savings Dai"; string public constant symbol = "sDAI"; string public constant version = "1"; uint8 public constant decimals = 18; uint256 public totalSupply; mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint256)) public allowance; mapping (address => uint256) public nonces; // --- Data --- VatLike public immutable vat; DaiJoinLike public immutable daiJoin; DaiLike public immutable dai; PotLike public immutable pot; // --- Events --- event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw(address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares); // --- EIP712 niceties --- uint256 public immutable deploymentChainId; bytes32 private immutable _DOMAIN_SEPARATOR; bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); uint256 private constant RAY = 10 ** 27; constructor(address _daiJoin, address _pot) { daiJoin = DaiJoinLike(_daiJoin); vat = VatLike(daiJoin.vat()); dai = DaiLike(daiJoin.dai()); pot = PotLike(_pot); deploymentChainId = block.chainid; _DOMAIN_SEPARATOR = _calculateDomainSeparator(block.chainid); vat.hope(address(daiJoin)); vat.hope(address(pot)); dai.approve(address(daiJoin), type(uint256).max); } function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256(bytes(version)), chainId, address(this) ) ); } function DOMAIN_SEPARATOR() external view returns (bytes32) { return block.chainid == deploymentChainId ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(block.chainid); } function _rpow(uint256 x, uint256 n) internal pure returns (uint256 z) { assembly { switch x case 0 {switch n case 0 {z := RAY} default {z := 0}} default { switch mod(n, 2) case 0 { z := RAY } default { z := x } let half := div(RAY, 2) // for rounding. for { n := div(n, 2) } n { n := div(n,2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0,0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0,0) } x := div(xxRound, RAY) if mod(n,2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0,0) } z := div(zxRound, RAY) } } } } } function _divup(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x != 0 ? ((x - 1) / y) + 1 : 0; } } // --- ERC20 Mutations --- function transfer(address to, uint256 value) external returns (bool) { require(to != address(0) && to != address(this), "SavingsDai/invalid-address"); uint256 balance = balanceOf[msg.sender]; require(balance >= value, "SavingsDai/insufficient-balance"); unchecked { balanceOf[msg.sender] = balance - value; balanceOf[to] += value; } emit Transfer(msg.sender, to, value); return true; } function transferFrom(address from, address to, uint256 value) external returns (bool) { require(to != address(0) && to != address(this), "SavingsDai/invalid-address"); uint256 balance = balanceOf[from]; require(balance >= value, "SavingsDai/insufficient-balance"); if (from != msg.sender) { uint256 allowed = allowance[from][msg.sender]; if (allowed != type(uint256).max) { require(allowed >= value, "SavingsDai/insufficient-allowance"); unchecked { allowance[from][msg.sender] = allowed - value; } } } unchecked { balanceOf[from] = balance - value; balanceOf[to] += value; } emit Transfer(from, to, value); return true; } function approve(address spender, uint256 value) external returns (bool) { allowance[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } function increaseAllowance(address spender, uint256 addedValue) external returns (bool) { uint256 newValue = allowance[msg.sender][spender] + addedValue; allowance[msg.sender][spender] = newValue; emit Approval(msg.sender, spender, newValue); return true; } function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool) { uint256 allowed = allowance[msg.sender][spender]; require(allowed >= subtractedValue, "SavingsDai/insufficient-allowance"); unchecked{ allowed = allowed - subtractedValue; } allowance[msg.sender][spender] = allowed; emit Approval(msg.sender, spender, allowed); return true; } // --- Mint/Burn Internal --- function _mint(uint256 assets, uint256 shares, address receiver) internal { require(receiver != address(0) && receiver != address(this), "SavingsDai/invalid-address"); dai.transferFrom(msg.sender, address(this), assets); daiJoin.join(address(this), assets); pot.join(shares); // note: we don't need an overflow check here b/c shares totalSupply will always be <= dai totalSupply unchecked { balanceOf[receiver] = balanceOf[receiver] + shares; totalSupply = totalSupply + shares; } emit Deposit(msg.sender, receiver, assets, shares); } function _burn(uint256 assets, uint256 shares, address receiver, address owner) internal { uint256 balance = balanceOf[owner]; require(balance >= shares, "SavingsDai/insufficient-balance"); if (owner != msg.sender) { uint256 allowed = allowance[owner][msg.sender]; if (allowed != type(uint256).max) { require(allowed >= shares, "SavingsDai/insufficient-allowance"); unchecked { allowance[owner][msg.sender] = allowed - shares; } } } unchecked { balanceOf[owner] = balance - shares; // note: we don't need overflow checks b/c require(balance >= value) and balance <= totalSupply totalSupply = totalSupply - shares; } pot.exit(shares); daiJoin.exit(receiver, assets); emit Withdraw(msg.sender, receiver, owner, assets, shares); } // --- ERC-4626 --- function asset() external view returns (address) { return address(dai); } function totalAssets() external view returns (uint256) { return convertToAssets(totalSupply); } function convertToShares(uint256 assets) public view returns (uint256) { uint256 rho = pot.rho(); uint256 chi = (block.timestamp > rho) ? _rpow(pot.dsr(), block.timestamp - rho) * pot.chi() / RAY : pot.chi(); return assets * RAY / chi; } function convertToAssets(uint256 shares) public view returns (uint256) { uint256 rho = pot.rho(); uint256 chi = (block.timestamp > rho) ? _rpow(pot.dsr(), block.timestamp - rho) * pot.chi() / RAY : pot.chi(); return shares * chi / RAY; } function maxDeposit(address) external pure returns (uint256) { return type(uint256).max; } function previewDeposit(uint256 assets) external view returns (uint256) { return convertToShares(assets); } function deposit(uint256 assets, address receiver) external returns (uint256 shares) { uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi(); shares = assets * RAY / chi; _mint(assets, shares, receiver); } function maxMint(address) external pure returns (uint256) { return type(uint256).max; } function previewMint(uint256 shares) external view returns (uint256) { uint256 rho = pot.rho(); uint256 chi = (block.timestamp > rho) ? _rpow(pot.dsr(), block.timestamp - rho) * pot.chi() / RAY : pot.chi(); return _divup(shares * chi, RAY); } function mint(uint256 shares, address receiver) external returns (uint256 assets) { uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi(); assets = _divup(shares * chi, RAY); _mint(assets, shares, receiver); } function maxWithdraw(address owner) external view returns (uint256) { return convertToAssets(balanceOf[owner]); } function previewWithdraw(uint256 assets) external view returns (uint256) { uint256 rho = pot.rho(); uint256 chi = (block.timestamp > rho) ? _rpow(pot.dsr(), block.timestamp - rho) * pot.chi() / RAY : pot.chi(); return _divup(assets * RAY, chi); } function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares) { uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi(); shares = _divup(assets * RAY, chi); _burn(assets, shares, receiver, owner); } function maxRedeem(address owner) external view returns (uint256) { return balanceOf[owner]; } function previewRedeem(uint256 shares) external view returns (uint256) { return convertToAssets(shares); } function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets) { uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi(); assets = shares * chi / RAY; _burn(assets, shares, receiver, owner); } // --- Approve by signature --- function _isValidSignature( address signer, bytes32 digest, bytes memory signature ) internal view returns (bool) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } if (signer == ecrecover(digest, v, r, s)) { return true; } } (bool success, bytes memory result) = signer.staticcall( abi.encodeWithSelector(IERC1271.isValidSignature.selector, digest, signature) ); return (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector); } function permit( address owner, address spender, uint256 value, uint256 deadline, bytes memory signature ) public { require(block.timestamp <= deadline, "SavingsDai/permit-expired"); require(owner != address(0), "SavingsDai/invalid-owner"); uint256 nonce; unchecked { nonce = nonces[owner]++; } bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", block.chainid == deploymentChainId ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(block.chainid), keccak256(abi.encode( PERMIT_TYPEHASH, owner, spender, value, nonce, deadline )) )); require(_isValidSignature(owner, digest, signature), "SavingsDai/invalid-permit"); allowance[owner][spender] = value; emit Approval(owner, spender, value); } function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external { permit(owner, spender, value, deadline, abi.encodePacked(r, s, v)); } }
File 2 of 5: 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 5: Pot
// hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/pot.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/pot.sol /// pot.sol -- Dai Savings Rate // 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"; */ /* "Savings Dai" is obtained when Dai is deposited into this contract. Each "Savings Dai" accrues Dai interest at the "Dai Savings Rate". This contract does not implement a user tradeable token and is intended to be used with adapters. --- `save` your `dai` in the `pot` --- - `dsr`: the Dai Savings Rate - `pie`: user balance of Savings Dai - `join`: start saving some dai - `exit`: remove some dai - `drip`: perform rate collection */ contract VatLike { function move(address,address,uint256) external; function suck(address,address,uint256) external; } contract Pot 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, "Pot/not-authorized"); _; } // --- Data --- mapping (address => uint256) public pie; // user Savings Dai uint256 public Pie; // total Savings Dai uint256 public dsr; // the Dai Savings Rate uint256 public chi; // the Rate Accumulator VatLike public vat; // CDP engine address public vow; // debt engine uint256 public rho; // time of last drip uint256 public live; // Access Flag // --- Init --- constructor(address vat_) public { wards[msg.sender] = 1; vat = VatLike(vat_); dsr = ONE; chi = ONE; rho = now; live = 1; } // --- Math --- uint256 constant ONE = 10 ** 27; function rpow(uint x, uint n, uint base) internal pure returns (uint z) { assembly { switch x case 0 {switch n case 0 {z := base} default {z := 0}} default { switch mod(n, 2) case 0 { z := base } default { z := x } let half := div(base, 2) // for rounding. for { n := div(n, 2) } n { n := div(n,2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0,0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0,0) } x := div(xxRound, base) if mod(n,2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0,0) } z := div(zxRound, base) } } } } } function rmul(uint x, uint y) internal pure returns (uint z) { z = mul(x, y) / ONE; } 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 file(bytes32 what, uint256 data) external note auth { require(live == 1, "Pot/not-live"); require(now == rho, "Pot/rho-not-updated"); if (what == "dsr") dsr = data; else revert("Pot/file-unrecognized-param"); } function file(bytes32 what, address addr) external note auth { if (what == "vow") vow = addr; else revert("Pot/file-unrecognized-param"); } function cage() external note auth { live = 0; dsr = ONE; } // --- Savings Rate Accumulation --- function drip() external note returns (uint tmp) { require(now >= rho, "Pot/invalid-now"); tmp = rmul(rpow(dsr, now - rho, ONE), chi); uint chi_ = sub(tmp, chi); chi = tmp; rho = now; vat.suck(address(vow), address(this), mul(Pie, chi_)); } // --- Savings Dai Management --- function join(uint wad) external note { require(now == rho, "Pot/rho-not-updated"); pie[msg.sender] = add(pie[msg.sender], wad); Pie = add(Pie, wad); vat.move(msg.sender, address(this), mul(chi, wad)); } function exit(uint wad) external note { pie[msg.sender] = sub(pie[msg.sender], wad); Pie = sub(Pie, wad); vat.move(address(this), msg.sender, mul(chi, wad)); } }
File 4 of 5: 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); } }
File 5 of 5: 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); } }