Skip to content

Commit 0780c50

Browse files
committed
Add Kicker
1 parent e136bb1 commit 0780c50

File tree

4 files changed

+622
-0
lines changed

4 files changed

+622
-0
lines changed

deploy/FlapperDeploy.sol

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
pragma solidity ^0.8.21;
1818

1919
import "dss-interfaces/Interfaces.sol";
20+
import { MCD, DssInstance } from "dss-test/MCD.sol";
2021
import { ScriptTools } from "dss-test/ScriptTools.sol";
2122

2223
import { SplitterInstance } from "./SplitterInstance.sol";
@@ -25,9 +26,12 @@ import { FlapperUniV2SwapOnly } from "src/FlapperUniV2SwapOnly.sol";
2526
import { SplitterMom } from "src/SplitterMom.sol";
2627
import { OracleWrapper } from "src/OracleWrapper.sol";
2728
import { Splitter } from "src/Splitter.sol";
29+
import { Kicker } from "src/Kicker.sol";
2830

2931
library FlapperDeploy {
3032

33+
address constant LOG = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F;
34+
3135
function deployFlapperUniV2(
3236
address deployer,
3337
address owner,
@@ -68,4 +72,18 @@ library FlapperDeploy {
6872
splitterInstance.splitter = splitter;
6973
splitterInstance.mom = mom;
7074
}
75+
76+
function deployKicker(
77+
address deployer,
78+
address owner
79+
) internal returns (address kicker) {
80+
DssInstance memory dss = MCD.loadFromChainlog(LOG);
81+
82+
kicker = address(new Kicker(
83+
dss.chainlog.getAddress("MCD_VAT"),
84+
dss.chainlog.getAddress("MCD_VOW"),
85+
dss.chainlog.getAddress("MCD_SPLIT")));
86+
87+
ScriptTools.switchOwner(kicker, deployer, owner);
88+
}
7189
}

deploy/FlapperInit.sol

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ interface SplitterLike {
6060
function usdsJoin() external view returns (address);
6161
function hop() external view returns (uint256);
6262
function rely(address) external;
63+
function deny(address) external;
6364
function file(bytes32, uint256) external;
6465
function file(bytes32, address) external;
6566
}
@@ -70,6 +71,11 @@ interface FarmLike {
7071
function setRewardsDuration(uint256) external;
7172
}
7273

74+
interface KickerLike {
75+
function file(bytes32, uint256) external;
76+
function file(bytes32, int256) external;
77+
}
78+
7379
struct FlapperUniV2Config {
7480
uint256 want;
7581
address pip;
@@ -99,6 +105,12 @@ struct SplitterConfig {
99105
bytes32 momChainlogKey;
100106
}
101107

108+
struct KickerConfig {
109+
int256 khump;
110+
uint256 kbump;
111+
bytes32 chainlogKey;
112+
}
113+
102114
library FlapperInit {
103115
uint256 constant WAD = 10 ** 18;
104116
uint256 constant RAY = 10 ** 27;
@@ -208,4 +220,26 @@ library FlapperInit {
208220
if (cfg.prevMomChainlogKey != bytes32(0)) dss.chainlog.removeAddress(cfg.prevMomChainlogKey);
209221
dss.chainlog.setAddress(cfg.momChainlogKey, address(mom));
210222
}
223+
224+
function initKicker(
225+
DssInstance memory dss,
226+
address kicker,
227+
KickerConfig memory cfg
228+
) internal {
229+
require(cfg.kbump % RAY == 0, "kbump not multiple of RAY");
230+
231+
address vow = dss.chainlog.getAddress("MCD_VOW");
232+
SplitterLike splitter = SplitterLike(dss.chainlog.getAddress("MCD_SPLIT"));
233+
234+
// vow.file(vow)
235+
236+
KickerLike(kicker).file("khump", cfg.khump);
237+
KickerLike(kicker).file("kbump", cfg.kbump);
238+
239+
dss.vat.rely(kicker);
240+
SplitterLike(splitter).rely(kicker);
241+
SplitterLike(splitter).deny(address(vow));
242+
243+
dss.chainlog.setAddress(cfg.chainlogKey, kicker);
244+
}
211245
}

src/Kicker.sol

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// SPDX-FileCopyrightText: © 2025 Dai Foundation <www.daifoundation.org>
2+
// SPDX-License-Identifier: AGPL-3.0-or-later
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
pragma solidity ^0.8.21;
18+
19+
interface VatLike {
20+
function dai(address) external view returns (uint256);
21+
function sin(address) external view returns (uint256);
22+
function hope(address) external;
23+
function suck(address, address, uint256) external;
24+
}
25+
26+
interface VowLike {
27+
function Sin() external view returns (uint256);
28+
function Ash() external view returns (uint256);
29+
}
30+
31+
interface SplitterLike {
32+
function kick(uint256, uint256) external returns (uint256);
33+
}
34+
35+
contract Kicker {
36+
// --- storage variables ---
37+
38+
mapping(address usr => uint256 allowed) public wards;
39+
uint256 public kbump;
40+
int256 public khump;
41+
42+
// --- immutables ---
43+
44+
VatLike public immutable vat;
45+
VowLike public immutable vow;
46+
SplitterLike public immutable splitter;
47+
48+
// --- immutables ---
49+
50+
constructor(address vat_, address vow_, address splitter_) {
51+
vat = VatLike(vat_);
52+
vow = VowLike(vow_);
53+
splitter = SplitterLike(splitter_);
54+
vat.hope(splitter_);
55+
56+
wards[msg.sender] = 1;
57+
emit Rely(msg.sender);
58+
}
59+
60+
// --- events ---
61+
62+
event Rely(address indexed usr);
63+
event Deny(address indexed usr);
64+
event File(bytes32 indexed what, uint256 data);
65+
event File(bytes32 indexed what, int256 data);
66+
67+
// --- modifiers ---
68+
69+
modifier auth {
70+
require(wards[msg.sender] == 1, "Kicker/not-authorized");
71+
_;
72+
}
73+
74+
// --- internals ---
75+
76+
function _toInt256(uint256 x) internal pure returns (int256 y) {
77+
require(x <= uint256(type(int256).max), "Kicker/overflow");
78+
y = int256(x);
79+
}
80+
81+
// --- administration ---
82+
83+
function rely(address usr) external auth {
84+
wards[usr] = 1;
85+
emit Rely(usr);
86+
}
87+
88+
function deny(address usr) external auth {
89+
wards[usr] = 0;
90+
emit Deny(usr);
91+
}
92+
93+
function file(bytes32 what, uint256 data) external auth {
94+
if (what == "kbump") {
95+
kbump = data;
96+
} else revert("Kicker/file-unrecognized-param");
97+
emit File(what, data);
98+
}
99+
100+
function file(bytes32 what, int256 data) external auth {
101+
if (what == "khump") {
102+
khump = data;
103+
} else revert("Kicker/file-unrecognized-param");
104+
emit File(what, data);
105+
}
106+
107+
// --- execution ---
108+
109+
function flap() external returns (uint256 id) {
110+
require(_toInt256(vat.dai(address(vow))) >= _toInt256(vat.sin(address(vow))) + _toInt256(kbump) + khump, "Kicker/insufficient-allowance");
111+
// require(vat.sin(address(vow)) - vow.Sin() - vow.Ash() == 0 || vat.dai(address(vow)) == 0 , "Kicker/not-healed");
112+
vat.suck(address(vow), address(this), kbump);
113+
id = splitter.kick(kbump, 0);
114+
}
115+
}

0 commit comments

Comments
 (0)