-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Supply Sync #16
base: master
Are you sure you want to change the base?
Supply Sync #16
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-or-later | ||
|
||
/// MkrSky.sol -- Mkr/Sky Exchanger | ||
|
||
// Copyright (C) 2023 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.21; | ||
|
||
interface GemLike { | ||
function totalSupply() external view returns (uint256); | ||
function balanceOf(address) external view returns (uint256); | ||
function approve(address, uint256) external; | ||
function mint(address, uint256) external; | ||
function burn(address, uint256) external; | ||
} | ||
|
||
contract SupplySync { | ||
GemLike public immutable mkr; | ||
GemLike public immutable sky; | ||
|
||
constructor(address mkr_, address sky_, address owner) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Considering the converter doesn't have the conversion value hardcoded, I wouldn't do it here. My suggestion would be to actually pass the converter as the constructor param, and then you have the 3 values. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok done |
||
mkr = GemLike(mkr_); | ||
sky = GemLike(sky_); | ||
|
||
// Allow owner (pause proxy) to burn the sky in this contract, if ever needed to wind down | ||
sky.approve(owner, type(uint256).max); | ||
} | ||
|
||
function sync() external { | ||
uint256 mkrSupplyInSky = mkr.totalSupply() * 24_000; | ||
uint256 skyBalance = sky.balanceOf(address(this)); | ||
|
||
unchecked { | ||
if (mkrSupplyInSky > skyBalance) { | ||
sky.mint(address(this), mkrSupplyInSky - skyBalance); | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I'd prefer an elseif, so we avoid to burn 0 if sync is called multiple times. But it is really a very subjective thing, not really important gas wise. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, changed to that and also added return values so it's easier to use it in a bot/cron-job. |
||
sky.burn(address(this), skyBalance - mkrSupplyInSky); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-or-later | ||
|
||
pragma solidity ^0.8.21; | ||
|
||
import "dss-test/DssTest.sol"; | ||
import { SupplySync } from "src/SupplySync.sol"; | ||
import { SkyDeploy } from "deploy/SkyDeploy.sol"; | ||
import { SkyInit } from "deploy/SkyInit.sol"; | ||
|
||
interface GemLike { | ||
function totalSupply() external view returns (uint256); | ||
function balanceOf(address) external view returns (uint256); | ||
function allowance(address, address) external view returns (uint256); | ||
function burn(address, uint256) external; | ||
} | ||
|
||
interface SkyLike is GemLike { | ||
function wards(address) external view returns (uint256); | ||
function rely(address) external; | ||
telome marked this conversation as resolved.
Show resolved
Hide resolved
|
||
function deny(address) external; | ||
} | ||
|
||
contract SupplySyncTest is DssTest { | ||
DssInstance dss; | ||
|
||
address PAUSE_PROXY; | ||
GemLike MKR; | ||
SkyLike SKY; | ||
|
||
SupplySync sync; | ||
|
||
function setUp() public { | ||
vm.createSelectFork(vm.envString("ETH_RPC_URL")); | ||
|
||
dss = MCD.loadFromChainlog(0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F); | ||
|
||
PAUSE_PROXY = dss.chainlog.getAddress("MCD_PAUSE_PROXY"); | ||
MKR = GemLike(dss.chainlog.getAddress("MCD_GOV")); | ||
SKY = SkyLike(dss.chainlog.getAddress("SKY")); | ||
|
||
sync = SupplySync(SkyDeploy.deploySupplySync(address(MKR), address(SKY), PAUSE_PROXY)); | ||
vm.startPrank(PAUSE_PROXY); | ||
SkyInit.initSupplySync(dss, address(sync)); | ||
vm.stopPrank(); | ||
} | ||
|
||
function testDeployAndInit() public { | ||
assertEq(address(sync.mkr()), address(MKR)); | ||
assertEq(address(sync.sky()), address(SKY)); | ||
assertEq(SKY.allowance(address(sync), PAUSE_PROXY), type(uint256).max); | ||
assertEq(SKY.wards(address(sync)), 1); | ||
assertEq(dss.chainlog.getAddress("SKY_SUPPLY_SYNC"), address(sync)); | ||
} | ||
|
||
function _checkSync(bool isExpectedMint, uint256 expectedChange) internal { | ||
uint256 mkrSupply = MKR.totalSupply(); | ||
uint256 skySupplyBefore = SKY.totalSupply(); | ||
uint256 syncBalanceBefore = SKY.balanceOf(address(sync)); | ||
|
||
sync.sync(); | ||
|
||
uint256 syncBalanceAfter = SKY.balanceOf(address(sync)); | ||
|
||
assertEq(syncBalanceAfter, mkrSupply * 24_000); | ||
if (isExpectedMint) { | ||
assertEq(syncBalanceAfter, syncBalanceBefore + expectedChange); | ||
assertEq(SKY.totalSupply(), skySupplyBefore + expectedChange); | ||
} else { | ||
assertEq(syncBalanceAfter, syncBalanceBefore - expectedChange); | ||
assertEq(SKY.totalSupply(), skySupplyBefore - expectedChange); | ||
} | ||
} | ||
|
||
function testSZeroSkyInSync() public { | ||
oldchili marked this conversation as resolved.
Show resolved
Hide resolved
|
||
deal(address(SKY), address(sync), 0); | ||
_checkSync(true, MKR.totalSupply() * 24_000); | ||
} | ||
|
||
function testLessSkyInSync() public { | ||
deal(address(SKY), address(sync), MKR.totalSupply() * 24_000 - 1234); | ||
_checkSync(true, 1234); | ||
} | ||
|
||
function testMoreSkyInSync() public { | ||
deal(address(SKY), address(sync), MKR.totalSupply() * 24_000 + 1234); | ||
_checkSync(false, 1234); | ||
} | ||
|
||
function testExactSkyInSync() public { | ||
deal(address(SKY), address(sync), MKR.totalSupply() * 24_000); | ||
_checkSync(true, 0); | ||
} | ||
|
||
function testWindDown() public { | ||
deal(address(SKY), address(sync), 1234); | ||
|
||
vm.startPrank(PAUSE_PROXY); | ||
SKY.burn(address(sync), SKY.balanceOf(address(sync))); | ||
SKY.deny(address(sync)); // revoke mint allowance | ||
vm.stopPrank(); | ||
|
||
assertEq(SKY.balanceOf(address(sync)), 0); | ||
vm.expectRevert("Sky/not-authorized"); | ||
sync.sync(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shoulde be 2024
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done