diff --git a/src/pools/D3M4626TypePool.sol b/src/pools/D3M4626TypePool.sol index 5a287b02..1949b7ca 100644 --- a/src/pools/D3M4626TypePool.sol +++ b/src/pools/D3M4626TypePool.sol @@ -25,6 +25,15 @@ interface VatLike { function nope(address) external; } +interface D3mHubLike { + function vat() external view returns (address); + function end() external view returns (EndLike); +} + +interface EndLike { + function Art(bytes32) external view returns (uint256); +} + contract D3M4626TypePool is ID3MPool { /* EVENTS */ @@ -37,23 +46,28 @@ contract D3M4626TypePool is ID3MPool { IERC20 public immutable dai; IERC4626 public immutable vault; VatLike public immutable vat; + bytes32 public immutable ilk; /* STORAGE */ address public hub; + uint256 public exited; mapping(address => uint256) public wards; /* CONSTRUCTOR */ - constructor(address newDai, address newVault, address newVat) { - require(newDai != address(0), "D3M4626TypePool/zero-address"); - require(newVat != address(0), "D3M4626TypePool/zero-address"); - require(newVault != address(0), "D3M4626TypePool/zero-address"); - require(IERC4626(newVault).asset() == address(newDai), "D3M4626TypePool/vault-asset-is-not-dai"); + constructor(bytes32 ilk_, address hub_, address dai_, address vault_) { + require(ilk_ != bytes32(0), "D3M4626TypePool/zero-bytes32"); + require(hub_ != address(0), "D3M4626TypePool/zero-address"); + require(dai_ != address(0), "D3M4626TypePool/zero-address"); + require(vault_ != address(0), "D3M4626TypePool/zero-address"); + require(IERC4626(vault_).asset() == dai_, "D3M4626TypePool/vault-asset-is-not-dai"); - dai = IERC20(newDai); - vault = IERC4626(newVault); - vat = VatLike(newVat); + ilk = ilk_; + hub = hub_; + dai = IERC20(dai_); + vault = IERC4626(vault_); + vat = VatLike(D3mHubLike(hub).vat()); wards[msg.sender] = 1; emit Rely(msg.sender); @@ -64,7 +78,7 @@ contract D3M4626TypePool is ID3MPool { /* MODIFIERS */ modifier onlyHub() { - require(msg.sender == hub, "D3M4626TypePool/only-hub"); + require(msg.sender == address(hub), "D3M4626TypePool/only-hub"); _; } @@ -76,20 +90,21 @@ contract D3M4626TypePool is ID3MPool { /* ONLY HUB */ /// @inheritdoc ID3MPool - function deposit(uint256 assets) external override onlyHub { - vault.deposit(assets, address(this)); + function deposit(uint256 wad) external override onlyHub { + vault.deposit(wad, address(this)); } /// @inheritdoc ID3MPool - function withdraw(uint256 assets) external override onlyHub { - vault.withdraw(assets, msg.sender, address(this)); + function withdraw(uint256 wad) external override onlyHub { + vault.withdraw(wad, msg.sender, address(this)); } /// @inheritdoc ID3MPool - /// @dev prop = 100 ether exists 100%. - function exit(address dst, uint256 prop) external onlyHub { - uint256 shares = prop * vault.balanceOf(address(this)) / 100 ether; - vault.transfer(dst, shares); + function exit(address dst, uint256 wad) external override onlyHub { + uint256 exited_ = exited; + exited = exited_ + wad; + uint256 amt = wad * vault.balanceOf(address(this)) / (D3mHubLike(hub).end().Art(ilk) - exited_); + require(vault.transfer(dst, amt), "D3M4626TypePool/transfer-failed"); } /* ONLY AUTHORIZED */ @@ -97,7 +112,7 @@ contract D3M4626TypePool is ID3MPool { /// @inheritdoc ID3MPool function quit(address dst) external auth { require(vat.live() == 1, "D3M4626TypePool/no-quit-during-shutdown"); - vault.transfer(dst, vault.balanceOf(address(this))); + require(vault.transfer(dst, vault.balanceOf(address(this))), "D3M4626TypePool/transfer-failed"); } function rely(address usr) public auth { diff --git a/src/tests/pools/D3M4626TypePool.t.sol b/src/tests/pools/D3M4626TypePool.t.sol index e2d9a7f6..995353cf 100644 --- a/src/tests/pools/D3M4626TypePool.t.sol +++ b/src/tests/pools/D3M4626TypePool.t.sol @@ -36,13 +36,14 @@ contract D3M4626TypePoolTest is D3MPoolBaseTest { D3M4626TypePool pool; ERC4626 vault; + bytes32 constant ILK = "TEST-ILK"; function setUp() public { baseInit("D3M4626TypePool"); vault = new ERC4626(ERC20(address(dai)), "dai vault", "DV"); - setPoolContract(pool = new D3M4626TypePool(address(dai), address(vault), address(vat))); + setPoolContract(pool = new D3M4626TypePool(ILK, address(hub), address(dai), address(vault))); pool.file("hub", address(hub)); @@ -61,6 +62,10 @@ contract D3M4626TypePoolTest is D3MPoolBaseTest { assertEq(address(pool.vat()), address(vat)); } + function invariant_ilk_value() public { + assertEq(pool.ilk(), ILK); + } + function test_cannot_file_hub_no_auth() public { pool.deny(address(this)); vm.expectRevert("D3M4626TypePool/not-authorized"); @@ -103,14 +108,16 @@ contract D3M4626TypePoolTest is D3MPoolBaseTest { function test_exit_adai() public { deal(address(dai), address(this), 1e18); vault.deposit(1e18, address(this)); - vault.transfer(address(pool), vault.balanceOf(address(this))); + uint256 tokens = vault.totalSupply(); + vault.transfer(address(pool), tokens); assertEq(vault.balanceOf(address(this)), 0); - assertEq(vault.balanceOf(address(pool)), 1e18); + assertEq(vault.balanceOf(address(pool)), tokens); - vm.prank(address(hub)); pool.exit(address(this), 1e18); + end.setArt(tokens); + vm.prank(address(hub)); pool.exit(address(this), tokens); - assertEq(vault.balanceOf(address(this)), 0.01e18); - assertEq(vault.balanceOf(address(pool)), 0.99e18); + assertEq(vault.balanceOf(address(this)), tokens); + assertEq(vault.balanceOf(address(pool)), 0); } function test_quit_moves_balance() public { diff --git a/src/tests/pools/D3MPoolBase.t.sol b/src/tests/pools/D3MPoolBase.t.sol index e9e106c9..af5ff6e2 100644 --- a/src/tests/pools/D3MPoolBase.t.sol +++ b/src/tests/pools/D3MPoolBase.t.sol @@ -110,16 +110,19 @@ abstract contract D3MPoolBaseTest is DssTest { end.setArt(100 ether); assertEq(redeemableToken.balanceOf(TEST_ADDRESS), 0); + assertEq(ExitLike(address(pool)).exited(), 0); vm.prank(address(hub)); pool.exit(TEST_ADDRESS, 10 ether); // Exit 10% assertApproxEqAbs(redeemableToken.balanceOf(TEST_ADDRESS), initialBalance * 10 / 100, 10); assertApproxEqAbs(redeemableToken.balanceOf(address(pool)), initialBalance * 90 / 100, 10); + assertEq(ExitLike(address(pool)).exited(), 10 ether); vm.prank(address(hub)); pool.exit(TEST_ADDRESS, 20 ether); // Exit another 20% assertApproxEqAbs(redeemableToken.balanceOf(TEST_ADDRESS), initialBalance * 30 / 100, 10); assertApproxEqAbs(redeemableToken.balanceOf(address(pool)), initialBalance * 70 / 100, 10); + assertEq(ExitLike(address(pool)).exited(), 30 ether); } }