// hevm: flattened sources of src/psm.sol
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.5.12 >=0.6.12 <0.7.0;
////// lib/dss-interfaces/src/dss/DaiAbstract.sol
/* pragma solidity >=0.5.12; */
// https://github.com/makerdao/dss/blob/master/src/dai.sol
interface DaiAbstract {
function wards(address) external view returns (uint256);
function rely(address) external;
function deny(address) external;
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function version() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address) external view returns (uint256);
function allowance(address, address) external view returns (uint256);
function nonces(address) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external view returns (bytes32);
function transfer(address, uint256) external;
function transferFrom(address, address, uint256) external returns (bool);
function mint(address, uint256) external;
function burn(address, uint256) external;
function approve(address, uint256) external returns (bool);
function push(address, uint256) external;
function pull(address, uint256) external;
function move(address, address, uint256) external;
function permit(address, address, uint256, uint256, bool, uint8, bytes32, bytes32) external;
}
////// lib/dss-interfaces/src/dss/DaiJoinAbstract.sol
/* pragma solidity >=0.5.12; */
// https://github.com/makerdao/dss/blob/master/src/join.sol
interface DaiJoinAbstract {
function wards(address) external view returns (uint256);
function rely(address usr) external;
function deny(address usr) external;
function vat() external view returns (address);
function dai() external view returns (address);
function live() external view returns (uint256);
function cage() external;
function join(address, uint256) external;
function exit(address, uint256) external;
}
////// lib/dss-interfaces/src/dss/VatAbstract.sol
/* pragma solidity >=0.5.12; */
// https://github.com/makerdao/dss/blob/master/src/vat.sol
interface VatAbstract {
function wards(address) external view returns (uint256);
function rely(address) external;
function deny(address) external;
function can(address, address) external view returns (uint256);
function hope(address) external;
function nope(address) external;
function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256);
function urns(bytes32, address) external view returns (uint256, uint256);
function gem(bytes32, address) external view returns (uint256);
function dai(address) external view returns (uint256);
function sin(address) external view returns (uint256);
function debt() external view returns (uint256);
function vice() external view returns (uint256);
function Line() external view returns (uint256);
function live() external view returns (uint256);
function init(bytes32) external;
function file(bytes32, uint256) external;
function file(bytes32, bytes32, uint256) external;
function cage() external;
function slip(bytes32, address, int256) external;
function flux(bytes32, address, address, uint256) external;
function move(address, address, uint256) external;
function frob(bytes32, address, address, address, int256, int256) external;
function fork(bytes32, address, address, int256, int256) external;
function grab(bytes32, address, address, address, int256, int256) external;
function heal(uint256) external;
function suck(address, address, uint256) external;
function fold(bytes32, address, int256) external;
}
////// src/psm.sol
// Copyright (C) 2021 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.6.12; */
/* import { DaiJoinAbstract } from "dss-interfaces/dss/DaiJoinAbstract.sol"; */
/* import { DaiAbstract } from "dss-interfaces/dss/DaiAbstract.sol"; */
/* import { VatAbstract } from "dss-interfaces/dss/VatAbstract.sol"; */
interface AuthGemJoinAbstract {
function dec() external view returns (uint256);
function vat() external view returns (address);
function ilk() external view returns (bytes32);
function join(address, uint256, address) external;
function exit(address, uint256) external;
}
// Peg Stability Module
// Allows anyone to go between Dai and the Gem by pooling the liquidity
// An optional fee is charged for incoming and outgoing transfers
contract DssPsm {
// --- Auth ---
mapping (address => uint256) public wards;
function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); }
function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); }
modifier auth { require(wards[msg.sender] == 1); _; }
VatAbstract immutable public vat;
AuthGemJoinAbstract immutable public gemJoin;
DaiAbstract immutable public dai;
DaiJoinAbstract immutable public daiJoin;
bytes32 immutable public ilk;
address immutable public vow;
uint256 immutable internal to18ConversionFactor;
uint256 public tin; // toll in [wad]
uint256 public tout; // toll out [wad]
// --- Events ---
event Rely(address indexed usr);
event Deny(address indexed usr);
event File(bytes32 indexed what, uint256 data);
event SellGem(address indexed owner, uint256 value, uint256 fee);
event BuyGem(address indexed owner, uint256 value, uint256 fee);
// --- Init ---
constructor(address gemJoin_, address daiJoin_, address vow_) public {
wards[msg.sender] = 1;
emit Rely(msg.sender);
AuthGemJoinAbstract gemJoin__ = gemJoin = AuthGemJoinAbstract(gemJoin_);
DaiJoinAbstract daiJoin__ = daiJoin = DaiJoinAbstract(daiJoin_);
VatAbstract vat__ = vat = VatAbstract(address(gemJoin__.vat()));
DaiAbstract dai__ = dai = DaiAbstract(address(daiJoin__.dai()));
ilk = gemJoin__.ilk();
vow = vow_;
to18ConversionFactor = 10 ** (18 - gemJoin__.dec());
dai__.approve(daiJoin_, uint256(-1));
vat__.hope(daiJoin_);
}
// --- Math ---
uint256 constant WAD = 10 ** 18;
uint256 constant RAY = 10 ** 27;
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x + y) >= x);
}
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x - y) <= x);
}
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x);
}
// --- Administration ---
function file(bytes32 what, uint256 data) external auth {
if (what == "tin") tin = data;
else if (what == "tout") tout = data;
else revert("DssPsm/file-unrecognized-param");
emit File(what, data);
}
// hope can be used to transfer control of the PSM vault to another contract
// This can be used to upgrade the contract
function hope(address usr) external auth {
vat.hope(usr);
}
function nope(address usr) external auth {
vat.nope(usr);
}
// --- Primary Functions ---
function sellGem(address usr, uint256 gemAmt) external {
uint256 gemAmt18 = mul(gemAmt, to18ConversionFactor);
uint256 fee = mul(gemAmt18, tin) / WAD;
uint256 daiAmt = sub(gemAmt18, fee);
gemJoin.join(address(this), gemAmt, msg.sender);
vat.frob(ilk, address(this), address(this), address(this), int256(gemAmt18), int256(gemAmt18));
vat.move(address(this), vow, mul(fee, RAY));
daiJoin.exit(usr, daiAmt);
emit SellGem(usr, gemAmt, fee);
}
function buyGem(address usr, uint256 gemAmt) external {
uint256 gemAmt18 = mul(gemAmt, to18ConversionFactor);
uint256 fee = mul(gemAmt18, tout) / WAD;
uint256 daiAmt = add(gemAmt18, fee);
require(dai.transferFrom(msg.sender, address(this), daiAmt), "DssPsm/failed-transfer");
daiJoin.join(address(this), daiAmt);
vat.frob(ilk, address(this), address(this), address(this), -int256(gemAmt18), -int256(gemAmt18));
gemJoin.exit(usr, gemAmt);
vat.move(address(this), vow, mul(fee, RAY));
emit BuyGem(usr, gemAmt, fee);
}
}
{
"compilationTarget": {
"DssPsm.sol": "DssPsm"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"gemJoin_","type":"address"},{"internalType":"address","name":"daiJoin_","type":"address"},{"internalType":"address","name":"vow_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"BuyGem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"usr","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"what","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"data","type":"uint256"}],"name":"File","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"usr","type":"address"}],"name":"Rely","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"SellGem","type":"event"},{"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"gemAmt","type":"uint256"}],"name":"buyGem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dai","outputs":[{"internalType":"contract DaiAbstract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"daiJoin","outputs":[{"internalType":"contract DaiJoinAbstract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"what","type":"bytes32"},{"internalType":"uint256","name":"data","type":"uint256"}],"name":"file","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gemJoin","outputs":[{"internalType":"contract AuthGemJoinAbstract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"}],"name":"hope","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ilk","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"}],"name":"nope","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"gemAmt","type":"uint256"}],"name":"sellGem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vat","outputs":[{"internalType":"contract VatAbstract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]