From d06adbf07c759987b89779d1fa65e31f22924f7b Mon Sep 17 00:00:00 2001 From: 0xp3th1um <0xp3th1um@dewiz.xyz> Date: Tue, 4 Feb 2025 13:27:22 +0200 Subject: [PATCH] feat: add contracts and tests --- .gitmodules | 3 ++ script/Counter.s.sol | 19 ----------- script/DeepStack.s.sol | 21 ++++++++++++ src/Counter.sol | 14 -------- src/DeepStack.sol | 46 +++++++++++++++++++++++++ test/Counter.t.sol | 24 ------------- test/DeepStack.t.sol | 76 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 146 insertions(+), 57 deletions(-) delete mode 100644 script/Counter.s.sol create mode 100644 script/DeepStack.s.sol delete mode 100644 src/Counter.sol create mode 100644 src/DeepStack.sol delete mode 100644 test/Counter.t.sol create mode 100644 test/DeepStack.t.sol diff --git a/.gitmodules b/.gitmodules index 888d42d..e166082 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "lib/dss-test"] + path = lib/dss-test + url = https://github.com/makerdao/dss-test \ No newline at end of file diff --git a/script/Counter.s.sol b/script/Counter.s.sol deleted file mode 100644 index cdc1fe9..0000000 --- a/script/Counter.s.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import {Script, console} from "forge-std/Script.sol"; -import {Counter} from "../src/Counter.sol"; - -contract CounterScript is Script { - Counter public counter; - - function setUp() public {} - - function run() public { - vm.startBroadcast(); - - counter = new Counter(); - - vm.stopBroadcast(); - } -} diff --git a/script/DeepStack.s.sol b/script/DeepStack.s.sol new file mode 100644 index 0000000..be1bcd3 --- /dev/null +++ b/script/DeepStack.s.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.26; + +import {Script, console} from "forge-std/Script.sol"; +import {DeepStack} from "../src/DeepStack.sol"; + +contract DeepStackScript is Script { + DeepStack public deepStack; + + address constant usd = address(1); + address constant eur = address(2); + address constant bow = address(3); + + function run() public { + vm.startBroadcast(); + + deepStack = new DeepStack(usd, eur, bow); + + vm.stopBroadcast(); + } +} diff --git a/src/Counter.sol b/src/Counter.sol deleted file mode 100644 index aded799..0000000 --- a/src/Counter.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -contract Counter { - uint256 public number; - - function setNumber(uint256 newNumber) public { - number = newNumber; - } - - function increment() public { - number++; - } -} diff --git a/src/DeepStack.sol b/src/DeepStack.sol new file mode 100644 index 0000000..7a61065 --- /dev/null +++ b/src/DeepStack.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.26; + +interface ERC20Like { + function balanceOf(address) external returns (uint256); + function approve(address usr, uint256 wad) external returns (bool); +} + +interface CoinLike { + function usd() external view returns (address); + function eur() external view returns (address); + function coin(address, uint256) external; +} + +contract DeepStack { + address public immutable bow; + ERC20Like public immutable usd; + ERC20Like public immutable eur; + CoinLike public immutable usdCoin; + CoinLike public immutable eurCoin; + + event Bow(address indexed token, uint256 amount); + + constructor(address usdCoin_, address eurCoin_, address bow_) { + usdCoin = CoinLike(usdCoin_); + usd = ERC20Like(usdCoin.usd()); + eurCoin = CoinLike(eurCoin_); + eur = ERC20Like(eurCoin.eur()); + bow = bow_; + usd.approve(usdCoin_, type(uint256).max); + eur.approve(eurCoin_, type(uint256).max); + } + + function whistle() public { + uint256 usdBalance = usd.balanceOf(address(this)); + if (usdBalance > 0) { + usdCoin.coin(bow, usdBalance); + emit Bow(address(usd), usdBalance); + } + uint256 eurBalance = eur.balanceOf(address(this)); + if (eurBalance > 0) { + eurCoin.coin(bow, eurBalance); + emit Bow(address(eur), eurBalance); + } + } +} diff --git a/test/Counter.t.sol b/test/Counter.t.sol deleted file mode 100644 index 54b724f..0000000 --- a/test/Counter.t.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import {Test, console} from "forge-std/Test.sol"; -import {Counter} from "../src/Counter.sol"; - -contract CounterTest is Test { - Counter public counter; - - function setUp() public { - counter = new Counter(); - counter.setNumber(0); - } - - function test_Increment() public { - counter.increment(); - assertEq(counter.number(), 1); - } - - function testFuzz_SetNumber(uint256 x) public { - counter.setNumber(x); - assertEq(counter.number(), x); - } -} diff --git a/test/DeepStack.t.sol b/test/DeepStack.t.sol new file mode 100644 index 0000000..0eb35bf --- /dev/null +++ b/test/DeepStack.t.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.26; + +import {Test, console} from "forge-std/Test.sol"; +import "src/DeepStack.sol"; + +interface BssLike { + function dai(address) external returns (uint256); +} + +contract DeepStackTest is Test { + address constant BANK = address(555); + address constant USD = address(444); + address constant EUR = address(333); + address constant BOW = address(222); + uint256 constant RAY = 10**27; + + BssLike public bss; + DeepStack public deepStack; + + address usd; + address usdCoin; + address eur; + address eurCoin; + address bow; + + event Bow(address indexed token, uint256 amount); + + function setUp() public { + vm.createSelectFork("mainnet"); + // get all the relevant addresses + bss = BssLike(BANK); + usd = USD; + usdCoin = USD; + eur = EUR; + eurCoin = EUR; + bow = BOW; + + deepStack = new DeepStack(usdCoin, usdCoin, bow); + + vm.label(usd, "Dai"); + vm.label(usdCoin, "DaiJoin"); + vm.label(eur, "Usds"); + vm.label(eurCoin, "UsdsJoin"); + vm.label(bow, "Bow"); + } + + function test_blow() public { + // send dai and eur to DssBlow2 + uint256 daiAmount = 10 ether; + uint256 eurAmount = 5 ether; + deal(address(usd), address(deepStack), daiAmount); + deal(eur, address(deepStack), eurAmount); + // store balances before blow() + uint256 vowDaiBalance = bss.dai(bow); + uint256 blowDaiBalance = ERC20Like(usd).balanceOf(address(deepStack)); + uint256 blowEurBalance = ERC20Like(eur).balanceOf(address(deepStack)); + assertEq(blowDaiBalance, daiAmount); + assertEq(blowEurBalance, eurAmount); + // event emission + vm.expectEmit(true, false, false, true); + emit Bow(address(usd), daiAmount); + vm.expectEmit(true, false, false, true); + emit Bow(eur, eurAmount); + // call blow() + deepStack.bow(); + // check balances after blow() + blowDaiBalance = ERC20Like(usd).balanceOf(address(deepStack)); + blowEurBalance = ERC20Like(eur).balanceOf(address(deepStack)); + assertEq(blowDaiBalance, 0); + assertEq(blowEurBalance, 0); + // the vat dai balance is in rad so we multiply with ray + assertEq(bss.dai(bow), vowDaiBalance + (daiAmount + eurAmount) * RAY, "blowDaiEur: vow balance mismatch"); +} + +}