diff --git a/README.md b/README.md index 342886e4..ad05c34d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Multi Collateral Dai + # Multi Collateral Dai ![Build Status](https://github.com/makerdao/dss/actions/workflows/.github/workflows/tests.yaml/badge.svg?branch=master) This repository contains the core smart contract code for Multi diff --git a/cache/solidity-files-cache.json b/cache/solidity-files-cache.json new file mode 100644 index 00000000..048daecd --- /dev/null +++ b/cache/solidity-files-cache.json @@ -0,0 +1 @@ +{"_format":"","paths":{"artifacts":"out","build_infos":"out/build-info","sources":"src","tests":"test","scripts":"script","libraries":["lib"]},"files":{"src/dai.sol":{"lastModificationDate":1782316029874,"contentHash":"fe8a705d06c13780","interfaceReprHash":null,"sourceName":"src/dai.sol","imports":[],"versionRequirement":"^0.8.0","artifacts":{"Dai":{"0.8.35":{"default":{"path":"dai.sol/Dai.json","build_id":"fd067ac922a9a6cb"}}}},"seenByCompiler":true}},"builds":["fd067ac922a9a6cb"],"profiles":{"default":{"solc":{"optimizer":{"enabled":false,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"osaka","viaIR":false,"libraries":{}},"vyper":{"evmVersion":"osaka","outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode"]}}}}},"preprocessed":false,"mocks":[]} \ No newline at end of file diff --git a/gas_report_dai.txt b/gas_report_dai.txt new file mode 100644 index 00000000..76f40a6e --- /dev/null +++ b/gas_report_dai.txt @@ -0,0 +1,152 @@ +No files changed, compilation skipped + +Ran 34 tests for src/test/dai.t.sol:DaiTest +[PASS] testAllowanceStartsAtZero() (gas: 15515) +Logs: + gas: 12982 + +[PASS] testApproveSetsAllowance() (gas: 72741) +Logs: + Test: 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 + Token: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f + Me: 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 + User 2: 0xc7183455a4C133Ae270771860664b6B7ec320bB1 + gas: 70121 + +[PASS] testApproveWillModifyAllowance() (gas: 178489) +[PASS] testApproveWillNotModifyAllowance() (gas: 165917) +[PASS] testBurn() (gas: 43548) +[PASS] testBurnAuth() (gas: 140739) +[PASS] testBurnGuyAuth() (gas: 154865) +[PASS] testBurnGuyWithTrust() (gas: 160494) +[PASS] testBurnself() (gas: 46116) +[PASS] testChargesAmountApproved() (gas: 121885) +Logs: + gas: 124087 + +[PASS] testDaiAddress() (gas: 14046) +Logs: + Error: a == b not satisfied [address] + Expected: 0x11Ee1eeF5D446D07Cf26941C7F2B4B1Dfb9D030B + Actual: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f + +[PASS] testDomain_Separator() (gas: 19337) +Logs: + Error: a == b not satisfied [bytes32] + Expected: 0x68a9504c1a7fba795f7730732abab11cb5fa5113edd2396392abd5c1bbda4043 + Actual: 0xfad5514f651d156e6fe232ee8ae83a6cfca2d936832a0cece2737056c6446819 + +[PASS] testMintGuy() (gas: 65522) +[PASS] testMintGuyAuth() (gas: 119328) +[PASS] testMintself() (gas: 48492) +[PASS] testPermit() (gas: 147142) +[PASS] testPermitWithExpiry() (gas: 123742) +[PASS] testRevertChargeMoreThanApproved() (gas: 160642) +Logs: + Error: Assertion Failed + gas: 158067 + +[PASS] testRevertIfWrongAccountTransfers() (gas: 48209) +Logs: + Error: Assertion Failed + gas: 45678 + +[PASS] testRevertInsufficientFundsTransfers() (gas: 101028) +Logs: + Error: Assertion Failed + gas: 98409 + +[PASS] testRevertMintGuyNoAuth() (gas: 41221) +[PASS] testRevertPermitAddress0() (gas: 44445) +[PASS] testRevertPermitWithExpiry() (gas: 55199) +[PASS] testRevertReplay() (gas: 148820) +[PASS] testRevertTransferFromSelfNonArbitrarySize() (gas: 54403) +Logs: + Error: Assertion Failed + +[PASS] testRevertTransferWithoutApproval() (gas: 104001) +Logs: + Error: Assertion Failed + gas: 101450 + +[PASS] testRevertUntrustedTransferFrom() (gas: 59692) +[PASS] testSetupPrecondition() (gas: 10621) +[PASS] testTransferCost() (gas: 60033) +Logs: + gas: 57433 + +[PASS] testTransferFromSelf() (gas: 66751) +[PASS] testTrustedTransferFrom() (gas: 128249) +[PASS] testTrusting() (gas: 108382) +[PASS] testTypehash() (gas: 5843) +[PASS] testValidTransfers() (gas: 79111) +Logs: + token11111: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f + gas: 76510 + +Suite result: ok. 34 passed; 0 failed; 0 skipped; finished in 129.05ms (124.97ms CPU time) + +╭--------------------------+-----------------+-------+--------+-------+---------╮ +| src/dai.sol:Dai Contract | | | | | | ++===============================================================================+ +| Deployment Cost | Deployment Size | | | | | +|--------------------------+-----------------+-------+--------+-------+---------| +| 1429297 | 6935 | | | | | +|--------------------------+-----------------+-------+--------+-------+---------| +| | | | | | | +|--------------------------+-----------------+-------+--------+-------+---------| +| Function Name | Min | Avg | Median | Max | # Calls | +|--------------------------+-----------------+-------+--------+-------+---------| +| DOMAIN_SEPARATOR | 2448 | 2448 | 2448 | 2448 | 4 | +|--------------------------+-----------------+-------+--------+-------+---------| +| PERMIT_TYPEHASH | 420 | 420 | 420 | 420 | 4 | +|--------------------------+-----------------+-------+--------+-------+---------| +| allowance | 3169 | 3169 | 3169 | 3169 | 15 | +|--------------------------+-----------------+-------+--------+-------+---------| +| approve | 24739 | 43681 | 46663 | 47023 | 7 | +|--------------------------+-----------------+-------+--------+-------+---------| +| balanceOf | 2891 | 2891 | 2891 | 2891 | 16 | +|--------------------------+-----------------+-------+--------+-------+---------| +| burn | 32022 | 33682 | 34512 | 34512 | 3 | +|--------------------------+-----------------+-------+--------+-------+---------| +| mint | 36910 | 62077 | 54010 | 71122 | 70 | +|--------------------------+-----------------+-------+--------+-------+---------| +| nonces | 2913 | 2913 | 2913 | 2913 | 3 | +|--------------------------+-----------------+-------+--------+-------+---------| +| permit | 28496 | 56032 | 58448 | 79198 | 6 | +|--------------------------+-----------------+-------+--------+-------+---------| +| rely | 46360 | 46360 | 46360 | 46360 | 2 | +|--------------------------+-----------------+-------+--------+-------+---------| +| totalSupply | 2470 | 2470 | 2470 | 2470 | 1 | +|--------------------------+-----------------+-------+--------+-------+---------| +| transfer | 24562 | 48974 | 52055 | 52067 | 9 | +|--------------------------+-----------------+-------+--------+-------+---------| +| transferFrom | 25097 | 31539 | 27463 | 52566 | 5 | +╰--------------------------+-----------------+-------+--------+-------+---------╯ + +╭---------------------------------------+-----------------+-------+--------+-------+---------╮ +| src/test/dai.t.sol:TokenUser Contract | | | | | | ++============================================================================================+ +| Deployment Cost | Deployment Size | | | | | +|---------------------------------------+-----------------+-------+--------+-------+---------| +| 735260 | 3347 | | | | | +|---------------------------------------+-----------------+-------+--------+-------+---------| +| | | | | | | +|---------------------------------------+-----------------+-------+--------+-------+---------| +| Function Name | Min | Avg | Median | Max | # Calls | +|---------------------------------------+-----------------+-------+--------+-------+---------| +| doApprove(address) | 52656 | 52656 | 52656 | 52656 | 2 | +|---------------------------------------+-----------------+-------+--------+-------+---------| +| doApprove(address,uint256) | 52921 | 52921 | 52921 | 52921 | 1 | +|---------------------------------------+-----------------+-------+--------+-------+---------| +| doBurn(address,uint256) | 37980 | 37980 | 37980 | 37980 | 1 | +|---------------------------------------+-----------------+-------+--------+-------+---------| +| doBurn(uint256) | 35106 | 35106 | 35106 | 35106 | 1 | +|---------------------------------------+-----------------+-------+--------+-------+---------| +| doMint | 30644 | 45284 | 45284 | 59925 | 2 | +|---------------------------------------+-----------------+-------+--------+-------+---------| +| doTransferFrom | 33632 | 55286 | 59855 | 64667 | 5 | +╰---------------------------------------+-----------------+-------+--------+-------+---------╯ + + +Ran 1 test suite in 233.85ms (129.05ms CPU time): 34 tests passed, 0 failed, 0 skipped (34 total tests) diff --git a/src/abaci.sol b/src/abaci.sol index 6cbd6662..7b5a1826 100644 --- a/src/abaci.sol +++ b/src/abaci.sol @@ -27,18 +27,25 @@ interface Abacus { } contract LinearDecrease is Abacus { - // --- 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 { + 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, "LinearDecrease/not-authorized"); _; } // --- Data --- - uint256 public tau; // Seconds after auction start when the price reaches zero [seconds] + uint256 public tau; // Seconds after auction start when the price reaches zero [seconds] // --- Events --- event Rely(address indexed usr); @@ -54,19 +61,22 @@ contract LinearDecrease is Abacus { // --- Administration --- function file(bytes32 what, uint256 data) external auth { - if (what == "tau") tau = data; + if (what == "tau") tau = data; else revert("LinearDecrease/file-unrecognized-param"); emit File(what, data); } // --- Math --- uint256 constant RAY = 10 ** 27; + function add(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); } + function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * y; require(y == 0 || z / y == x); @@ -82,26 +92,33 @@ contract LinearDecrease is Abacus { // // Note the internal call to mul multiples by RAY, thereby ensuring that the rmul calculation // which utilizes top and tau (RAY values) is also a RAY value. - function price(uint256 top, uint256 dur) override external view returns (uint256) { + function price(uint256 top, uint256 dur) external view override returns (uint256) { if (dur >= tau) return 0; return rmul(top, mul(tau - dur, RAY) / tau); } } contract StairstepExponentialDecrease is Abacus { - // --- 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 { + 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, "StairstepExponentialDecrease/not-authorized"); _; } // --- Data --- uint256 public step; // Length of time between price drops [seconds] - uint256 public cut; // Per-step multiplicative factor [ray] + uint256 public cut; // Per-step multiplicative factor [ray] // --- Events --- event Rely(address indexed usr); @@ -119,7 +136,7 @@ contract StairstepExponentialDecrease is Abacus { // --- Administration --- function file(bytes32 what, uint256 data) external auth { - if (what == "cut") require((cut = data) <= RAY, "StairstepExponentialDecrease/cut-gt-RAY"); + if (what == "cut") require((cut = data) <= RAY, "StairstepExponentialDecrease/cut-gt-RAY"); else if (what == "step") step = data; else revert("StairstepExponentialDecrease/file-unrecognized-param"); emit File(what, data); @@ -127,31 +144,37 @@ contract StairstepExponentialDecrease is Abacus { // --- Math --- uint256 constant RAY = 10 ** 27; + function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * y; require(y == 0 || z / y == x); z = z / RAY; } + // optimized version from dss PR #78 function rpow(uint256 x, uint256 n, uint256 b) internal pure returns (uint256 z) { assembly { - switch n case 0 { z := b } + switch n + case 0 { z := b } default { - switch x case 0 { z := 0 } + switch x + case 0 { z := 0 } default { - switch mod(n, 2) case 0 { z := b } default { z := x } - let half := div(b, 2) // for rounding. - for { n := div(n, 2) } n { n := div(n,2) } { + switch mod(n, 2) + case 0 { z := b } + default { z := x } + let half := div(b, 2) // for rounding. + for { n := div(n, 2) } n { n := div(n, 2) } { let xx := mul(x, x) - if shr(128, x) { revert(0,0) } + if shr(128, x) { revert(0, 0) } let xxRound := add(xx, half) - if lt(xxRound, xx) { revert(0,0) } + if lt(xxRound, xx) { revert(0, 0) } x := div(xxRound, b) - if mod(n,2) { + if mod(n, 2) { let zx := mul(z, x) - if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } + if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) } let zxRound := add(zx, half) - if lt(zxRound, zx) { revert(0,0) } + if lt(zxRound, zx) { revert(0, 0) } z := div(zxRound, b) } } @@ -170,7 +193,7 @@ contract StairstepExponentialDecrease is Abacus { // returns: top * (cut ^ dur) // // - function price(uint256 top, uint256 dur) override external view returns (uint256) { + function price(uint256 top, uint256 dur) external view override returns (uint256) { return rmul(top, rpow(cut, dur / step, RAY)); } } @@ -179,18 +202,25 @@ contract StairstepExponentialDecrease is Abacus { // this continous (i.e. per-second) exponential decrease has be implemented as it is more gas-efficient // than using the stairstep version with step = 1 (primarily due to 1 fewer SLOAD per price calculation). contract ExponentialDecrease is Abacus { - // --- 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 { + 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, "ExponentialDecrease/not-authorized"); _; } // --- Data --- - uint256 public cut; // Per-second multiplicative factor [ray] + uint256 public cut; // Per-second multiplicative factor [ray] // --- Events --- event Rely(address indexed usr); @@ -208,38 +238,44 @@ contract ExponentialDecrease is Abacus { // --- Administration --- function file(bytes32 what, uint256 data) external auth { - if (what == "cut") require((cut = data) <= RAY, "ExponentialDecrease/cut-gt-RAY"); + if (what == "cut") require((cut = data) <= RAY, "ExponentialDecrease/cut-gt-RAY"); else revert("ExponentialDecrease/file-unrecognized-param"); emit File(what, data); } // --- Math --- uint256 constant RAY = 10 ** 27; + function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * y; require(y == 0 || z / y == x); z = z / RAY; } + // optimized version from dss PR #78 function rpow(uint256 x, uint256 n, uint256 b) internal pure returns (uint256 z) { assembly { - switch n case 0 { z := b } + switch n + case 0 { z := b } default { - switch x case 0 { z := 0 } + switch x + case 0 { z := 0 } default { - switch mod(n, 2) case 0 { z := b } default { z := x } - let half := div(b, 2) // for rounding. - for { n := div(n, 2) } n { n := div(n,2) } { + switch mod(n, 2) + case 0 { z := b } + default { z := x } + let half := div(b, 2) // for rounding. + for { n := div(n, 2) } n { n := div(n, 2) } { let xx := mul(x, x) - if shr(128, x) { revert(0,0) } + if shr(128, x) { revert(0, 0) } let xxRound := add(xx, half) - if lt(xxRound, xx) { revert(0,0) } + if lt(xxRound, xx) { revert(0, 0) } x := div(xxRound, b) - if mod(n,2) { + if mod(n, 2) { let zx := mul(z, x) - if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } + if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) } let zxRound := add(zx, half) - if lt(zxRound, zx) { revert(0,0) } + if lt(zxRound, zx) { revert(0, 0) } z := div(zxRound, b) } } @@ -256,7 +292,7 @@ contract ExponentialDecrease is Abacus { // // returns: top * (cut ^ dur) // - function price(uint256 top, uint256 dur) override external view returns (uint256) { + function price(uint256 top, uint256 dur) external view override returns (uint256) { return rmul(top, rpow(cut, dur, RAY)); } } diff --git a/src/cat.sol b/src/cat.sol index f359dbcc..a2667f18 100644 --- a/src/cat.sol +++ b/src/cat.sol @@ -24,23 +24,28 @@ pragma solidity >=0.5.12; // New deployments of this contract will need to include custom events (TO DO). interface Kicker { - function kick(address urn, address gal, uint256 tab, uint256 lot, uint256 bid) - external returns (uint256); + function kick(address urn, address gal, uint256 tab, uint256 lot, uint256 bid) external returns (uint256); } interface VatLike { - function ilks(bytes32) external view returns ( - uint256 Art, // [wad] - uint256 rate, // [ray] - uint256 spot, // [ray] - uint256 line, // [rad] - uint256 dust // [rad] - ); - function urns(bytes32,address) external view returns ( - uint256 ink, // [wad] - uint256 art // [wad] - ); - function grab(bytes32,address,address,address,int256,int256) external; + function ilks(bytes32) + external + view + returns ( + uint256 Art, // [wad] + uint256 rate, // [ray] + uint256 spot, // [ray] + uint256 line, // [rad] + uint256 dust // [rad] + ); + function urns(bytes32, address) + external + view + returns ( + uint256 ink, // [wad] + uint256 art // [wad] + ); + function grab(bytes32, address, address, address, int256, int256) external; function hope(address) external; function nope(address) external; } @@ -51,38 +56,38 @@ interface VowLike { contract Cat { // --- Auth --- - mapping (address => uint256) public wards; - function rely(address usr) external auth { wards[usr] = 1; } - function deny(address usr) external auth { wards[usr] = 0; } - modifier auth { + mapping(address => uint256) public wards; + + function rely(address usr) external auth { + wards[usr] = 1; + } + + function deny(address usr) external auth { + wards[usr] = 0; + } + modifier auth() { require(wards[msg.sender] == 1, "Cat/not-authorized"); _; } // --- Data --- struct Ilk { - address flip; // Liquidator - uint256 chop; // Liquidation Penalty [wad] - uint256 dunk; // Liquidation Quantity [rad] + address flip; // Liquidator + uint256 chop; // Liquidation Penalty [wad] + uint256 dunk; // Liquidation Quantity [rad] } - mapping (bytes32 => Ilk) public ilks; + mapping(bytes32 => Ilk) public ilks; - uint256 public live; // Active Flag - VatLike public vat; // CDP Engine - VowLike public vow; // Debt Engine - uint256 public box; // Max Dai out for liquidation [rad] + uint256 public live; // Active Flag + VatLike public vat; // CDP Engine + VowLike public vow; // Debt Engine + uint256 public box; // Max Dai out for liquidation [rad] uint256 public litter; // Balance of Dai out for liquidation [rad] // --- Events --- event Bite( - bytes32 indexed ilk, - address indexed urn, - uint256 ink, - uint256 art, - uint256 tab, - address flip, - uint256 id + bytes32 indexed ilk, address indexed urn, uint256 ink, uint256 art, uint256 tab, address flip, uint256 id ); // --- Init --- @@ -96,14 +101,18 @@ contract Cat { uint256 constant WAD = 10 ** 18; function min(uint256 x, uint256 y) internal pure returns (uint256 z) { - if (x > y) { z = y; } else { z = x; } + if (x > y) z = y; + else z = x; } + 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); } @@ -113,27 +122,31 @@ contract Cat { if (what == "vow") vow = VowLike(data); else revert("Cat/file-unrecognized-param"); } + function file(bytes32 what, uint256 data) external auth { if (what == "box") box = data; else revert("Cat/file-unrecognized-param"); } + function file(bytes32 ilk, bytes32 what, uint256 data) external auth { if (what == "chop") ilks[ilk].chop = data; else if (what == "dunk") ilks[ilk].dunk = data; else revert("Cat/file-unrecognized-param"); } + function file(bytes32 ilk, bytes32 what, address flip) external auth { if (what == "flip") { vat.nope(ilks[ilk].flip); ilks[ilk].flip = flip; vat.hope(flip); + } else { + revert("Cat/file-unrecognized-param"); } - else revert("Cat/file-unrecognized-param"); } // --- CDP Liquidation --- function bite(bytes32 ilk, address urn) external returns (uint256 id) { - (,uint256 rate,uint256 spot,,uint256 dust) = vat.ilks(ilk); + (, uint256 rate, uint256 spot,, uint256 dust) = vat.ilks(ilk); (uint256 ink, uint256 art) = vat.urns(ilk, urn); require(live == 1, "Cat/not-live"); @@ -152,13 +165,11 @@ contract Cat { uint256 dink = min(ink, mul(ink, dart) / art); - require(dart > 0 && dink > 0 , "Cat/null-auction"); - require(dart <= 2**255 && dink <= 2**255, "Cat/overflow" ); + require(dart > 0 && dink > 0, "Cat/null-auction"); + require(dart <= 2 ** 255 && dink <= 2 ** 255, "Cat/overflow"); // This may leave the CDP in a dusty state - vat.grab( - ilk, urn, address(this), address(vow), -int256(dink), -int256(dart) - ); + vat.grab(ilk, urn, address(this), address(vow), -int256(dink), -int256(dart)); vow.fess(mul(dart, rate)); { // Avoid stack too deep @@ -167,13 +178,7 @@ contract Cat { uint256 tab = mul(mul(dart, rate), milk.chop) / WAD; litter = add(litter, tab); - id = Kicker(milk.flip).kick({ - urn: urn, - gal: address(vow), - tab: tab, - lot: dink, - bid: 0 - }); + id = Kicker(milk.flip).kick({urn: urn, gal: address(vow), tab: tab, lot: dink, bid: 0}); } emit Bite(ilk, urn, dink, dart, mul(dart, rate), milk.flip, id); diff --git a/src/clip.sol b/src/clip.sol index c43d8fff..2625dd48 100644 --- a/src/clip.sol +++ b/src/clip.sol @@ -20,10 +20,10 @@ pragma solidity ^0.6.12; interface VatLike { - function move(address,address,uint256) external; - function flux(bytes32,address,address,uint256) external; + function move(address, address, uint256) external; + function flux(bytes32, address, address, uint256) external; function ilks(bytes32) external returns (uint256, uint256, uint256, uint256, uint256); - function suck(address,address,uint256) external; + function suck(address, address, uint256) external; } interface PipLike { @@ -50,40 +50,48 @@ interface AbacusLike { contract Clipper { // --- 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 { + 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, "Clipper/not-authorized"); _; } // --- Data --- - bytes32 immutable public ilk; // Collateral type of this Clipper - VatLike immutable public vat; // Core CDP Engine + bytes32 public immutable ilk; // Collateral type of this Clipper + VatLike public immutable vat; // Core CDP Engine - DogLike public dog; // Liquidation module - address public vow; // Recipient of dai raised in auctions - SpotterLike public spotter; // Collateral price module - AbacusLike public calc; // Current price calculator + DogLike public dog; // Liquidation module + address public vow; // Recipient of dai raised in auctions + SpotterLike public spotter; // Collateral price module + AbacusLike public calc; // Current price calculator - uint256 public buf; // Multiplicative factor to increase starting price [ray] - uint256 public tail; // Time elapsed before auction reset [seconds] - uint256 public cusp; // Percentage drop before auction reset [ray] - uint64 public chip; // Percentage of tab to suck from vow to incentivize keepers [wad] - uint192 public tip; // Flat fee to suck from vow to incentivize keepers [rad] - uint256 public chost; // Cache the ilk dust times the ilk chop to prevent excessive SLOADs [rad] + uint256 public buf; // Multiplicative factor to increase starting price [ray] + uint256 public tail; // Time elapsed before auction reset [seconds] + uint256 public cusp; // Percentage drop before auction reset [ray] + uint64 public chip; // Percentage of tab to suck from vow to incentivize keepers [wad] + uint192 public tip; // Flat fee to suck from vow to incentivize keepers [rad] + uint256 public chost; // Cache the ilk dust times the ilk chop to prevent excessive SLOADs [rad] - uint256 public kicks; // Total auctions - uint256[] public active; // Array of active auction ids + uint256 public kicks; // Total auctions + uint256[] public active; // Array of active auction ids struct Sale { - uint256 pos; // Index in active array - uint256 tab; // Dai to raise [rad] - uint256 lot; // collateral to sell [wad] - address usr; // Liquidated CDP - uint96 tic; // Auction start time - uint256 top; // Starting price [ray] + uint256 pos; // Index in active array + uint256 tab; // Dai to raise [rad] + uint256 lot; // collateral to sell [wad] + address usr; // Liquidated CDP + uint96 tic; // Auction start time + uint256 top; // Starting price [ray] } mapping(uint256 => Sale) public sales; @@ -113,13 +121,7 @@ contract Clipper { uint256 coin ); event Take( - uint256 indexed id, - uint256 max, - uint256 price, - uint256 owe, - uint256 tab, - uint256 lot, - address indexed usr + uint256 indexed id, uint256 max, uint256 price, uint256 owe, uint256 tab, uint256 lot, address indexed usr ); event Redo( uint256 indexed id, @@ -135,17 +137,17 @@ contract Clipper { // --- Init --- constructor(address vat_, address spotter_, address dog_, bytes32 ilk_) public { - vat = VatLike(vat_); + vat = VatLike(vat_); spotter = SpotterLike(spotter_); - dog = DogLike(dog_); - ilk = ilk_; - buf = RAY; + dog = DogLike(dog_); + ilk = ilk_; + buf = RAY; wards[msg.sender] = 1; emit Rely(msg.sender); } // --- Synchronization --- - modifier lock { + modifier lock() { require(locked == 0, "Clipper/system-locked"); locked = 1; _; @@ -159,47 +161,54 @@ contract Clipper { // --- Administration --- function file(bytes32 what, uint256 data) external auth lock { - if (what == "buf") buf = data; - else if (what == "tail") tail = data; // Time elapsed before auction reset - else if (what == "cusp") cusp = data; // Percentage drop before auction reset - else if (what == "chip") chip = uint64(data); // Percentage of tab to incentivize (max: 2^64 - 1 => 18.xxx WAD = 18xx%) - else if (what == "tip") tip = uint192(data); // Flat fee to incentivize keepers (max: 2^192 - 1 => 6.277T RAD) - else if (what == "stopped") stopped = data; // Set breaker (0, 1, 2, or 3) + if (what == "buf") buf = data; + else if (what == "tail") tail = data; // Time elapsed before auction reset + else if (what == "cusp") cusp = data; // Percentage drop before auction reset + else if (what == "chip") chip = uint64(data); // Percentage of tab to incentivize (max: 2^64 - 1 => 18.xxx WAD = 18xx%) + else if (what == "tip") tip = uint192(data); // Flat fee to incentivize keepers (max: 2^192 - 1 => 6.277T RAD) + else if (what == "stopped") stopped = data; // Set breaker (0, 1, 2, or 3) else revert("Clipper/file-unrecognized-param"); emit File(what, data); } + function file(bytes32 what, address data) external auth lock { if (what == "spotter") spotter = SpotterLike(data); - else if (what == "dog") dog = DogLike(data); - else if (what == "vow") vow = data; - else if (what == "calc") calc = AbacusLike(data); + else if (what == "dog") dog = DogLike(data); + else if (what == "vow") vow = data; + else if (what == "calc") calc = AbacusLike(data); else revert("Clipper/file-unrecognized-param"); emit File(what, data); } // --- Math --- - uint256 constant BLN = 10 ** 9; + uint256 constant BLN = 10 ** 9; uint256 constant WAD = 10 ** 18; uint256 constant RAY = 10 ** 27; function min(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x <= y ? x : y; } + 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); } + function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, y) / WAD; } + function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, y) / RAY; } + function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, RAY) / y; } @@ -211,7 +220,7 @@ contract Clipper { // if mat has changed since the last poke, the resulting value will be // incorrect. function getFeedPrice() internal returns (uint256 feedPrice) { - (PipLike pip, ) = spotter.ilks(ilk); + (PipLike pip,) = spotter.ilks(ilk); (bytes32 val, bool has) = pip.peek(); require(has, "Clipper/invalid-price"); feedPrice = rdiv(mul(uint256(val), BLN), spotter.par()); @@ -227,17 +236,23 @@ contract Clipper { // multiplicative factor to increase the starting price, and `par` is a // reference per DAI. function kick( - uint256 tab, // Debt [rad] - uint256 lot, // Collateral [wad] - address usr, // Address that will receive any leftover collateral - address kpr // Address that will receive incentives - ) external auth lock isStopped(1) returns (uint256 id) { + uint256 tab, // Debt [rad] + uint256 lot, // Collateral [wad] + address usr, // Address that will receive any leftover collateral + address kpr // Address that will receive incentives + ) + external + auth + lock + isStopped(1) + returns (uint256 id) + { // Input validation - require(tab > 0, "Clipper/zero-tab"); - require(lot > 0, "Clipper/zero-lot"); + require(tab > 0, "Clipper/zero-tab"); + require(lot > 0, "Clipper/zero-lot"); require(usr != address(0), "Clipper/zero-usr"); id = ++kicks; - require(id > 0, "Clipper/overflow"); + require(id > 0, "Clipper/overflow"); active.push(id); @@ -254,7 +269,7 @@ contract Clipper { sales[id].top = top; // incentive to kick auction - uint256 _tip = tip; + uint256 _tip = tip; uint256 _chip = chip; uint256 coin; if (_tip > 0 || _chip > 0) { @@ -268,12 +283,16 @@ contract Clipper { // Reset an auction // See `kick` above for an explanation of the computation of `top`. function redo( - uint256 id, // id of the auction to reset - address kpr // Address that will receive incentives - ) external lock isStopped(2) { + uint256 id, // id of the auction to reset + address kpr // Address that will receive incentives + ) + external + lock + isStopped(2) + { // Read auction data address usr = sales[id].usr; - uint96 tic = sales[id].tic; + uint96 tic = sales[id].tic; uint256 top = sales[id].top; require(usr != address(0), "Clipper/not-running-auction"); @@ -283,8 +302,8 @@ contract Clipper { (bool done,) = status(tic, top); require(done, "Clipper/cannot-reset"); - uint256 tab = sales[id].tab; - uint256 lot = sales[id].lot; + uint256 tab = sales[id].tab; + uint256 lot = sales[id].lot; sales[id].tic = uint96(block.timestamp); uint256 feedPrice = getFeedPrice(); @@ -293,7 +312,7 @@ contract Clipper { sales[id].top = top; // incentive to redo auction - uint256 _tip = tip; + uint256 _tip = tip; uint256 _chip = chip; uint256 coin; if (_tip > 0 || _chip > 0) { @@ -308,7 +327,7 @@ contract Clipper { } // Buy up to `amt` of collateral from the auction indexed by `id`. - // + // // Auctions will not collect more DAI than their assigned DAI target,`tab`; // thus, if `amt` would cost more DAI than `tab` at the current price, the // amount of collateral purchased will instead be just enough to collect `tab` DAI. @@ -325,15 +344,18 @@ contract Clipper { // If `tab <= chost`, partial purchases are no longer possible; that is, the remaining // collateral can only be purchased entirely, or not at all. function take( - uint256 id, // Auction id - uint256 amt, // Upper limit on amount of collateral to buy [wad] - uint256 max, // Maximum acceptable price (DAI / collateral) [ray] - address who, // Receiver of collateral and external call address - bytes calldata data // Data to pass in external call; if length 0, no call is done - ) external lock isStopped(3) { - + uint256 id, // Auction id + uint256 amt, // Upper limit on amount of collateral to buy [wad] + uint256 max, // Maximum acceptable price (DAI / collateral) [ray] + address who, // Receiver of collateral and external call address + bytes calldata data // Data to pass in external call; if length 0, no call is done + ) + external + lock + isStopped(3) + { address usr = sales[id].usr; - uint96 tic = sales[id].tic; + uint96 tic = sales[id].tic; require(usr != address(0), "Clipper/not-running-auction"); @@ -355,7 +377,7 @@ contract Clipper { { // Purchase as much as possible, up to amt - uint256 slice = min(lot, amt); // slice <= lot + uint256 slice = min(lot, amt); // slice <= lot // DAI needed to buy a slice of this sale owe = mul(slice, price); @@ -363,24 +385,25 @@ contract Clipper { // Don't collect more than tab of DAI if (owe > tab) { // Total debt will be paid - owe = tab; // owe' <= owe + owe = tab; // owe' <= owe // Adjust slice - slice = owe / price; // slice' = owe' / price <= owe / price == slice <= lot + slice = owe / price; // slice' = owe' / price <= owe / price == slice <= lot } else if (owe < tab && slice < lot) { // If slice == lot => auction completed => dust doesn't matter uint256 _chost = chost; - if (tab - owe < _chost) { // safe as owe < tab + if (tab - owe < _chost) { + // safe as owe < tab // If tab <= chost, buyers have to take the entire lot. require(tab > _chost, "Clipper/no-partial-purchase"); // Adjust amount to pay - owe = tab - _chost; // owe' <= owe + owe = tab - _chost; // owe' <= owe // Adjust slice - slice = owe / price; // slice' = owe' / price < owe / price == slice < lot + slice = owe / price; // slice' = owe' / price < owe / price == slice < lot } } // Calculate remaining tab after operation - tab = tab - owe; // safe since owe <= tab + tab = tab - owe; // safe since owe <= tab // Calculate remaining lot after operation lot = lot - slice; @@ -416,10 +439,10 @@ contract Clipper { } function _remove(uint256 id) internal { - uint256 _move = active[active.length - 1]; + uint256 _move = active[active.length - 1]; if (id != _move) { - uint256 _index = sales[id].pos; - active[_index] = _move; + uint256 _index = sales[id].pos; + active[_index] = _move; sales[_move].pos = _index; } active.pop(); @@ -440,7 +463,7 @@ contract Clipper { function getStatus(uint256 id) external view returns (bool needsRedo, uint256 price, uint256 lot, uint256 tab) { // Read auction data address usr = sales[id].usr; - uint96 tic = sales[id].tic; + uint96 tic = sales[id].tic; bool done; (done, price) = status(tic, sales[id].top); @@ -453,7 +476,7 @@ contract Clipper { // Internally returns boolean for if an auction needs a redo function status(uint96 tic, uint256 top) internal view returns (bool done, uint256 price) { price = calc.price(top, sub(block.timestamp, tic)); - done = (sub(block.timestamp, tic) > tail || rdiv(price, top) < cusp); + done = (sub(block.timestamp, tic) > tail || rdiv(price, top) < cusp); } // Public function to update the cached dust*chop value. diff --git a/src/cure.sol b/src/cure.sol index 8403808f..181a1bb7 100644 --- a/src/cure.sol +++ b/src/cure.sol @@ -24,14 +24,14 @@ interface SourceLike { } contract Cure { - mapping (address => uint256) public wards; + mapping(address => uint256) public wards; uint256 public live; address[] public srcs; uint256 public wait; uint256 public when; - mapping (address => uint256) public pos; // position in srcs + 1, 0 means a source does not exist - mapping (address => uint256) public amt; - mapping (address => uint256) public loaded; + mapping(address => uint256) public pos; // position in srcs + 1, 0 means a source does not exist + mapping(address => uint256) public amt; + mapping(address => uint256) public loaded; uint256 public lCount; uint256 public say; @@ -44,7 +44,7 @@ contract Cure { event Load(address indexed src); event Cage(); - modifier auth { + modifier auth() { require(wards[msg.sender] == 1, "Cure/not-authorized"); _; } @@ -73,7 +73,9 @@ contract Cure { } function tell() external view returns (uint256) { - require(live == 0 && (lCount == srcs.length || block.timestamp >= when), "Cure/missing-load-and-time-not-passed"); + require( + live == 0 && (lCount == srcs.length || block.timestamp >= when), "Cure/missing-load-and-time-not-passed" + ); return say; } diff --git a/src/dai.sol b/src/dai.sol index efc1da28..5e6eb8d4 100644 --- a/src/dai.sol +++ b/src/dai.sol @@ -17,130 +17,227 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -pragma solidity ^0.6.12; +pragma solidity ^0.8.0; // FIXME: This contract was altered compared to the production version. // It doesn't use LibNote anymore. // New deployments of this contract will need to include custom events (TO DO). -contract Dai { - // --- Auth --- - mapping (address => uint) public wards; - function rely(address guy) external auth { wards[guy] = 1; } - function deny(address guy) external auth { wards[guy] = 0; } - modifier auth { - require(wards[msg.sender] == 1, "Dai/not-authorized"); - _; - } +/** + * @title DAI_Contract + * @author MakerDAO + * @notice This contract was altered compared to the production version. + * It doesn't use LibNote anymore. + * New deployments of this contract will need to include custom events (TO DO). + * @dev This contract upgrades compile version making for Gas Optimization + */ - // --- ERC20 Data --- - string public constant name = "Dai Stablecoin"; - string public constant symbol = "DAI"; - string public constant version = "1"; - uint8 public constant decimals = 18; +contract Dai { + /*////////////////////////////////////////////////////////////// + ERRORS + //////////////////////////////////////////////////////////////*/ + error Dai__InsufficientBalance(); + error Dai__InsufficientAllowance(); + error Dai__InvalidAddress(); + error Dai__InvalidPermit(); + error Dai__PermitExpired(); + error Dai__InvalidNonce(); + error Dai__DaiNotAuthorized(); + + /*////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////*/ + + string private constant name = "Dai Stablecoin"; + string private constant symbol = "DAI"; + string private constant version = "1"; + uint8 private constant decimals = 18; uint256 public totalSupply; + uint256 internal constant MAX_UINT = type(uint256).max; - mapping (address => uint) public balanceOf; - mapping (address => mapping (address => uint)) public allowance; - mapping (address => uint) public nonces; - - event Approval(address indexed src, address indexed guy, uint wad); - event Transfer(address indexed src, address indexed dst, uint wad); - - // --- Math --- - function add(uint x, uint y) internal pure returns (uint z) { - require((z = x + y) >= x); - } - function sub(uint x, uint y) internal pure returns (uint z) { - require((z = x - y) <= x); - } + /*////////////////////////////////////////////////////////////// + BYTES VARIABLES + //////////////////////////////////////////////////////////////*/ // --- EIP712 niceties --- bytes32 public DOMAIN_SEPARATOR; // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)"); bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; + bytes32 internal constant EIP712_DOMAIN_TYPEHASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + + bytes32 internal constant NAME_HASH = keccak256(abi.encodePacked(name)); + + bytes32 internal constant VERSION_HASH = keccak256(abi.encodePacked(version)); + + /*////////////////////////////////////////////////////////////// + MAPPINGS + //////////////////////////////////////////////////////////////*/ + + mapping(address => uint256) public wards; + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + mapping(address => uint256) public nonces; + + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ - constructor(uint256 chainId_) public { + event Approval(address indexed src, address indexed guy, uint256 wad); + event Transfer(address indexed src, address indexed dst, uint256 wad); + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(uint256 chainId_) { wards[msg.sender] = 1; - DOMAIN_SEPARATOR = keccak256(abi.encode( - keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), - keccak256(bytes(name)), - keccak256(bytes(version)), - chainId_, - address(this) - )); + DOMAIN_SEPARATOR = + keccak256(abi.encode(EIP712_DOMAIN_TYPEHASH, NAME_HASH, VERSION_HASH, chainId_, address(this))); + } + /*////////////////////////////////////////////////////////////// + MODIFIER + //////////////////////////////////////////////////////////////*/ + + modifier auth() { + if (wards[msg.sender] != 1) { + revert Dai__DaiNotAuthorized(); + } + _; + } + + /*////////////////////////////////////////////////////////////// + EXTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + function rely(address guy) external auth { + wards[guy] = 1; + } + + function deny(address guy) external auth { + wards[guy] = 0; } // --- Token --- - function transfer(address dst, uint wad) external returns (bool) { + function transfer(address dst, uint256 wad) external returns (bool) { return transferFrom(msg.sender, dst, wad); } - function transferFrom(address src, address dst, uint wad) - public returns (bool) - { - require(balanceOf[src] >= wad, "Dai/insufficient-balance"); - if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { - require(allowance[src][msg.sender] >= wad, "Dai/insufficient-allowance"); - allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad); + + function transferFrom(address src, address dst, uint256 wad) public returns (bool) { + uint256 srcBalance = balanceOf[src]; + + if (srcBalance < wad) { + revert Dai__InsufficientBalance(); } - balanceOf[src] = sub(balanceOf[src], wad); - balanceOf[dst] = add(balanceOf[dst], wad); + + if (src != msg.sender) { + uint256 allowed = allowance[src][msg.sender]; + + if (allowed != MAX_UINT) { + if (allowed < wad) { + revert Dai__InsufficientAllowance(); + } + + unchecked { + allowance[src][msg.sender] = allowed - wad; + } + } + } + + uint256 dstBalance = balanceOf[dst]; + + unchecked { + balanceOf[src] = srcBalance - wad; + balanceOf[dst] = dstBalance + wad; + } + emit Transfer(src, dst, wad); + return true; } - function mint(address usr, uint wad) external auth { - balanceOf[usr] = add(balanceOf[usr], wad); - totalSupply = add(totalSupply, wad); + + function mint(address usr, uint256 wad) external auth { + balanceOf[usr] += wad; + totalSupply += wad; + emit Transfer(address(0), usr, wad); } - function burn(address usr, uint wad) external { - require(balanceOf[usr] >= wad, "Dai/insufficient-balance"); - if (usr != msg.sender && allowance[usr][msg.sender] != uint(-1)) { - require(allowance[usr][msg.sender] >= wad, "Dai/insufficient-allowance"); - allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad); + + function burn(address usr, uint256 wad) external { + uint256 usrBalance = balanceOf[usr]; + + if (usrBalance < wad) revert Dai__InsufficientBalance(); + + if (usr != msg.sender) { + uint256 allowed = allowance[usr][msg.sender]; + + if (allowed != MAX_UINT) { + if (allowed < wad) revert Dai__InsufficientAllowance(); + + unchecked { + allowance[usr][msg.sender] = allowed - wad; + } + } } - balanceOf[usr] = sub(balanceOf[usr], wad); - totalSupply = sub(totalSupply, wad); + + unchecked { + balanceOf[usr] = usrBalance - wad; + totalSupply -= wad; + } + emit Transfer(usr, address(0), wad); } - function approve(address usr, uint wad) external returns (bool) { + + function approve(address usr, uint256 wad) external returns (bool) { allowance[msg.sender][usr] = wad; emit Approval(msg.sender, usr, wad); return true; } // --- Alias --- - function push(address usr, uint wad) external { + function push(address usr, uint256 wad) external { transferFrom(msg.sender, usr, wad); } - function pull(address usr, uint wad) external { + + function pull(address usr, uint256 wad) external { transferFrom(usr, msg.sender, wad); } - function move(address src, address dst, uint wad) external { + + function move(address src, address dst, uint256 wad) external { transferFrom(src, dst, wad); } // --- Approve by signature --- - function permit(address holder, address spender, uint256 nonce, uint256 expiry, - bool allowed, uint8 v, bytes32 r, bytes32 s) external - { - bytes32 digest = - keccak256(abi.encodePacked( + function permit( + address holder, + address spender, + uint256 nonce, + uint256 expiry, + bool allowed, + uint8 v, + bytes32 r, + bytes32 s + ) external { + bytes32 digest = keccak256( + abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR, - keccak256(abi.encode(PERMIT_TYPEHASH, - holder, - spender, - nonce, - expiry, - allowed)) - )); - - require(holder != address(0), "Dai/invalid-address-0"); - require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit"); - require(expiry == 0 || now <= expiry, "Dai/permit-expired"); - require(nonce == nonces[holder]++, "Dai/invalid-nonce"); - uint wad = allowed ? uint(-1) : 0; + keccak256(abi.encode(PERMIT_TYPEHASH, holder, spender, nonce, expiry, allowed)) + ) + ); + if (holder == address(0)) { + revert Dai__InvalidAddress(); + } + if (holder != ecrecover(digest, v, r, s)) { + revert Dai__InvalidPermit(); + } + if (expiry != 0 && block.timestamp > expiry) { + revert Dai__PermitExpired(); + } + if (nonce != nonces[holder]++) { + revert Dai__InvalidNonce(); + } + uint256 wad = allowed ? MAX_UINT : 0; allowance[holder][spender] = wad; emit Approval(holder, spender, wad); } diff --git a/src/dog.sol b/src/dog.sol index d941d80f..9f6e7507 100644 --- a/src/dog.sol +++ b/src/dog.sol @@ -21,27 +21,28 @@ pragma solidity ^0.6.12; interface ClipperLike { function ilk() external view returns (bytes32); - function kick( - uint256 tab, - uint256 lot, - address usr, - address kpr - ) external returns (uint256); + function kick(uint256 tab, uint256 lot, address usr, address kpr) external returns (uint256); } interface VatLike { - function ilks(bytes32) external view returns ( - uint256 Art, // [wad] - uint256 rate, // [ray] - uint256 spot, // [ray] - uint256 line, // [rad] - uint256 dust // [rad] - ); - function urns(bytes32,address) external view returns ( - uint256 ink, // [wad] - uint256 art // [wad] - ); - function grab(bytes32,address,address,address,int256,int256) external; + function ilks(bytes32) + external + view + returns ( + uint256 Art, // [wad] + uint256 rate, // [ray] + uint256 spot, // [ray] + uint256 line, // [rad] + uint256 dust // [rad] + ); + function urns(bytes32, address) + external + view + returns ( + uint256 ink, // [wad] + uint256 art // [wad] + ); + function grab(bytes32, address, address, address, int256, int256) external; function hope(address) external; function nope(address) external; } @@ -52,30 +53,38 @@ interface VowLike { contract Dog { // --- 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 { + 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, "Dog/not-authorized"); _; } // --- Data --- struct Ilk { - address clip; // Liquidator - uint256 chop; // Liquidation Penalty [wad] - uint256 hole; // Max DAI needed to cover debt+fees of active auctions per ilk [rad] - uint256 dirt; // Amt DAI needed to cover debt+fees of active auctions per ilk [rad] + address clip; // Liquidator + uint256 chop; // Liquidation Penalty [wad] + uint256 hole; // Max DAI needed to cover debt+fees of active auctions per ilk [rad] + uint256 dirt; // Amt DAI needed to cover debt+fees of active auctions per ilk [rad] } - VatLike immutable public vat; // CDP Engine + VatLike public immutable vat; // CDP Engine - mapping (bytes32 => Ilk) public ilks; + mapping(bytes32 => Ilk) public ilks; - VowLike public vow; // Debt Engine - uint256 public live; // Active Flag - uint256 public Hole; // Max DAI needed to cover debt+fees of active auctions [rad] - uint256 public Dirt; // Amt DAI needed to cover debt+fees of active auctions [rad] + VowLike public vow; // Debt Engine + uint256 public live; // Active Flag + uint256 public Hole; // Max DAI needed to cover debt+fees of active auctions [rad] + uint256 public Dirt; // Amt DAI needed to cover debt+fees of active auctions [rad] // --- Events --- event Rely(address indexed usr); @@ -87,13 +96,13 @@ contract Dog { event File(bytes32 indexed ilk, bytes32 indexed what, address clip); event Bark( - bytes32 indexed ilk, - address indexed urn, - uint256 ink, - uint256 art, - uint256 due, - address clip, - uint256 indexed id + bytes32 indexed ilk, + address indexed urn, + uint256 ink, + uint256 art, + uint256 due, + address clip, + uint256 indexed id ); event Digs(bytes32 indexed ilk, uint256 rad); event Cage(); @@ -112,12 +121,15 @@ contract Dog { function min(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x <= y ? x : y; } + 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); } @@ -128,24 +140,32 @@ contract Dog { else revert("Dog/file-unrecognized-param"); emit File(what, data); } + function file(bytes32 what, uint256 data) external auth { if (what == "Hole") Hole = data; else revert("Dog/file-unrecognized-param"); emit File(what, data); } + function file(bytes32 ilk, bytes32 what, uint256 data) external auth { if (what == "chop") { require(data >= WAD, "Dog/file-chop-lt-WAD"); ilks[ilk].chop = data; - } else if (what == "hole") ilks[ilk].hole = data; - else revert("Dog/file-unrecognized-param"); + } else if (what == "hole") { + ilks[ilk].hole = data; + } else { + revert("Dog/file-unrecognized-param"); + } emit File(ilk, what, data); } + function file(bytes32 ilk, bytes32 what, address clip) external auth { if (what == "clip") { require(ilk == ClipperLike(clip).ilk(), "Dog/file-ilk-neq-clip.ilk"); ilks[ilk].clip = clip; - } else revert("Dog/file-unrecognized-param"); + } else { + revert("Dog/file-unrecognized-param"); + } emit File(ilk, what, clip); } @@ -177,7 +197,7 @@ contract Dog { uint256 dust; { uint256 spot; - (,rate, spot,, dust) = vat.ilks(ilk); + (, rate, spot,, dust) = vat.ilks(ilk); require(spot > 0 && mul(ink, spot) < mul(art, rate), "Dog/not-unsafe"); // Get the minimum value between: @@ -192,7 +212,6 @@ contract Dog { // Partial liquidation edge case logic if (art > dart) { if (mul(art - dart, rate) < dust) { - // If the leftover Vault would be dusty, just liquidate it entirely. // This will result in at least one of dirt_i > hole_i or Dirt > Hole becoming true. // The amount of excess will be bounded above by ceiling(dust_i * chop_i / WAD). @@ -200,7 +219,6 @@ contract Dog { // the extra amount of target DAI over the limits intended is not of economic concern. dart = art; } else { - // In a partial liquidation, the resulting auction should also be non-dusty. require(mul(dart, rate) >= dust, "Dog/dusty-auction-from-partial-liquidation"); } @@ -210,27 +228,20 @@ contract Dog { uint256 dink = mul(ink, dart) / art; require(dink > 0, "Dog/null-auction"); - require(dart <= 2**255 && dink <= 2**255, "Dog/overflow"); + require(dart <= 2 ** 255 && dink <= 2 ** 255, "Dog/overflow"); - vat.grab( - ilk, urn, milk.clip, address(vow), -int256(dink), -int256(dart) - ); + vat.grab(ilk, urn, milk.clip, address(vow), -int256(dink), -int256(dart)); uint256 due = mul(dart, rate); vow.fess(due); - { // Avoid stack too deep + { // Avoid stack too deep // This calcuation will overflow if dart*rate exceeds ~10^14 uint256 tab = mul(due, milk.chop) / WAD; Dirt = add(Dirt, tab); ilks[ilk].dirt = add(milk.dirt, tab); - id = ClipperLike(milk.clip).kick({ - tab: tab, - lot: dink, - usr: urn, - kpr: kpr - }); + id = ClipperLike(milk.clip).kick({tab: tab, lot: dink, usr: urn, kpr: kpr}); } emit Bark(ilk, urn, dink, dart, due, milk.clip, id); diff --git a/src/end.sol b/src/end.sol index 14e17b19..ade9d253 100644 --- a/src/end.sol +++ b/src/end.sol @@ -23,17 +23,21 @@ pragma solidity ^0.6.12; interface VatLike { function dai(address) external view returns (uint256); - function ilks(bytes32 ilk) external returns ( - uint256 Art, // [wad] - uint256 rate, // [ray] - uint256 spot, // [ray] - uint256 line, // [rad] - uint256 dust // [rad] - ); - function urns(bytes32 ilk, address urn) external returns ( - uint256 ink, // [wad] - uint256 art // [wad] - ); + function ilks(bytes32 ilk) + external + returns ( + uint256 Art, // [wad] + uint256 rate, // [ray] + uint256 spot, // [ray] + uint256 line, // [rad] + uint256 dust // [rad] + ); + function urns(bytes32 ilk, address urn) + external + returns ( + uint256 ink, // [wad] + uint256 art // [wad] + ); function debt() external returns (uint256); function move(address src, address dst, uint256 rad) external; function hope(address) external; @@ -44,21 +48,18 @@ interface VatLike { } interface CatLike { - function ilks(bytes32) external returns ( - address flip, - uint256 chop, // [ray] - uint256 lump // [rad] - ); + function ilks(bytes32) + external + returns ( + address flip, + uint256 chop, // [ray] + uint256 lump // [rad] + ); function cage() external; } interface DogLike { - function ilks(bytes32) external returns ( - address clip, - uint256 chop, - uint256 hole, - uint256 dirt - ); + function ilks(bytes32) external returns (address clip, uint256 chop, uint256 hole, uint256 dirt); function cage() external; } @@ -71,28 +72,27 @@ interface VowLike { } interface FlipLike { - function bids(uint256 id) external view returns ( - uint256 bid, // [rad] - uint256 lot, // [wad] - address guy, - uint48 tic, // [unix epoch time] - uint48 end, // [unix epoch time] - address usr, - address gal, - uint256 tab // [rad] - ); + function bids(uint256 id) + external + view + returns ( + uint256 bid, // [rad] + uint256 lot, // [wad] + address guy, + uint48 tic, // [unix epoch time] + uint48 end, // [unix epoch time] + address usr, + address gal, + uint256 tab // [rad] + ); function yank(uint256 id) external; } interface ClipLike { - function sales(uint256 id) external view returns ( - uint256 pos, - uint256 tab, - uint256 lot, - address usr, - uint96 tic, - uint256 top - ); + function sales(uint256 id) + external + view + returns (uint256 pos, uint256 tab, uint256 lot, address usr, uint96 tic, uint256 top); function yank(uint256 id) external; } @@ -102,10 +102,13 @@ interface PipLike { interface SpotLike { function par() external view returns (uint256); - function ilks(bytes32) external view returns ( - PipLike pip, - uint256 mat // [ray] - ); + function ilks(bytes32) + external + view + returns ( + PipLike pip, + uint256 mat // [ray] + ); function cage() external; } @@ -231,35 +234,43 @@ interface CureLike { contract End { // --- 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 { + 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, "End/not-authorized"); _; } // --- Data --- - VatLike public vat; // CDP Engine - CatLike public cat; - DogLike public dog; - VowLike public vow; // Debt Engine - PotLike public pot; + VatLike public vat; // CDP Engine + CatLike public cat; + DogLike public dog; + VowLike public vow; // Debt Engine + PotLike public pot; SpotLike public spot; CureLike public cure; - uint256 public live; // Active Flag - uint256 public when; // Time of cage [unix epoch time] - uint256 public wait; // Processing Cooldown Length [seconds] - uint256 public debt; // Total outstanding dai following processing [rad] + uint256 public live; // Active Flag + uint256 public when; // Time of cage [unix epoch time] + uint256 public wait; // Processing Cooldown Length [seconds] + uint256 public debt; // Total outstanding dai following processing [rad] - mapping (bytes32 => uint256) public tag; // Cage price [ray] - mapping (bytes32 => uint256) public gap; // Collateral shortfall [wad] - mapping (bytes32 => uint256) public Art; // Total debt per ilk [wad] - mapping (bytes32 => uint256) public fix; // Final cash price [ray] + mapping(bytes32 => uint256) public tag; // Cage price [ray] + mapping(bytes32 => uint256) public gap; // Collateral shortfall [wad] + mapping(bytes32 => uint256) public Art; // Total debt per ilk [wad] + mapping(bytes32 => uint256) public fix; // Final cash price [ray] - mapping (address => uint256) public bag; // [wad] - mapping (bytes32 => mapping (address => uint256)) public out; // [wad] + mapping(address => uint256) public bag; // [wad] + mapping(bytes32 => mapping(address => uint256)) public out; // [wad] // --- Events --- event Rely(address indexed usr); @@ -289,22 +300,28 @@ contract End { // --- Math --- uint256 constant WAD = 10 ** 18; uint256 constant RAY = 10 ** 27; + function add(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x + y; require(z >= 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); } + function min(uint256 x, uint256 y) internal pure returns (uint256 z) { return x <= y ? x : y; } + function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, y) / RAY; } + function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, WAD) / y; } @@ -312,16 +329,17 @@ contract End { // --- Administration --- function file(bytes32 what, address data) external auth { require(live == 1, "End/not-live"); - if (what == "vat") vat = VatLike(data); - else if (what == "cat") cat = CatLike(data); - else if (what == "dog") dog = DogLike(data); - else if (what == "vow") vow = VowLike(data); - else if (what == "pot") pot = PotLike(data); + if (what == "vat") vat = VatLike(data); + else if (what == "cat") cat = CatLike(data); + else if (what == "dog") dog = DogLike(data); + else if (what == "vow") vow = VowLike(data); + else if (what == "pot") pot = PotLike(data); else if (what == "spot") spot = SpotLike(data); else if (what == "cure") cure = CureLike(data); else revert("End/file-unrecognized-param"); emit File(what, data); } + function file(bytes32 what, uint256 data) external auth { require(live == 1, "End/not-live"); if (what == "wait") wait = data; @@ -362,7 +380,7 @@ contract End { (, uint256 rate,,,) = vat.ilks(ilk); (, uint256 tab, uint256 lot, address usr,,) = clip.sales(id); - vat.suck(address(vow), address(vow), tab); + vat.suck(address(vow), address(vow), tab); clip.yank(id); uint256 art = tab / rate; @@ -380,7 +398,7 @@ contract End { (, uint256 rate,,,) = vat.ilks(ilk); (uint256 bid, uint256 lot,,,, address usr,, uint256 tab) = flip.bids(id); - vat.suck(address(vow), address(vow), tab); + vat.suck(address(vow), address(vow), tab); vat.suck(address(vow), address(this), bid); vat.hope(address(flip)); flip.yank(id); @@ -401,7 +419,7 @@ contract End { uint256 wad = min(ink, owe); gap[ilk] = add(gap[ilk], sub(owe, wad)); - require(wad <= 2**255 && art <= 2**255, "End/overflow"); + require(wad <= 2 ** 255 && art <= 2 ** 255, "End/overflow"); vat.grab(ilk, urn, address(this), address(vow), -int256(wad), -int256(art)); emit Skim(ilk, urn, wad, art); } @@ -410,7 +428,7 @@ contract End { require(live == 0, "End/still-live"); (uint256 ink, uint256 art) = vat.urns(ilk, msg.sender); require(art == 0, "End/art-not-zero"); - require(ink <= 2**255, "End/overflow"); + require(ink <= 2 ** 255, "End/overflow"); vat.grab(ilk, msg.sender, msg.sender, address(vow), -int256(ink), 0); emit Free(ilk, msg.sender, ink); } @@ -423,6 +441,7 @@ contract End { debt = sub(vat.debt(), cure.tell()); emit Thaw(); } + function flow(bytes32 ilk) external { require(debt != 0, "End/debt-zero"); require(fix[ilk] == 0, "End/fix-ilk-already-defined"); @@ -439,6 +458,7 @@ contract End { bag[msg.sender] = add(bag[msg.sender], wad); emit Pack(msg.sender, wad); } + function cash(bytes32 ilk, uint256 wad) external { require(fix[ilk] != 0, "End/fix-ilk-not-defined"); vat.flux(ilk, address(this), msg.sender, rmul(wad, fix[ilk])); diff --git a/src/flap.sol b/src/flap.sol index 8a0125bb..731718a5 100644 --- a/src/flap.sol +++ b/src/flap.sol @@ -25,11 +25,12 @@ pragma solidity ^0.6.12; // New deployments of this contract will need to include custom events (TO DO). interface VatLike { - function move(address,address,uint) external; + function move(address, address, uint256) external; } + interface GemLike { - function move(address,address,uint) external; - function burn(address,uint) external; + function move(address, address, uint256) external; + function burn(address, uint256) external; } /* @@ -44,43 +45,45 @@ interface GemLike { contract Flapper { // --- Auth --- - mapping (address => uint) public wards; - function rely(address usr) external auth { wards[usr] = 1; } - function deny(address usr) external auth { wards[usr] = 0; } - modifier auth { + mapping(address => uint256) public wards; + + function rely(address usr) external auth { + wards[usr] = 1; + } + + function deny(address usr) external auth { + wards[usr] = 0; + } + modifier auth() { require(wards[msg.sender] == 1, "Flapper/not-authorized"); _; } // --- Data --- struct Bid { - uint256 bid; // gems paid [wad] - uint256 lot; // dai in return for bid [rad] - address guy; // high bidder - uint48 tic; // bid expiry time [unix epoch time] - uint48 end; // auction expiry time [unix epoch time] + uint256 bid; // gems paid [wad] + uint256 lot; // dai in return for bid [rad] + address guy; // high bidder + uint48 tic; // bid expiry time [unix epoch time] + uint48 end; // auction expiry time [unix epoch time] } - mapping (uint => Bid) public bids; + mapping(uint256 => Bid) public bids; - VatLike public vat; // CDP Engine - GemLike public gem; + VatLike public vat; // CDP Engine + GemLike public gem; - uint256 constant ONE = 1.00E18; - uint256 public beg = 1.05E18; // 5% minimum bid increase - uint48 public ttl = 3 hours; // 3 hours bid duration [seconds] - uint48 public tau = 2 days; // 2 days total auction length [seconds] - uint256 public kicks = 0; - uint256 public live; // Active Flag - uint256 public lid; // max dai to be in auction at one time [rad] - uint256 public fill; // current dai in auction [rad] + uint256 constant ONE = 1.0e18; + uint256 public beg = 1.05e18; // 5% minimum bid increase + uint48 public ttl = 3 hours; // 3 hours bid duration [seconds] + uint48 public tau = 2 days; // 2 days total auction length [seconds] + uint256 public kicks = 0; + uint256 public live; // Active Flag + uint256 public lid; // max dai to be in auction at one time [rad] + uint256 public fill; // current dai in auction [rad] // --- Events --- - event Kick( - uint256 id, - uint256 lot, - uint256 bid - ); + event Kick(uint256 id, uint256 lot, uint256 bid); // --- Init --- constructor(address vat_, address gem_) public { @@ -94,18 +97,21 @@ contract Flapper { function add(uint48 x, uint48 y) internal pure returns (uint48 z) { require((z = x + y) >= x); } - function add256(uint x, uint y) internal pure returns (uint z) { + + function add256(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } - function sub(uint x, uint y) internal pure returns (uint z) { + + function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } - function mul(uint x, uint y) internal pure returns (uint z) { + + function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } // --- Admin --- - function file(bytes32 what, uint data) external auth { + function file(bytes32 what, uint256 data) external auth { if (what == "beg") beg = data; else if (what == "ttl") ttl = uint48(data); else if (what == "tau") tau = uint48(data); @@ -114,35 +120,37 @@ contract Flapper { } // --- Auction --- - function kick(uint lot, uint bid) external auth returns (uint id) { + function kick(uint256 lot, uint256 bid) external auth returns (uint256 id) { require(live == 1, "Flapper/not-live"); - require(kicks < uint(-1), "Flapper/overflow"); + require(kicks < uint256(-1), "Flapper/overflow"); fill = add256(fill, lot); require(fill <= lid, "Flapper/over-lid"); id = ++kicks; bids[id].bid = bid; bids[id].lot = lot; - bids[id].guy = msg.sender; // configurable?? + bids[id].guy = msg.sender; // configurable?? bids[id].end = add(uint48(now), tau); vat.move(msg.sender, address(this), lot); emit Kick(id, lot, bid); } - function tick(uint id) external { + + function tick(uint256 id) external { require(bids[id].end < now, "Flapper/not-finished"); require(bids[id].tic == 0, "Flapper/bid-already-placed"); bids[id].end = add(uint48(now), tau); } - function tend(uint id, uint lot, uint bid) external { + + function tend(uint256 id, uint256 lot, uint256 bid) external { require(live == 1, "Flapper/not-live"); require(bids[id].guy != address(0), "Flapper/guy-not-set"); require(bids[id].tic > now || bids[id].tic == 0, "Flapper/already-finished-tic"); require(bids[id].end > now, "Flapper/already-finished-end"); require(lot == bids[id].lot, "Flapper/lot-not-matching"); - require(bid > bids[id].bid, "Flapper/bid-not-higher"); + require(bid > bids[id].bid, "Flapper/bid-not-higher"); require(mul(bid, ONE) >= mul(beg, bids[id].bid), "Flapper/insufficient-increase"); if (msg.sender != bids[id].guy) { @@ -154,7 +162,8 @@ contract Flapper { bids[id].bid = bid; bids[id].tic = add(uint48(now), ttl); } - function deal(uint id) external { + + function deal(uint256 id) external { require(live == 1, "Flapper/not-live"); require(bids[id].tic != 0 && (bids[id].tic < now || bids[id].end < now), "Flapper/not-finished"); uint256 lot = bids[id].lot; @@ -164,11 +173,12 @@ contract Flapper { fill = sub(fill, lot); } - function cage(uint rad) external auth { - live = 0; - vat.move(address(this), msg.sender, rad); + function cage(uint256 rad) external auth { + live = 0; + vat.move(address(this), msg.sender, rad); } - function yank(uint id) external { + + function yank(uint256 id) external { require(live == 0, "Flapper/still-live"); require(bids[id].guy != address(0), "Flapper/guy-not-set"); gem.move(address(this), bids[id].guy, bids[id].bid); diff --git a/src/flip.sol b/src/flip.sol index 5b40dcab..8e5b091d 100644 --- a/src/flip.sol +++ b/src/flip.sol @@ -24,8 +24,8 @@ pragma solidity >=0.5.12; // New deployments of this contract will need to include custom events (TO DO). interface VatLike { - function move(address,address,uint256) external; - function flux(bytes32,address,address,uint256) external; + function move(address, address, uint256) external; + function flux(bytes32, address, address, uint256) external; } interface CatLike { @@ -48,47 +48,46 @@ interface CatLike { contract Flipper { // --- Auth --- - mapping (address => uint256) public wards; - function rely(address usr) external auth { wards[usr] = 1; } - function deny(address usr) external auth { wards[usr] = 0; } - modifier auth { + mapping(address => uint256) public wards; + + function rely(address usr) external auth { + wards[usr] = 1; + } + + function deny(address usr) external auth { + wards[usr] = 0; + } + modifier auth() { require(wards[msg.sender] == 1, "Flipper/not-authorized"); _; } // --- Data --- struct Bid { - uint256 bid; // dai paid [rad] - uint256 lot; // gems in return for bid [wad] - address guy; // high bidder - uint48 tic; // bid expiry time [unix epoch time] - uint48 end; // auction expiry time [unix epoch time] + uint256 bid; // dai paid [rad] + uint256 lot; // gems in return for bid [wad] + address guy; // high bidder + uint48 tic; // bid expiry time [unix epoch time] + uint48 end; // auction expiry time [unix epoch time] address usr; address gal; - uint256 tab; // total dai wanted [rad] + uint256 tab; // total dai wanted [rad] } - mapping (uint256 => Bid) public bids; + mapping(uint256 => Bid) public bids; - VatLike public vat; // CDP Engine - bytes32 public ilk; // collateral type + VatLike public vat; // CDP Engine + bytes32 public ilk; // collateral type - uint256 constant ONE = 1.00E18; - uint256 public beg = 1.05E18; // 5% minimum bid increase - uint48 public ttl = 3 hours; // 3 hours bid duration [seconds] - uint48 public tau = 2 days; // 2 days total auction length [seconds] + uint256 constant ONE = 1.0e18; + uint256 public beg = 1.05e18; // 5% minimum bid increase + uint48 public ttl = 3 hours; // 3 hours bid duration [seconds] + uint48 public tau = 2 days; // 2 days total auction length [seconds] uint256 public kicks = 0; - CatLike public cat; // cat liquidation module + CatLike public cat; // cat liquidation module // --- Events --- - event Kick( - uint256 id, - uint256 lot, - uint256 bid, - uint256 tab, - address indexed usr, - address indexed gal - ); + event Kick(uint256 id, uint256 lot, uint256 bid, uint256 tab, address indexed usr, address indexed gal); // --- Init --- constructor(address vat_, address cat_, bytes32 ilk_) public { @@ -102,6 +101,7 @@ contract Flipper { function add(uint48 x, uint48 y) internal pure returns (uint48 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); } @@ -113,22 +113,21 @@ contract Flipper { else if (what == "tau") tau = uint48(data); else revert("Flipper/file-unrecognized-param"); } + function file(bytes32 what, address data) external auth { if (what == "cat") cat = CatLike(data); else revert("Flipper/file-unrecognized-param"); } // --- Auction --- - function kick(address usr, address gal, uint256 tab, uint256 lot, uint256 bid) - public auth returns (uint256 id) - { - require(kicks < uint256(-1), "Flipper/overflow"); + function kick(address usr, address gal, uint256 tab, uint256 lot, uint256 bid) public auth returns (uint256 id) { + require(kicks < type(uint256).max, "Flipper/overflow"); id = ++kicks; bids[id].bid = bid; bids[id].lot = lot; - bids[id].guy = msg.sender; // configurable?? - bids[id].end = add(uint48(now), tau); + bids[id].guy = msg.sender; // configurable?? + bids[id].end = add(uint48(block.timestamp), tau); bids[id].usr = usr; bids[id].gal = gal; bids[id].tab = tab; @@ -137,19 +136,21 @@ contract Flipper { emit Kick(id, lot, bid, tab, usr, gal); } + function tick(uint256 id) external { - require(bids[id].end < now, "Flipper/not-finished"); + require(bids[id].end < block.timestamp, "Flipper/not-finished"); require(bids[id].tic == 0, "Flipper/bid-already-placed"); - bids[id].end = add(uint48(now), tau); + bids[id].end = add(uint48(block.timestamp), tau); } + function tend(uint256 id, uint256 lot, uint256 bid) external { require(bids[id].guy != address(0), "Flipper/guy-not-set"); - require(bids[id].tic > now || bids[id].tic == 0, "Flipper/already-finished-tic"); - require(bids[id].end > now, "Flipper/already-finished-end"); + require(bids[id].tic > block.timestamp || bids[id].tic == 0, "Flipper/already-finished-tic"); + require(bids[id].end > block.timestamp, "Flipper/already-finished-end"); require(lot == bids[id].lot, "Flipper/lot-not-matching"); require(bid <= bids[id].tab, "Flipper/higher-than-tab"); - require(bid > bids[id].bid, "Flipper/bid-not-higher"); + require(bid > bids[id].bid, "Flipper/bid-not-higher"); require(mul(bid, ONE) >= mul(beg, bids[id].bid) || bid == bids[id].tab, "Flipper/insufficient-increase"); if (msg.sender != bids[id].guy) { @@ -159,12 +160,13 @@ contract Flipper { vat.move(msg.sender, bids[id].gal, bid - bids[id].bid); bids[id].bid = bid; - bids[id].tic = add(uint48(now), ttl); + bids[id].tic = add(uint48(block.timestamp), ttl); } + function dent(uint256 id, uint256 lot, uint256 bid) external { require(bids[id].guy != address(0), "Flipper/guy-not-set"); - require(bids[id].tic > now || bids[id].tic == 0, "Flipper/already-finished-tic"); - require(bids[id].end > now, "Flipper/already-finished-end"); + require(bids[id].tic > block.timestamp || bids[id].tic == 0, "Flipper/already-finished-tic"); + require(bids[id].end > block.timestamp, "Flipper/already-finished-end"); require(bid == bids[id].bid, "Flipper/not-matching-bid"); require(bid == bids[id].tab, "Flipper/tend-not-finished"); @@ -178,10 +180,14 @@ contract Flipper { vat.flux(ilk, address(this), bids[id].usr, bids[id].lot - lot); bids[id].lot = lot; - bids[id].tic = add(uint48(now), ttl); + bids[id].tic = add(uint48(block.timestamp), ttl); } + function deal(uint256 id) external { - require(bids[id].tic != 0 && (bids[id].tic < now || bids[id].end < now), "Flipper/not-finished"); + require( + bids[id].tic != 0 && (bids[id].tic < block.timestamp || bids[id].end < block.timestamp), + "Flipper/not-finished" + ); cat.claw(bids[id].tab); vat.flux(ilk, address(this), bids[id].guy, bids[id].lot); delete bids[id]; diff --git a/src/flop.sol b/src/flop.sol index 7752cb63..ca34ce78 100644 --- a/src/flop.sol +++ b/src/flop.sol @@ -24,15 +24,17 @@ pragma solidity ^0.6.12; // New deployments of this contract will need to include custom events (TO DO). interface VatLike { - function move(address,address,uint) external; - function suck(address,address,uint) external; + function move(address, address, uint256) external; + function suck(address, address, uint256) external; } + interface GemLike { - function mint(address,uint) external; + function mint(address, uint256) external; } + interface VowLike { - function Ash() external returns (uint); - function kiss(uint) external; + function Ash() external returns (uint256); + function kiss(uint256) external; } /* @@ -48,44 +50,45 @@ interface VowLike { contract Flopper { // --- Auth --- - mapping (address => uint) public wards; - function rely(address usr) external auth { wards[usr] = 1; } - function deny(address usr) external auth { wards[usr] = 0; } - modifier auth { + mapping(address => uint256) public wards; + + function rely(address usr) external auth { + wards[usr] = 1; + } + + function deny(address usr) external auth { + wards[usr] = 0; + } + modifier auth() { require(wards[msg.sender] == 1, "Flopper/not-authorized"); _; } // --- Data --- struct Bid { - uint256 bid; // dai paid [rad] - uint256 lot; // gems in return for bid [wad] - address guy; // high bidder - uint48 tic; // bid expiry time [unix epoch time] - uint48 end; // auction expiry time [unix epoch time] + uint256 bid; // dai paid [rad] + uint256 lot; // gems in return for bid [wad] + address guy; // high bidder + uint48 tic; // bid expiry time [unix epoch time] + uint48 end; // auction expiry time [unix epoch time] } - mapping (uint => Bid) public bids; + mapping(uint256 => Bid) public bids; - VatLike public vat; // CDP Engine - GemLike public gem; + VatLike public vat; // CDP Engine + GemLike public gem; - uint256 constant ONE = 1.00E18; - uint256 public beg = 1.05E18; // 5% minimum bid increase - uint256 public pad = 1.50E18; // 50% lot increase for tick - uint48 public ttl = 3 hours; // 3 hours bid lifetime [seconds] - uint48 public tau = 2 days; // 2 days total auction length [seconds] - uint256 public kicks = 0; - uint256 public live; // Active Flag - address public vow; // not used until shutdown + uint256 constant ONE = 1.0e18; + uint256 public beg = 1.05e18; // 5% minimum bid increase + uint256 public pad = 1.5e18; // 50% lot increase for tick + uint48 public ttl = 3 hours; // 3 hours bid lifetime [seconds] + uint48 public tau = 2 days; // 2 days total auction length [seconds] + uint256 public kicks = 0; + uint256 public live; // Active Flag + address public vow; // not used until shutdown // --- Events --- - event Kick( - uint256 id, - uint256 lot, - uint256 bid, - address indexed gal - ); + event Kick(uint256 id, uint256 lot, uint256 bid, address indexed gal); // --- Init --- constructor(address vat_, address gem_) public { @@ -99,15 +102,18 @@ contract Flopper { function add(uint48 x, uint48 y) internal pure returns (uint48 z) { require((z = x + y) >= x); } - function mul(uint x, uint y) internal pure returns (uint z) { + + function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } - function min(uint x, uint y) internal pure returns (uint z) { - if (x > y) { z = y; } else { z = x; } + + function min(uint256 x, uint256 y) internal pure returns (uint256 z) { + if (x > y) z = y; + else z = x; } // --- Admin --- - function file(bytes32 what, uint data) external auth { + function file(bytes32 what, uint256 data) external auth { if (what == "beg") beg = data; else if (what == "pad") pad = data; else if (what == "ttl") ttl = uint48(data); @@ -116,9 +122,9 @@ contract Flopper { } // --- Auction --- - function kick(address gal, uint lot, uint bid) external auth returns (uint id) { + function kick(address gal, uint256 lot, uint256 bid) external auth returns (uint256 id) { require(live == 1, "Flopper/not-live"); - require(kicks < uint(-1), "Flopper/overflow"); + require(kicks < uint256(-1), "Flopper/overflow"); id = ++kicks; bids[id].bid = bid; @@ -128,20 +134,22 @@ contract Flopper { emit Kick(id, lot, bid, gal); } - function tick(uint id) external { + + function tick(uint256 id) external { require(bids[id].end < now, "Flopper/not-finished"); require(bids[id].tic == 0, "Flopper/bid-already-placed"); bids[id].lot = mul(pad, bids[id].lot) / ONE; bids[id].end = add(uint48(now), tau); } - function dent(uint id, uint lot, uint bid) external { + + function dent(uint256 id, uint256 lot, uint256 bid) external { require(live == 1, "Flopper/not-live"); require(bids[id].guy != address(0), "Flopper/guy-not-set"); require(bids[id].tic > now || bids[id].tic == 0, "Flopper/already-finished-tic"); require(bids[id].end > now, "Flopper/already-finished-end"); require(bid == bids[id].bid, "Flopper/not-matching-bid"); - require(lot < bids[id].lot, "Flopper/lot-not-lower"); + require(lot < bids[id].lot, "Flopper/lot-not-lower"); require(mul(beg, lot) <= mul(bids[id].lot, ONE), "Flopper/insufficient-decrease"); if (msg.sender != bids[id].guy) { @@ -149,7 +157,7 @@ contract Flopper { // on first dent, clear as much Ash as possible if (bids[id].tic == 0) { - uint Ash = VowLike(bids[id].guy).Ash(); + uint256 Ash = VowLike(bids[id].guy).Ash(); VowLike(bids[id].guy).kiss(min(bid, Ash)); } @@ -159,7 +167,8 @@ contract Flopper { bids[id].lot = lot; bids[id].tic = add(uint48(now), ttl); } - function deal(uint id) external { + + function deal(uint256 id) external { require(live == 1, "Flopper/not-live"); require(bids[id].tic != 0 && (bids[id].tic < now || bids[id].end < now), "Flopper/not-finished"); gem.mint(bids[id].guy, bids[id].lot); @@ -168,10 +177,11 @@ contract Flopper { // --- Shutdown --- function cage() external auth { - live = 0; - vow = msg.sender; + live = 0; + vow = msg.sender; } - function yank(uint id) external { + + function yank(uint256 id) external { require(live == 0, "Flopper/still-live"); require(bids[id].guy != address(0), "Flopper/guy-not-set"); vat.suck(vow, bids[id].guy, bids[id].bid); diff --git a/src/join.sol b/src/join.sol index 42b01c91..86055979 100644 --- a/src/join.sol +++ b/src/join.sol @@ -24,19 +24,19 @@ pragma solidity ^0.6.12; // New deployments of this contract will need to include custom events (TO DO). interface GemLike { - function decimals() external view returns (uint); - function transfer(address,uint) external returns (bool); - function transferFrom(address,address,uint) external returns (bool); + function decimals() external view returns (uint256); + function transfer(address, uint256) external returns (bool); + function transferFrom(address, address, uint256) external returns (bool); } interface DSTokenLike { - function mint(address,uint) external; - function burn(address,uint) external; + function mint(address, uint256) external; + function burn(address, uint256) external; } interface VatLike { - function slip(bytes32,address,int) external; - function move(address,address,uint) external; + function slip(bytes32, address, int256) external; + function move(address, address, uint256) external; } /* @@ -65,25 +65,27 @@ interface VatLike { contract GemJoin { // --- Auth --- - mapping (address => uint) public wards; + 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 { + modifier auth() { require(wards[msg.sender] == 1, "GemJoin/not-authorized"); _; } - VatLike public vat; // CDP Engine - bytes32 public ilk; // Collateral Type + VatLike public vat; // CDP Engine + bytes32 public ilk; // Collateral Type GemLike public gem; - uint public dec; - uint public live; // Active Flag + uint256 public dec; + uint256 public live; // Active Flag // Events event Rely(address indexed usr); @@ -101,20 +103,23 @@ contract GemJoin { dec = gem.decimals(); emit Rely(msg.sender); } + function cage() external auth { live = 0; emit Cage(); } - function join(address usr, uint wad) external { + + function join(address usr, uint256 wad) external { require(live == 1, "GemJoin/not-live"); - require(int(wad) >= 0, "GemJoin/overflow"); - vat.slip(ilk, usr, int(wad)); + require(int256(wad) >= 0, "GemJoin/overflow"); + vat.slip(ilk, usr, int256(wad)); require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin/failed-transfer"); emit Join(usr, wad); } - function exit(address usr, uint wad) external { + + function exit(address usr, uint256 wad) external { require(wad <= 2 ** 255, "GemJoin/overflow"); - vat.slip(ilk, msg.sender, -int(wad)); + vat.slip(ilk, msg.sender, -int256(wad)); require(gem.transfer(usr, wad), "GemJoin/failed-transfer"); emit Exit(usr, wad); } @@ -122,23 +127,25 @@ contract GemJoin { contract DaiJoin { // --- Auth --- - mapping (address => uint) public wards; + 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 { + modifier auth() { require(wards[msg.sender] == 1, "DaiJoin/not-authorized"); _; } - VatLike public vat; // CDP Engine - DSTokenLike public dai; // Stablecoin Token - uint public live; // Active Flag + VatLike public vat; // CDP Engine + DSTokenLike public dai; // Stablecoin Token + uint256 public live; // Active Flag // Events event Rely(address indexed usr); @@ -153,20 +160,24 @@ contract DaiJoin { vat = VatLike(vat_); dai = DSTokenLike(dai_); } + function cage() external auth { live = 0; emit Cage(); } - uint constant ONE = 10 ** 27; - function mul(uint x, uint y) internal pure returns (uint z) { + uint256 constant ONE = 10 ** 27; + + function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } - function join(address usr, uint wad) external { + + function join(address usr, uint256 wad) external { vat.move(address(this), usr, mul(ONE, wad)); dai.burn(msg.sender, wad); emit Join(usr, wad); } - function exit(address usr, uint wad) external { + + function exit(address usr, uint256 wad) external { require(live == 1, "DaiJoin/not-live"); vat.move(msg.sender, address(this), mul(ONE, wad)); dai.mint(usr, wad); diff --git a/src/jug.sol b/src/jug.sol index dae9b263..5c24e9f1 100644 --- a/src/jug.sol +++ b/src/jug.sol @@ -24,33 +24,41 @@ pragma solidity ^0.6.12; // New deployments of this contract will need to include custom events (TO DO). interface VatLike { - function ilks(bytes32) external returns ( - uint256 Art, // [wad] - uint256 rate // [ray] - ); - function fold(bytes32,address,int) external; + function ilks(bytes32) + external + returns ( + uint256 Art, // [wad] + uint256 rate // [ray] + ); + function fold(bytes32, address, int256) external; } contract Jug { // --- Auth --- - mapping (address => uint) public wards; - function rely(address usr) external auth { wards[usr] = 1; } - function deny(address usr) external auth { wards[usr] = 0; } - modifier auth { + mapping(address => uint256) public wards; + + function rely(address usr) external auth { + wards[usr] = 1; + } + + function deny(address usr) external auth { + wards[usr] = 0; + } + modifier auth() { require(wards[msg.sender] == 1, "Jug/not-authorized"); _; } // --- Data --- struct Ilk { - uint256 duty; // Collateral-specific, per-second stability fee contribution [ray] - uint256 rho; // Time of last drip [unix epoch time] + uint256 duty; // Collateral-specific, per-second stability fee contribution [ray] + uint256 rho; // Time of last drip [unix epoch time] } - mapping (bytes32 => Ilk) public ilks; - VatLike public vat; // CDP Engine - address public vow; // Debt Engine - uint256 public base; // Global, per-second stability fee contribution [ray] + mapping(bytes32 => Ilk) public ilks; + VatLike public vat; // CDP Engine + address public vow; // Debt Engine + uint256 public base; // Global, per-second stability fee contribution [ray] // --- Init --- constructor(address vat_) public { @@ -59,39 +67,49 @@ contract Jug { } // --- Math --- - function _rpow(uint x, uint n, uint b) internal pure returns (uint z) { - assembly { - switch x case 0 {switch n case 0 {z := b} default {z := 0}} - default { - switch mod(n, 2) case 0 { z := b } default { z := x } - let half := div(b, 2) // for rounding. - for { n := div(n, 2) } n { n := div(n,2) } { - let xx := mul(x, x) - if iszero(eq(div(xx, x), x)) { revert(0,0) } - let xxRound := add(xx, half) - if lt(xxRound, xx) { revert(0,0) } - x := div(xxRound, b) - if mod(n,2) { - let zx := mul(z, x) - if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } - let zxRound := add(zx, half) - if lt(zxRound, zx) { revert(0,0) } - z := div(zxRound, b) + function _rpow(uint256 x, uint256 n, uint256 b) internal pure returns (uint256 z) { + assembly { + switch x + case 0 { + switch n + case 0 { z := b } + default { z := 0 } + } + default { + switch mod(n, 2) + case 0 { z := b } + default { z := x } + let half := div(b, 2) // for rounding. + for { n := div(n, 2) } n { n := div(n, 2) } { + let xx := mul(x, x) + if iszero(eq(div(xx, x), x)) { revert(0, 0) } + let xxRound := add(xx, half) + if lt(xxRound, xx) { revert(0, 0) } + x := div(xxRound, b) + if mod(n, 2) { + let zx := mul(z, x) + if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) } + let zxRound := add(zx, half) + if lt(zxRound, zx) { revert(0, 0) } + z := div(zxRound, b) + } + } } - } } - } } uint256 constant ONE = 10 ** 27; - function _add(uint x, uint y) internal pure returns (uint z) { + + function _add(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x + y; require(z >= x); } - function _diff(uint x, uint y) internal pure returns (int z) { - z = int(x) - int(y); - require(int(x) >= 0 && int(y) >= 0); + + function _diff(uint256 x, uint256 y) internal pure returns (int256 z) { + z = int256(x) - int256(y); + require(int256(x) >= 0 && int256(y) >= 0); } - function _rmul(uint x, uint y) internal pure returns (uint z) { + + function _rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * y; require(y == 0 || z / y == x); z = z / ONE; @@ -102,26 +120,29 @@ contract Jug { Ilk storage i = ilks[ilk]; require(i.duty == 0, "Jug/ilk-already-init"); i.duty = ONE; - i.rho = now; + i.rho = now; } - function file(bytes32 ilk, bytes32 what, uint data) external auth { + + function file(bytes32 ilk, bytes32 what, uint256 data) external auth { require(now == ilks[ilk].rho, "Jug/rho-not-updated"); if (what == "duty") ilks[ilk].duty = data; else revert("Jug/file-unrecognized-param"); } - function file(bytes32 what, uint data) external auth { + + function file(bytes32 what, uint256 data) external auth { if (what == "base") base = data; else revert("Jug/file-unrecognized-param"); } + function file(bytes32 what, address data) external auth { if (what == "vow") vow = data; else revert("Jug/file-unrecognized-param"); } // --- Stability Fee Collection --- - function drip(bytes32 ilk) external returns (uint rate) { + function drip(bytes32 ilk) external returns (uint256 rate) { require(now >= ilks[ilk].rho, "Jug/invalid-now"); - (, uint prev) = vat.ilks(ilk); + (, uint256 prev) = vat.ilks(ilk); rate = _rmul(_rpow(_add(base, ilks[ilk].duty), now - ilks[ilk].rho, ONE), prev); vat.fold(ilk, vow, _diff(rate, prev)); ilks[ilk].rho = now; diff --git a/src/pot.sol b/src/pot.sol index cae58cda..2b2a9452 100644 --- a/src/pot.sol +++ b/src/pot.sol @@ -43,32 +43,38 @@ pragma solidity ^0.6.12; */ interface VatLike { - function move(address,address,uint256) external; - function suck(address,address,uint256) external; + function move(address, address, uint256) external; + function suck(address, address, uint256) external; } contract Pot { // --- Auth --- - mapping (address => uint) public wards; - function rely(address guy) external auth { wards[guy] = 1; } - function deny(address guy) external auth { wards[guy] = 0; } - modifier auth { + mapping(address => uint256) public wards; + + function rely(address guy) external auth { + wards[guy] = 1; + } + + function deny(address guy) external auth { + wards[guy] = 0; + } + modifier auth() { require(wards[msg.sender] == 1, "Pot/not-authorized"); _; } // --- Data --- - mapping (address => uint256) public pie; // Normalised Savings Dai [wad] + mapping(address => uint256) public pie; // Normalised Savings Dai [wad] - uint256 public Pie; // Total Normalised Savings Dai [wad] - uint256 public dsr; // The Dai Savings Rate [ray] - uint256 public chi; // The Rate Accumulator [ray] + uint256 public Pie; // Total Normalised Savings Dai [wad] + uint256 public dsr; // The Dai Savings Rate [ray] + uint256 public chi; // The Rate Accumulator [ray] - VatLike public vat; // CDP Engine - address public vow; // Debt Engine - uint256 public rho; // Time of last drip [unix epoch time] + VatLike public vat; // CDP Engine + address public vow; // Debt Engine + uint256 public rho; // Time of last drip [unix epoch time] - uint256 public live; // Active Flag + uint256 public live; // Active Flag // --- Init --- constructor(address vat_) public { @@ -82,23 +88,31 @@ contract Pot { // --- Math --- uint256 constant ONE = 10 ** 27; - function _rpow(uint x, uint n, uint base) internal pure returns (uint z) { + + function _rpow(uint256 x, uint256 n, uint256 base) internal pure returns (uint256 z) { assembly { - switch x case 0 {switch n case 0 {z := base} default {z := 0}} + switch x + case 0 { + switch n + case 0 { z := base } + default { z := 0 } + } default { - switch mod(n, 2) case 0 { z := base } default { z := x } - let half := div(base, 2) // for rounding. - for { n := div(n, 2) } n { n := div(n,2) } { + switch mod(n, 2) + case 0 { z := base } + default { z := x } + let half := div(base, 2) // for rounding. + for { n := div(n, 2) } n { n := div(n, 2) } { let xx := mul(x, x) - if iszero(eq(div(xx, x), x)) { revert(0,0) } + if iszero(eq(div(xx, x), x)) { revert(0, 0) } let xxRound := add(xx, half) - if lt(xxRound, xx) { revert(0,0) } + if lt(xxRound, xx) { revert(0, 0) } x := div(xxRound, base) - if mod(n,2) { + if mod(n, 2) { let zx := mul(z, x) - if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } + if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) } let zxRound := add(zx, half) - if lt(zxRound, zx) { revert(0,0) } + if lt(zxRound, zx) { revert(0, 0) } z := div(zxRound, base) } } @@ -106,19 +120,19 @@ contract Pot { } } - function _rmul(uint x, uint y) internal pure returns (uint z) { + function _rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = _mul(x, y) / ONE; } - function _add(uint x, uint y) internal pure returns (uint z) { + function _add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } - function _sub(uint x, uint y) internal pure returns (uint z) { + function _sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } - function _mul(uint x, uint y) internal pure returns (uint z) { + function _mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } @@ -141,26 +155,26 @@ contract Pot { } // --- Savings Rate Accumulation --- - function drip() external returns (uint tmp) { + function drip() external returns (uint256 tmp) { require(now >= rho, "Pot/invalid-now"); tmp = _rmul(_rpow(dsr, now - rho, ONE), chi); - uint chi_ = _sub(tmp, chi); + uint256 chi_ = _sub(tmp, chi); chi = tmp; rho = now; vat.suck(address(vow), address(this), _mul(Pie, chi_)); } // --- Savings Dai Management --- - function join(uint wad) external { + function join(uint256 wad) external { require(now == rho, "Pot/rho-not-updated"); pie[msg.sender] = _add(pie[msg.sender], wad); - Pie = _add(Pie, wad); + Pie = _add(Pie, wad); vat.move(msg.sender, address(this), _mul(chi, wad)); } - function exit(uint wad) external { + function exit(uint256 wad) external { pie[msg.sender] = _sub(pie[msg.sender], wad); - Pie = _sub(Pie, wad); + Pie = _sub(Pie, wad); vat.move(address(this), msg.sender, _mul(chi, wad)); } } diff --git a/src/spot.sol b/src/spot.sol index 2f5b98d9..85d7bedd 100644 --- a/src/spot.sol +++ b/src/spot.sol @@ -22,7 +22,7 @@ pragma solidity ^0.6.12; // New deployments of this contract will need to include custom events (TO DO). interface VatLike { - function file(bytes32, bytes32, uint) external; + function file(bytes32, bytes32, uint256) external; } interface PipLike { @@ -31,32 +31,38 @@ interface PipLike { contract Spotter { // --- Auth --- - mapping (address => uint) public wards; - function rely(address guy) external auth { wards[guy] = 1; } - function deny(address guy) external auth { wards[guy] = 0; } - modifier auth { + mapping(address => uint256) public wards; + + function rely(address guy) external auth { + wards[guy] = 1; + } + + function deny(address guy) external auth { + wards[guy] = 0; + } + modifier auth() { require(wards[msg.sender] == 1, "Spotter/not-authorized"); _; } // --- Data --- struct Ilk { - PipLike pip; // Price Feed - uint256 mat; // Liquidation ratio [ray] + PipLike pip; // Price Feed + uint256 mat; // Liquidation ratio [ray] } - mapping (bytes32 => Ilk) public ilks; + mapping(bytes32 => Ilk) public ilks; - VatLike public vat; // CDP Engine - uint256 public par; // ref per dai [ray] + VatLike public vat; // CDP Engine + uint256 public par; // ref per dai [ray] uint256 public live; // --- Events --- event Poke( - bytes32 ilk, - bytes32 val, // [wad] - uint256 spot // [ray] + bytes32 ilk, + bytes32 val, // [wad] + uint256 spot // [ray] ); // --- Init --- @@ -68,12 +74,13 @@ contract Spotter { } // --- Math --- - uint constant ONE = 10 ** 27; + uint256 constant ONE = 10 ** 27; - function mul(uint x, uint y) internal pure returns (uint z) { + function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } - function rdiv(uint x, uint y) internal pure returns (uint z) { + + function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, ONE) / y; } @@ -83,12 +90,14 @@ contract Spotter { if (what == "pip") ilks[ilk].pip = PipLike(pip_); else revert("Spotter/file-unrecognized-param"); } - function file(bytes32 what, uint data) external auth { + + function file(bytes32 what, uint256 data) external auth { require(live == 1, "Spotter/not-live"); if (what == "par") par = data; else revert("Spotter/file-unrecognized-param"); } - function file(bytes32 ilk, bytes32 what, uint data) external auth { + + function file(bytes32 ilk, bytes32 what, uint256 data) external auth { require(live == 1, "Spotter/not-live"); if (what == "mat") ilks[ilk].mat = data; else revert("Spotter/file-unrecognized-param"); @@ -97,7 +106,7 @@ contract Spotter { // --- Update value --- function poke(bytes32 ilk) external { (bytes32 val, bool has) = ilks[ilk].pip.peek(); - uint256 spot = has ? rdiv(rdiv(mul(uint(val), 10 ** 9), par), ilks[ilk].mat) : 0; + uint256 spot = has ? rdiv(rdiv(mul(uint256(val), 10 ** 9), par), ilks[ilk].mat) : 0; vat.file(ilk, "spot", spot); emit Poke(ilk, val, spot); } diff --git a/src/test/abaci.t.sol b/src/test/abaci.t.sol index 08838464..0f4cd541 100644 --- a/src/test/abaci.t.sol +++ b/src/test/abaci.t.sol @@ -25,7 +25,7 @@ import "../abaci.sol"; interface Hevm { function warp(uint256) external; - function store(address,bytes32,bytes32) external; + function store(address, bytes32, bytes32) external; } contract ClipperTest is DSTest { @@ -34,8 +34,7 @@ contract ClipperTest is DSTest { uint256 RAY = 10 ** 27; // CHEAT_CODE = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D - bytes20 constant CHEAT_CODE = - bytes20(uint160(uint256(keccak256('hevm cheat code')))); + bytes20 constant CHEAT_CODE = bytes20(uint160(uint256(keccak256("hevm cheat code")))); uint256 constant startTime = 604411200; // Used to avoid issues with `now` @@ -44,17 +43,14 @@ contract ClipperTest is DSTest { hevm.warp(startTime); } - function assertEqWithinTolerance( - uint256 x, - uint256 y, - uint256 tolerance) internal { - uint256 diff; - if (x >= y) { - diff = x - y; - } else { - diff = y - x; - } - assertTrue(diff <= tolerance); + function assertEqWithinTolerance(uint256 x, uint256 y, uint256 tolerance) internal { + uint256 diff; + if (x >= y) { + diff = x - y; + } else { + diff = y - x; + } + assertTrue(diff <= tolerance); } function checkExpDecrease( @@ -66,26 +62,24 @@ contract ClipperTest is DSTest { uint256 percentDecrease, uint256 testTime, uint256 tolerance - ) - public - { + ) public { uint256 price; uint256 lastPrice; uint256 testPrice; hevm.warp(startTime); calc.file(bytes32("step"), step); - calc.file(bytes32("cut"), cut); + calc.file(bytes32("cut"), cut); price = calc.price(top, now - tic); assertEq(price, top); - for(uint256 i = 1; i < testTime; i += 1) { + for (uint256 i = 1; i < testTime; i += 1) { hevm.warp(startTime + i); lastPrice = price; price = calc.price(top, now - tic); // Stairstep calculation - if (i % step == 0) { testPrice = lastPrice * percentDecrease / RAY; } - else { testPrice = lastPrice; } + if (i % step == 0) testPrice = lastPrice * percentDecrease / RAY; + else testPrice = lastPrice; assertEqWithinTolerance(testPrice, price, tolerance); } } @@ -97,66 +91,64 @@ contract ClipperTest is DSTest { uint256 step; uint256 testTime = 10 minutes; - /*** Extreme high collateral price ($50m) ***/ uint256 tolerance = 100000000; // Tolerance scales with price - uint256 top = 50000000 * RAY; + uint256 top = 50000000 * RAY; // 1.1234567890% decrease every 1 second // TODO: Check if there's a cleaner way to do this. I was getting rational_const errors. - percentDecrease = RAY - 1.1234567890E27 / 100; + percentDecrease = RAY - 1.123456789e27 / 100; step = 1; checkExpDecrease(calc, percentDecrease, step, top, tic, percentDecrease, testTime, tolerance); // 2.1234567890% decrease every 1 second - percentDecrease = RAY - 2.1234567890E27 / 100; + percentDecrease = RAY - 2.123456789e27 / 100; step = 1; checkExpDecrease(calc, percentDecrease, step, top, tic, percentDecrease, testTime, tolerance); // 1.1234567890% decrease every 5 seconds - percentDecrease = RAY - 1.1234567890E27 / 100; + percentDecrease = RAY - 1.123456789e27 / 100; step = 5; checkExpDecrease(calc, percentDecrease, step, top, tic, percentDecrease, testTime, tolerance); // 2.1234567890% decrease every 5 seconds - percentDecrease = RAY - 2.1234567890E27 / 100; + percentDecrease = RAY - 2.123456789e27 / 100; step = 5; checkExpDecrease(calc, percentDecrease, step, top, tic, percentDecrease, testTime, tolerance); // 1.1234567890% decrease every 5 minutes - percentDecrease = RAY - 1.1234567890E27 / 100; + percentDecrease = RAY - 1.123456789e27 / 100; step = 5 minutes; checkExpDecrease(calc, percentDecrease, step, top, tic, percentDecrease, testTime, tolerance); - /*** Extreme low collateral price ($0.0000001) ***/ tolerance = 1; // Lowest tolerance is 1e-27 top = 1 * RAY / 10000000; // 1.1234567890% decrease every 1 second - percentDecrease = RAY - 1.1234567890E27 / 100; + percentDecrease = RAY - 1.123456789e27 / 100; step = 1; checkExpDecrease(calc, percentDecrease, step, top, tic, percentDecrease, testTime, tolerance); // 2.1234567890% decrease every 1 second - percentDecrease = RAY - 2.1234567890E27 / 100; + percentDecrease = RAY - 2.123456789e27 / 100; step = 1; checkExpDecrease(calc, percentDecrease, step, top, tic, percentDecrease, testTime, tolerance); // 1.1234567890% decrease every 5 seconds - percentDecrease = RAY - 1.1234567890E27 / 100; + percentDecrease = RAY - 1.123456789e27 / 100; step = 5; checkExpDecrease(calc, percentDecrease, step, top, tic, percentDecrease, testTime, tolerance); // 2.1234567890% decrease every 5 seconds - percentDecrease = RAY - 2.1234567890E27 / 100; + percentDecrease = RAY - 2.123456789e27 / 100; step = 5; checkExpDecrease(calc, percentDecrease, step, top, tic, percentDecrease, testTime, tolerance); // 1.1234567890% decrease every 5 minutes - percentDecrease = RAY - 1.1234567890E27 / 100; + percentDecrease = RAY - 1.123456789e27 / 100; step = 5 minutes; checkExpDecrease(calc, percentDecrease, step, top, tic, percentDecrease, testTime, tolerance); } @@ -164,14 +156,16 @@ contract ClipperTest is DSTest { function test_continuous_exp_decrease() public { ExponentialDecrease calc = new ExponentialDecrease(); uint256 tHalf = 900; - uint256 cut = 0.999230132966E27; // ~15 half life, cut ~= e^(ln(1/2)/900) + uint256 cut = 0.999230132966e27; // ~15 half life, cut ~= e^(ln(1/2)/900) calc.file("cut", cut); uint256 top = 4000 * RAY; uint256 expectedPrice = top; - uint256 tolerance = RAY / 1000; // 0.001, i.e 0.1% - for (uint256 i = 0; i < 5; i++) { // will cover initial value + four half-lives - assertEqWithinTolerance(calc.price(top, i*tHalf), expectedPrice, tolerance); + uint256 tolerance = RAY / 1000; // 0.001, i.e 0.1% + + // Made a for loop modification here!! + for (uint256 i = 0; i < 5; i++) { + assertEqWithinTolerance(calc.price(top, i * tHalf), expectedPrice, tolerance); // each loop iteration advances one half-life, so expectedPrice decreases by a factor of 2 expectedPrice /= 2; } @@ -187,43 +181,43 @@ contract ClipperTest is DSTest { uint256 price = calc.price(top, now - tic); assertEq(price, top); - hevm.warp(startTime + 360); // 6min in, 1/10 done + hevm.warp(startTime + 360); // 6min in, 1/10 done price = calc.price(top, now - tic); assertEq(price, (1000 - 100) * RAY); - hevm.warp(startTime + 360 * 2); // 12min in, 2/10 done + hevm.warp(startTime + 360 * 2); // 12min in, 2/10 done price = calc.price(top, now - tic); assertEq(price, (1000 - 100 * 2) * RAY); - hevm.warp(startTime + 360 * 3); // 18min in, 3/10 done + hevm.warp(startTime + 360 * 3); // 18min in, 3/10 done price = calc.price(top, now - tic); assertEq(price, (1000 - 100 * 3) * RAY); - hevm.warp(startTime + 360 * 4); // 24min in, 4/10 done + hevm.warp(startTime + 360 * 4); // 24min in, 4/10 done price = calc.price(top, now - tic); assertEq(price, (1000 - 100 * 4) * RAY); - hevm.warp(startTime + 360 * 5); // 30min in, 5/10 done + hevm.warp(startTime + 360 * 5); // 30min in, 5/10 done price = calc.price(top, now - tic); assertEq(price, (1000 - 100 * 5) * RAY); - hevm.warp(startTime + 360 * 6); // 36min in, 6/10 done + hevm.warp(startTime + 360 * 6); // 36min in, 6/10 done price = calc.price(top, now - tic); assertEq(price, (1000 - 100 * 6) * RAY); - hevm.warp(startTime + 360 * 7); // 42min in, 7/10 done + hevm.warp(startTime + 360 * 7); // 42min in, 7/10 done price = calc.price(top, now - tic); assertEq(price, (1000 - 100 * 7) * RAY); - hevm.warp(startTime + 360 * 8); // 48min in, 8/10 done + hevm.warp(startTime + 360 * 8); // 48min in, 8/10 done price = calc.price(top, now - tic); assertEq(price, (1000 - 100 * 8) * RAY); - hevm.warp(startTime + 360 * 9); // 54min in, 9/10 done + hevm.warp(startTime + 360 * 9); // 54min in, 9/10 done price = calc.price(top, now - tic); assertEq(price, (1000 - 100 * 9) * RAY); - hevm.warp(startTime + 360 * 10); // 60min in, 10/10 done + hevm.warp(startTime + 360 * 10); // 60min in, 10/10 done price = calc.price(top, now - tic); assertEq(price, 0); } diff --git a/src/test/clip.t.sol b/src/test/clip.t.sol index 3eeef243..cb5f8329 100644 --- a/src/test/clip.t.sol +++ b/src/test/clip.t.sol @@ -23,9 +23,9 @@ import "ds-test/test.sol"; import "ds-token/token.sol"; import "ds-value/value.sol"; -import {Vat} from "../vat.sol"; +import {Vat} from "../vat.sol"; import {Spotter} from "../spot.sol"; -import {Vow} from "../vow.sol"; +import {Vow} from "../vow.sol"; import {GemJoin, DaiJoin} from "../join.sol"; import {Clipper} from "../clip.sol"; @@ -34,11 +34,10 @@ import "../dog.sol"; interface Hevm { function warp(uint256) external; - function store(address,bytes32,bytes32) external; + function store(address, bytes32, bytes32) external; } contract Exchange { - DSToken gold; DSToken dai; uint256 goldPrice; @@ -51,13 +50,12 @@ contract Exchange { function sellGold(uint256 goldAmt) external { gold.transferFrom(msg.sender, address(this), goldAmt); - uint256 daiAmt = goldAmt * goldPrice / 1E18; + uint256 daiAmt = goldAmt * goldPrice / 1e18; dai.transfer(msg.sender, daiAmt); } } contract Trader { - Clipper clip; Vat vat; DSToken gold; @@ -84,33 +82,18 @@ contract Trader { exchange = exchange_; } - function take( - uint256 id, - uint256 amt, - uint256 max, - address who, - bytes calldata data - ) - external - { - clip.take({ - id: id, - amt: amt, - max: max, - who: who, - data: data - }); + function take(uint256 id, uint256 amt, uint256 max, address who, bytes calldata data) external { + clip.take({id: id, amt: amt, max: max, who: who, data: data}); } - function clipperCall(address sender, uint256 owe, uint256 slice, bytes calldata data) - external { + function clipperCall(address sender, uint256 owe, uint256 slice, bytes calldata data) external { data; goldJoin.exit(address(this), slice); gold.approve(address(exchange)); exchange.sellGold(slice); dai.approve(address(daiJoin)); vat.hope(address(clip)); - daiJoin.join(sender, owe / 1E27); + daiJoin.join(sender, owe / 1e27); } } @@ -125,22 +108,8 @@ contract Guy { Vat(address(clip.vat())).hope(usr); } - function take( - uint256 id, - uint256 amt, - uint256 max, - address who, - bytes calldata data - ) - external - { - clip.take({ - id: id, - amt: amt, - max: max, - who: who, - data: data - }); + function take(uint256 id, uint256 amt, uint256 max, address who, bytes calldata data) external { + clip.take({id: id, amt: amt, max: max, who: who, data: data}); } function bark(Dog dog, bytes32 ilk, address urn, address usr) external { @@ -149,16 +118,17 @@ contract Guy { } contract BadGuy is Guy { + constructor(Clipper clip_) public Guy(clip_) {} - constructor(Clipper clip_) Guy(clip_) public {} - - function clipperCall(address sender, uint256 owe, uint256 slice, bytes calldata data) - external { - sender; owe; slice; data; + function clipperCall(address sender, uint256 owe, uint256 slice, bytes calldata data) external { + sender; + owe; + slice; + data; clip.take({ // attempt reentrancy id: 1, amt: 25 ether, - max: 5 ether * 10E27, + max: 5 ether * 10e27, who: address(this), data: "" }); @@ -166,67 +136,65 @@ contract BadGuy is Guy { } contract RedoGuy is Guy { + constructor(Clipper clip_) public Guy(clip_) {} - constructor(Clipper clip_) Guy(clip_) public {} - - function clipperCall( - address sender, uint256 owe, uint256 slice, bytes calldata data - ) external { - owe; slice; data; + function clipperCall(address sender, uint256 owe, uint256 slice, bytes calldata data) external { + owe; + slice; + data; clip.redo(1, sender); } } contract KickGuy is Guy { + constructor(Clipper clip_) public Guy(clip_) {} - constructor(Clipper clip_) Guy(clip_) public {} - - function clipperCall( - address sender, uint256 owe, uint256 slice, bytes calldata data - ) external { - sender; owe; slice; data; + function clipperCall(address sender, uint256 owe, uint256 slice, bytes calldata data) external { + sender; + owe; + slice; + data; clip.kick(1, 1, address(0), address(0)); } } contract FileUintGuy is Guy { + constructor(Clipper clip_) public Guy(clip_) {} - constructor(Clipper clip_) Guy(clip_) public {} - - function clipperCall( - address sender, uint256 owe, uint256 slice, bytes calldata data - ) external { - sender; owe; slice; data; + function clipperCall(address sender, uint256 owe, uint256 slice, bytes calldata data) external { + sender; + owe; + slice; + data; clip.file("stopped", 1); } } contract FileAddrGuy is Guy { + constructor(Clipper clip_) public Guy(clip_) {} - constructor(Clipper clip_) Guy(clip_) public {} - - function clipperCall( - address sender, uint256 owe, uint256 slice, bytes calldata data - ) external { - sender; owe; slice; data; + function clipperCall(address sender, uint256 owe, uint256 slice, bytes calldata data) external { + sender; + owe; + slice; + data; clip.file("vow", address(123)); } } contract YankGuy is Guy { + constructor(Clipper clip_) public Guy(clip_) {} - constructor(Clipper clip_) Guy(clip_) public {} - - function clipperCall( - address sender, uint256 owe, uint256 slice, bytes calldata data - ) external { - sender; owe; slice; data; + function clipperCall(address sender, uint256 owe, uint256 slice, bytes calldata data) external { + sender; + owe; + slice; + data; clip.yank(1); } } contract PublicClip is Clipper { - constructor(address vat, address spot, address dog, bytes32 ilk) public Clipper(vat, spot, dog, ilk) {} function add() public returns (uint256 id) { @@ -243,10 +211,10 @@ contract PublicClip is Clipper { contract ClipperTest is DSTest { Hevm hevm; - Vat vat; - Dog dog; + Vat vat; + Dog dog; Spotter spot; - Vow vow; + Vow vow; DSValue pip; DSToken gold; GemJoin goldJoin; @@ -267,8 +235,7 @@ contract ClipperTest is DSTest { uint256 RAD = 10 ** 45; // CHEAT_CODE = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D - bytes20 constant CHEAT_CODE = - bytes20(uint160(uint256(keccak256('hevm cheat code')))); + bytes20 constant CHEAT_CODE = bytes20(uint160(uint256(keccak256("hevm cheat code")))); bytes32 constant ilk = "gold"; uint256 constant goldPrice = 5 ether; @@ -283,29 +250,30 @@ contract ClipperTest is DSTest { (uint256 ink_,) = vat.urns(ilk_, urn_); return ink_; } + function _art(bytes32 ilk_, address urn_) internal view returns (uint256) { - (,uint256 art_) = vat.urns(ilk_, urn_); + (, uint256 art_) = vat.urns(ilk_, urn_); return art_; } - modifier takeSetup { + modifier takeSetup() { uint256 pos; uint256 tab; uint256 lot; address usr; - uint96 tic; + uint96 tic; uint256 top; uint256 ink; uint256 art; StairstepExponentialDecrease calc = new StairstepExponentialDecrease(); - calc.file("cut", RAY - ray(0.01 ether)); // 1% decrease - calc.file("step", 1); // Decrease every 1 second + calc.file("cut", RAY - ray(0.01 ether)); // 1% decrease + calc.file("step", 1); // Decrease every 1 second - clip.file("buf", ray(1.25 ether)); // 25% Initial price buffer - clip.file("calc", address(calc)); // File price contract - clip.file("cusp", ray(0.3 ether)); // 70% drop before reset - clip.file("tail", 3600); // 1 hour before reset + clip.file("buf", ray(1.25 ether)); // 25% Initial price buffer + clip.file("calc", address(calc)); // File price contract + clip.file("cusp", ray(0.3 ether)); // 70% drop before reset + clip.file("tail", 3600); // 1 hour before reset (ink, art) = vat.urns(ilk, me); assertEq(ink, 40 ether); @@ -338,9 +306,11 @@ contract ClipperTest is DSTest { function ray(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 9; } + function rad(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 27; } + function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } @@ -389,7 +359,7 @@ contract ClipperTest is DSTest { vat.file(ilk, "dust", rad(20 ether)); // $20 dust vat.file(ilk, "line", rad(10000 ether)); - vat.file("Line", rad(10000 ether)); + vat.file("Line", rad(10000 ether)); dog.file(ilk, "chop", 1.1 ether); // 10% chop dog.file(ilk, "hole", rad(1000 ether)); @@ -411,7 +381,7 @@ contract ClipperTest is DSTest { assertEq(vat.dai(me), rad(100 ether)); pip.poke(bytes32(uint256(4 ether))); // Spot = $2 - spot.poke(ilk); // Now unsafe + spot.poke(ilk); // Now unsafe ali = address(new Guy(clip)); bob = address(new Guy(clip)); @@ -422,8 +392,8 @@ contract ClipperTest is DSTest { Guy(bob).hope(address(clip)); vat.suck(address(0), address(this), rad(1000 ether)); - vat.suck(address(0), address(ali), rad(1000 ether)); - vat.suck(address(0), address(bob), rad(1000 ether)); + vat.suck(address(0), address(ali), rad(1000 ether)); + vat.suck(address(0), address(bob), rad(1000 ether)); } function test_change_dog() public { @@ -443,13 +413,13 @@ contract ClipperTest is DSTest { uint256 tab; uint256 lot; address usr; - uint96 tic; + uint96 tic; uint256 top; uint256 ink; uint256 art; - clip.file("tip", rad(100 ether)); // Flat fee of 100 DAI - clip.file("chip", 0); // No linear increase + clip.file("tip", rad(100 ether)); // Flat fee of 100 DAI + clip.file("chip", 0); // No linear increase assertEq(clip.kicks(), 0); (pos, tab, lot, usr, tic, top) = clip.sales(1); @@ -482,13 +452,13 @@ contract ClipperTest is DSTest { assertEq(art, 0 ether); pip.poke(bytes32(goldPrice)); // Spot = $2.5 - spot.poke(ilk); // Now safe + spot.poke(ilk); // Now safe hevm.warp(startTime + 100); vat.frob(ilk, me, me, me, 40 ether, 100 ether); pip.poke(bytes32(uint256(4 ether))); // Spot = $2 - spot.poke(ilk); // Now unsafe + spot.poke(ilk); // Now unsafe (pos, tab, lot, usr, tic, top) = clip.sales(2); assertEq(pos, 0); @@ -499,10 +469,10 @@ contract ClipperTest is DSTest { assertEq(top, 0); assertEq(vat.gem(ilk, me), 920 ether); - clip.file(bytes32("buf"), ray(1.25 ether)); // 25% Initial price buffer + clip.file(bytes32("buf"), ray(1.25 ether)); // 25% Initial price buffer - clip.file("tip", rad(100 ether)); // Flat fee of 100 DAI - clip.file("chip", 0.02 ether); // Linear increase of 2% of tab + clip.file("tip", rad(100 ether)); // Flat fee of 100 DAI + clip.file("chip", 0.02 ether); // Linear increase of 2% of tab assertEq(vat.dai(bob), rad(1000 ether)); @@ -571,7 +541,7 @@ contract ClipperTest is DSTest { uint256 tab; uint256 lot; address usr; - uint96 tic; + uint96 tic; uint256 top; uint256 ink; uint256 art; @@ -613,7 +583,7 @@ contract ClipperTest is DSTest { uint256 tab; uint256 lot; address usr; - uint96 tic; + uint96 tic; uint256 top; uint256 ink; uint256 art; @@ -655,7 +625,7 @@ contract ClipperTest is DSTest { uint256 tab; uint256 lot; address usr; - uint96 tic; + uint96 tic; uint256 top; uint256 ink; uint256 art; @@ -664,9 +634,9 @@ contract ClipperTest is DSTest { (, uint256 rate,,,) = vat.ilks(ilk); assertEq(rate, ray(1.02 ether)); - dog.file(ilk, "hole", 100 * RAD); // Makes room = 100 RAD - dog.file(ilk, "chop", 1 ether); // 0% chop for precise calculations - vat.file(ilk, "dust", 20 * RAD); // 20 DAI minimum Vault debt + dog.file(ilk, "hole", 100 * RAD); // Makes room = 100 RAD + dog.file(ilk, "chop", 1 ether); // 0% chop for precise calculations + vat.file(ilk, "dust", 20 * RAD); // 20 DAI minimum Vault debt clip.upchost(); assertEq(clip.kicks(), 0); @@ -680,7 +650,7 @@ contract ClipperTest is DSTest { assertEq(vat.gem(ilk, me), 960 ether); (ink, art) = vat.urns(ilk, me); assertEq(ink, 40 ether); - assertEq(art, 100 ether); // Full debt is 102 DAI since rate = 1.02 * RAY + assertEq(art, 100 ether); // Full debt is 102 DAI since rate = 1.02 * RAY // (art - dart) * rate ~= 2 RAD < dust = 20 RAD // => remnant would be dusty, so a full liquidation occurs. @@ -689,7 +659,7 @@ contract ClipperTest is DSTest { assertEq(clip.kicks(), 1); (pos, tab, lot, usr, tic, top) = clip.sales(1); assertEq(pos, 0); - assertEq(tab, mul(100 ether, rate)); // No chop + assertEq(tab, mul(100 ether, rate)); // No chop assertEq(lot, 40 ether); assertEq(usr, me); assertEq(uint256(tic), now); @@ -705,7 +675,7 @@ contract ClipperTest is DSTest { uint256 tab; uint256 lot; address usr; - uint96 tic; + uint96 tic; uint256 top; uint256 ink; uint256 art; @@ -714,9 +684,9 @@ contract ClipperTest is DSTest { (, uint256 rate,,,) = vat.ilks(ilk); assertEq(rate, ray(1.02 ether)); - dog.file(ilk, "hole", 816 * RAD / 10); // Makes room = 81.6 RAD => dart = 80 - dog.file(ilk, "chop", 1 ether); // 0% chop for precise calculations - vat.file(ilk, "dust", 204 * RAD / 10); // 20.4 DAI dust + dog.file(ilk, "hole", 816 * RAD / 10); // Makes room = 81.6 RAD => dart = 80 + dog.file(ilk, "chop", 1 ether); // 0% chop for precise calculations + vat.file(ilk, "dust", 204 * RAD / 10); // 20.4 DAI dust clip.upchost(); assertEq(clip.kicks(), 0); @@ -739,7 +709,7 @@ contract ClipperTest is DSTest { assertEq(clip.kicks(), 1); (pos, tab, lot, usr, tic, top) = clip.sales(1); assertEq(pos, 0); - assertEq(tab, 816 * RAD / 10); // Equal to ilk.hole + assertEq(tab, 816 * RAD / 10); // Equal to ilk.hole assertEq(lot, 32 ether); assertEq(usr, me); assertEq(uint256(tic), now); @@ -809,7 +779,7 @@ contract ClipperTest is DSTest { assertEq(_art(ilk, me), 100 ether); assertEq(dog.Dirt(), 0); - (,uint256 chop,, uint256 dirt) = dog.ilks(ilk); + (, uint256 chop,, uint256 dirt) = dog.ilks(ilk); assertEq(dirt, 0); dog.bark(ilk, me, address(this)); @@ -836,7 +806,7 @@ contract ClipperTest is DSTest { assertEq(_art(ilk, me), 100 ether); assertEq(dog.Dirt(), 0); - (,uint256 chop,, uint256 dirt) = dog.ilks(ilk); + (, uint256 chop,, uint256 dirt) = dog.ilks(ilk); assertEq(dirt, 0); dog.bark(ilk, me, address(this)); @@ -871,17 +841,11 @@ contract ClipperTest is DSTest { function test_take_over_tab() public takeSetup { // Bid so owe (= 25 * 5 = 125 RAD) > tab (= 110 RAD) // Readjusts slice to be tab/top = 25 - Guy(ali).take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(ali), - data: "" - }); + Guy(ali).take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(ali), data: ""}); - assertEq(vat.gem(ilk, ali), 22 ether); // Didn't take whole lot + assertEq(vat.gem(ilk, ali), 22 ether); // Didn't take whole lot assertEq(vat.dai(ali), rad(890 ether)); // Didn't pay more than tab (110) - assertEq(vat.gem(ilk, me), 978 ether); // 960 + (40 - 22) returned to usr + assertEq(vat.gem(ilk, me), 978 ether); // 960 + (40 - 22) returned to usr // Assert auction ends (uint256 pos, uint256 tab, uint256 lot, address usr, uint256 tic, uint256 top) = clip.sales(1); @@ -899,17 +863,11 @@ contract ClipperTest is DSTest { function test_take_at_tab() public takeSetup { // Bid so owe (= 22 * 5 = 110 RAD) == tab (= 110 RAD) - Guy(ali).take({ - id: 1, - amt: 22 ether, - max: ray(5 ether), - who: address(ali), - data: "" - }); + Guy(ali).take({id: 1, amt: 22 ether, max: ray(5 ether), who: address(ali), data: ""}); - assertEq(vat.gem(ilk, ali), 22 ether); // Didn't take whole lot + assertEq(vat.gem(ilk, ali), 22 ether); // Didn't take whole lot assertEq(vat.dai(ali), rad(890 ether)); // Paid full tab (110) - assertEq(vat.gem(ilk, me), 978 ether); // 960 + (40 - 22) returned to usr + assertEq(vat.gem(ilk, me), 978 ether); // 960 + (40 - 22) returned to usr // Assert auction ends (uint256 pos, uint256 tab, uint256 lot, address usr, uint256 tic, uint256 top) = clip.sales(1); @@ -927,23 +885,24 @@ contract ClipperTest is DSTest { function test_take_under_tab() public takeSetup { // Bid so owe (= 11 * 5 = 55 RAD) < tab (= 110 RAD) - Guy(ali).take({ - id: 1, - amt: 11 ether, // Half of tab at $110 + Guy(ali) + .take({ + id: 1, + amt: 11 ether, // Half of tab at $110 max: ray(5 ether), who: address(ali), data: "" }); - assertEq(vat.gem(ilk, ali), 11 ether); // Didn't take whole lot + assertEq(vat.gem(ilk, ali), 11 ether); // Didn't take whole lot assertEq(vat.dai(ali), rad(945 ether)); // Paid half tab (55) - assertEq(vat.gem(ilk, me), 960 ether); // Collateral not returned (yet) + assertEq(vat.gem(ilk, me), 960 ether); // Collateral not returned (yet) // Assert auction DOES NOT end (uint256 pos, uint256 tab, uint256 lot, address usr, uint256 tic, uint256 top) = clip.sales(1); assertEq(pos, 0); - assertEq(tab, rad(55 ether)); // 110 - 5 * 11 - assertEq(lot, 29 ether); // 40 - 11 + assertEq(tab, rad(55 ether)); // 110 - 5 * 11 + assertEq(lot, 29 ether); // 40 - 11 assertEq(usr, me); assertEq(uint256(tic), now); assertEq(top, ray(5 ether)); @@ -954,19 +913,20 @@ contract ClipperTest is DSTest { } function test_take_full_lot_partial_tab() public takeSetup { - hevm.warp(now + 69); // approx 50% price decline + hevm.warp(now + 69); // approx 50% price decline // Bid to purchase entire lot less than tab (~2.5 * 40 ~= 100 < 110) - Guy(ali).take({ - id: 1, - amt: 40 ether, // purchase all collateral + Guy(ali) + .take({ + id: 1, + amt: 40 ether, // purchase all collateral max: ray(2.5 ether), who: address(ali), data: "" }); - assertEq(vat.gem(ilk, ali), 40 ether); // Took entire lot - assertTrue(sub(vat.dai(ali), rad(900 ether)) < rad(0.1 ether)); // Paid about 100 ether - assertEq(vat.gem(ilk, me), 960 ether); // Collateral not returned + assertEq(vat.gem(ilk, ali), 40 ether); // Took entire lot + assertTrue(sub(vat.dai(ali), rad(900 ether)) < rad(0.1 ether)); // Paid about 100 ether + assertEq(vat.gem(ilk, me), 960 ether); // Collateral not returned // Assert auction ends (uint256 pos, uint256 tab, uint256 lot, address usr, uint256 tic, uint256 top) = clip.sales(1); @@ -985,13 +945,7 @@ contract ClipperTest is DSTest { function testFail_take_bid_too_low() public takeSetup { // Bid so max (= 4) < price (= top = 5) (fails with "Clipper/too-expensive") - Guy(ali).take({ - id: 1, - amt: 22 ether, - max: ray(4 ether), - who: address(ali), - data: "" - }); + Guy(ali).take({id: 1, amt: 22 ether, max: ray(4 ether), who: address(ali), data: ""}); } function test_take_bid_recalculates_due_to_chost_check() public takeSetup { @@ -999,16 +953,17 @@ contract ClipperTest is DSTest { assertEq(tab, rad(110 ether)); assertEq(lot, 40 ether); - (, uint256 price,uint256 _lot, uint256 _tab) = clip.getStatus(1); + (, uint256 price, uint256 _lot, uint256 _tab) = clip.getStatus(1); assertEq(_lot, lot); assertEq(_tab, tab); assertEq(price, ray(5 ether)); // Bid for an amount that would leave less than chost remaining tab--bid will be decreased // to leave tab == chost post-execution. - Guy(ali).take({ - id: 1, - amt: 18 * WAD, // Costs 90 DAI at current price; 110 - 90 == 20 < 22 == chost + Guy(ali) + .take({ + id: 1, + amt: 18 * WAD, // Costs 90 DAI at current price; 110 - 90 == 20 < 22 == chost max: ray(5 ether), who: address(ali), data: "" @@ -1031,13 +986,7 @@ contract ClipperTest is DSTest { // Bid so owe (= (22 - 1wei) * 5 = 110 RAD - 1) < tab (= 110 RAD) // 1 < 20 RAD => owe = 110 RAD - 20 RAD - Guy(ali).take({ - id: 1, - amt: 40 ether, - max: ray(2.8 ether), - who: address(ali), - data: "" - }); + Guy(ali).take({id: 1, amt: 40 ether, max: ray(2.8 ether), who: address(ali), data: ""}); // 40 * 2.73 = 109.42... // It means a very low amount of tab (< dust) would remain but doesn't matter @@ -1051,29 +1000,25 @@ contract ClipperTest is DSTest { (, uint256 price,,) = clip.getStatus(1); assertEq(price, ray(5 ether)); - clip.take({ - id: 1, - amt: 17.6 ether, - max: ray(5 ether), - who: address(this), - data: "" - }); + clip.take({id: 1, amt: 17.6 ether, max: ray(5 ether), who: address(this), data: ""}); (, uint256 tab, uint256 lot,,,) = clip.sales(1); assertEq(tab, rad(22 ether)); assertEq(lot, 22.4 ether); assertTrue(!(tab > clip.chost())); - assertTrue(!try_take({ - id: 1, - amt: 1 ether, // partial purchase attempt when !(tab > chost) - max: ray(5 ether), - who: address(this), - data: "" - })); + assertTrue( + !try_take({ + id: 1, + amt: 1 ether, // partial purchase attempt when !(tab > chost) + max: ray(5 ether), + who: address(this), + data: "" + }) + ); clip.take({ - id: 1, + id: 1, amt: tab / price, // This time take the whole tab max: ray(5 ether), who: address(this), @@ -1086,27 +1031,21 @@ contract ClipperTest is DSTest { uint256 tab; uint256 lot; address usr; - uint96 tic; + uint96 tic; uint256 top; // Bid so owe (= 10 * 5 = 50 RAD) < tab (= 110 RAD) - Guy(ali).take({ - id: 1, - amt: 10 ether, - max: ray(5 ether), - who: address(ali), - data: "" - }); + Guy(ali).take({id: 1, amt: 10 ether, max: ray(5 ether), who: address(ali), data: ""}); - assertEq(vat.gem(ilk, ali), 10 ether); // Didn't take whole lot + assertEq(vat.gem(ilk, ali), 10 ether); // Didn't take whole lot assertEq(vat.dai(ali), rad(950 ether)); // Paid some tab (50) - assertEq(vat.gem(ilk, me), 960 ether); // Collateral not returned (yet) + assertEq(vat.gem(ilk, me), 960 ether); // Collateral not returned (yet) // Assert auction DOES NOT end (pos, tab, lot, usr, tic, top) = clip.sales(1); assertEq(pos, 0); - assertEq(tab, rad(60 ether)); // 110 - 5 * 10 - assertEq(lot, 30 ether); // 40 - 10 + assertEq(tab, rad(60 ether)); // 110 - 5 * 10 + assertEq(lot, 30 ether); // 40 - 10 assertEq(usr, me); assertEq(uint256(tic), now); assertEq(top, ray(5 ether)); @@ -1114,9 +1053,10 @@ contract ClipperTest is DSTest { hevm.warp(now + 30); (, uint256 _price, uint256 _lot,) = clip.getStatus(1); - Guy(bob).take({ - id: 1, - amt: _lot, // Buy the rest of the lot + Guy(bob) + .take({ + id: 1, + amt: _lot, // Buy the rest of the lot max: ray(_price), // 5 * 0.99 ** 30 = 3.698501866941401 RAY => max > price who: address(bob), data: "" @@ -1131,24 +1071,24 @@ contract ClipperTest is DSTest { assertEq(uint256(tic), 0); assertEq(top, 0); - uint256 expectedGem = (RAY * 60 ether) / _price; // tab / price - assertEq(vat.gem(ilk, bob), expectedGem); // Didn't take whole lot - assertEq(vat.dai(bob), rad(940 ether)); // Paid rest of tab (60) + uint256 expectedGem = (RAY * 60 ether) / _price; // tab / price + assertEq(vat.gem(ilk, bob), expectedGem); // Didn't take whole lot + assertEq(vat.dai(bob), rad(940 ether)); // Paid rest of tab (60) - uint256 lotReturn = 30 ether - expectedGem; // lot - loaf.tab / max = 15 - assertEq(vat.gem(ilk, me), 960 ether + lotReturn); // Collateral returned (10 WAD) + uint256 lotReturn = 30 ether - expectedGem; // lot - loaf.tab / max = 15 + assertEq(vat.gem(ilk, me), 960 ether + lotReturn); // Collateral returned (10 WAD) } function auctionResetSetup(uint256 tau) internal { LinearDecrease calc = new LinearDecrease(); - calc.file(bytes32("tau"), tau); // tau hours till zero is reached (used to test tail) + calc.file(bytes32("tau"), tau); // tau hours till zero is reached (used to test tail) vat.file(ilk, "dust", rad(20 ether)); // $20 dust - clip.file("buf", ray(1.25 ether)); // 25% Initial price buffer - clip.file("calc", address(calc)); // File price contract - clip.file("cusp", ray(0.5 ether)); // 50% drop before reset - clip.file("tail", 3600); // 1 hour before reset + clip.file("buf", ray(1.25 ether)); // 25% Initial price buffer + clip.file("calc", address(calc)); // File price contract + clip.file("cusp", ray(0.5 ether)); // 50% drop before reset + clip.file("tail", 3600); // 1 hour before reset assertEq(clip.kicks(), 0); dog.bark(ilk, me, address(this)); @@ -1179,7 +1119,7 @@ contract ClipperTest is DSTest { assertTrue(try_redo(1, address(this))); (,,,, uint96 ticAfter, uint256 topAfter) = clip.sales(1); - assertEq(uint256(ticAfter), startTime + 3601 seconds); // (now) + assertEq(uint256(ticAfter), startTime + 3601 seconds); // (now) assertEq(topAfter, ray(3.75 ether)); // $3 spot + 25% buffer = $5 (used most recent OSM price) } @@ -1202,7 +1142,7 @@ contract ClipperTest is DSTest { assertTrue(try_redo(1, address(this))); (,,,, uint96 ticAfter, uint256 topAfter) = clip.sales(1); - assertEq(uint256(ticAfter), startTime + 1801 seconds); // (now) + assertEq(uint256(ticAfter), startTime + 1801 seconds); // (now) assertEq(topAfter, ray(3.75 ether)); // $3 spot + 25% buffer = $3.75 (used most recent OSM price) } @@ -1245,7 +1185,7 @@ contract ClipperTest is DSTest { uint256 tab; uint256 lot; address usr; - uint96 tic; + uint96 tic; uint256 top; uint256 ink; uint256 art; @@ -1282,39 +1222,21 @@ contract ClipperTest is DSTest { clip.file("stopped", 1); // Bid so owe (= 25 * 5 = 125 RAD) > tab (= 110 RAD) // Readjusts slice to be tab/top = 25 - Guy(ali).take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(ali), - data: "" - }); + Guy(ali).take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(ali), data: ""}); } function test_stopped_2_take() public takeSetup { clip.file("stopped", 2); // Bid so owe (= 25 * 5 = 125 RAD) > tab (= 110 RAD) // Readjusts slice to be tab/top = 25 - Guy(ali).take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(ali), - data: "" - }); + Guy(ali).take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(ali), data: ""}); } function testFail_stopped_3_take() public takeSetup { clip.file("stopped", 3); // Bid so owe (= 25 * 5 = 125 RAD) > tab (= 110 RAD) // Readjusts slice to be tab/top = 25 - Guy(ali).take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(ali), - data: "" - }); + Guy(ali).take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(ali), data: ""}); } function test_stopped_1_auction_reset_tail() public { @@ -1334,7 +1256,7 @@ contract ClipperTest is DSTest { assertTrue(try_redo(1, address(this))); (,,,, uint96 ticAfter, uint256 topAfter) = clip.sales(1); - assertEq(uint256(ticAfter), startTime + 3601 seconds); // (now) + assertEq(uint256(ticAfter), startTime + 3601 seconds); // (now) assertEq(topAfter, ray(3.75 ether)); // $3 spot + 25% buffer = $5 (used most recent OSM price) } @@ -1351,8 +1273,8 @@ contract ClipperTest is DSTest { hevm.warp(startTime + 3601 seconds); (bool needsRedo,,,) = clip.getStatus(1); - assertTrue(needsRedo); // Redo possible if circuit breaker not set - assertTrue(!try_redo(1, address(this))); // Redo fails because of circuit breaker + assertTrue(needsRedo); // Redo possible if circuit breaker not set + assertTrue(!try_redo(1, address(this))); // Redo fails because of circuit breaker } function test_stopped_3_auction_reset_tail() public { @@ -1368,13 +1290,13 @@ contract ClipperTest is DSTest { hevm.warp(startTime + 3601 seconds); (bool needsRedo,,,) = clip.getStatus(1); - assertTrue(needsRedo); // Redo possible if circuit breaker not set - assertTrue(!try_redo(1, address(this))); // Redo fails because of circuit breaker + assertTrue(needsRedo); // Redo possible if circuit breaker not set + assertTrue(!try_redo(1, address(this))); // Redo fails because of circuit breaker } function test_redo_incentive() public takeSetup { - clip.file("tip", rad(100 ether)); // Flat fee of 100 DAI - clip.file("chip", 0); // No linear increase + clip.file("tip", rad(100 ether)); // Flat fee of 100 DAI + clip.file("chip", 0); // No linear increase (, uint256 tab, uint256 lot,,,) = clip.sales(1); @@ -1385,7 +1307,7 @@ contract ClipperTest is DSTest { clip.redo(1, address(123)); assertEq(vat.dai(address(123)), clip.tip()); - clip.file("chip", 0.02 ether); // Reward 2% of tab + clip.file("chip", 0.02 ether); // Reward 2% of tab hevm.warp(now + 300); clip.redo(1, address(234)); assertEq(vat.dai(address(234)), clip.tip() + clip.chip() * tab / WAD); @@ -1413,13 +1335,7 @@ contract ClipperTest is DSTest { (, uint256 price,,) = clip.getStatus(1); assertEq(price, 1830161706366147524653080130); // 1.83 RAY - clip.take({ - id: 1, - amt: 38 ether, - max: ray(5 ether), - who: address(this), - data: "" - }); + clip.take({id: 1, amt: 38 ether, max: ray(5 ether), who: address(this), data: ""}); (, tab, lot,,,) = clip.sales(1); @@ -1451,9 +1367,9 @@ contract ClipperTest is DSTest { uint256 preGemBalance = vat.gem(ilk, address(this)); (,, uint256 origLot,,,) = clip.sales(1); - uint startGas = gasleft(); + uint256 startGas = gasleft(); clip.yank(1); - uint endGas = gasleft(); + uint256 endGas = gasleft(); emit log_named_uint("yank gas", startGas - endGas); // Assert that the auction was deleted. @@ -1485,7 +1401,7 @@ contract ClipperTest is DSTest { pclip.add(); // [1,2,3,4,5] - assertEq(pclip.count(), 5); // 5 elements added + assertEq(pclip.count(), 5); // 5 elements added assertEq(pclip.active(0), 1); assertEq(pclip.active(1), 2); assertEq(pclip.active(2), 3); @@ -1498,7 +1414,7 @@ contract ClipperTest is DSTest { assertEq(pclip.count(), 4); assertEq(pclip.active(0), 1); assertEq(pclip.active(1), 2); - assertEq(pclip.active(2), 5); // Swapped last for middle + assertEq(pclip.active(2), 5); // Swapped last for middle (pos,,,,,) = pclip.sales(5); assertEq(pos, 2); assertEq(pclip.active(3), 4); @@ -1534,25 +1450,13 @@ contract ClipperTest is DSTest { } function testFail_not_enough_dai() public takeSetup { - Guy(che).take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(che), - data: "" - }); + Guy(che).take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(che), data: ""}); } function test_flashsale() public takeSetup { assertEq(vat.dai(che), 0); assertEq(dai.balanceOf(che), 0); - Guy(che).take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(che), - data: "hey" - }); + Guy(che).take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(che), data: "hey"}); assertEq(vat.dai(che), 0); assertTrue(dai.balanceOf(che) > 0); // Che turned a profit } @@ -1560,100 +1464,59 @@ contract ClipperTest is DSTest { function testFail_reentrancy_take() public takeSetup { BadGuy usr = new BadGuy(clip); usr.hope(address(clip)); - vat.suck(address(0), address(usr), rad(1000 ether)); + vat.suck(address(0), address(usr), rad(1000 ether)); - usr.take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(usr), - data: "hey" - }); + usr.take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(usr), data: "hey"}); } function testFail_reentrancy_redo() public takeSetup { RedoGuy usr = new RedoGuy(clip); usr.hope(address(clip)); - vat.suck(address(0), address(usr), rad(1000 ether)); + vat.suck(address(0), address(usr), rad(1000 ether)); - usr.take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(usr), - data: "hey" - }); + usr.take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(usr), data: "hey"}); } function testFail_reentrancy_kick() public takeSetup { KickGuy usr = new KickGuy(clip); usr.hope(address(clip)); - vat.suck(address(0), address(usr), rad(1000 ether)); + vat.suck(address(0), address(usr), rad(1000 ether)); clip.rely(address(usr)); - usr.take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(usr), - data: "hey" - }); + usr.take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(usr), data: "hey"}); } function testFail_reentrancy_file_uint() public takeSetup { FileUintGuy usr = new FileUintGuy(clip); usr.hope(address(clip)); - vat.suck(address(0), address(usr), rad(1000 ether)); + vat.suck(address(0), address(usr), rad(1000 ether)); clip.rely(address(usr)); - usr.take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(usr), - data: "hey" - }); + usr.take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(usr), data: "hey"}); } function testFail_reentrancy_file_addr() public takeSetup { FileAddrGuy usr = new FileAddrGuy(clip); usr.hope(address(clip)); - vat.suck(address(0), address(usr), rad(1000 ether)); + vat.suck(address(0), address(usr), rad(1000 ether)); clip.rely(address(usr)); - usr.take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(usr), - data: "hey" - }); + usr.take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(usr), data: "hey"}); } function testFail_reentrancy_yank() public takeSetup { YankGuy usr = new YankGuy(clip); usr.hope(address(clip)); - vat.suck(address(0), address(usr), rad(1000 ether)); + vat.suck(address(0), address(usr), rad(1000 ether)); clip.rely(address(usr)); - usr.take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(usr), - data: "hey" - }); + usr.take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(usr), data: "hey"}); } - function testFail_take_impersonation() public takeSetup { // should fail, but works + function testFail_take_impersonation() public takeSetup { + // should fail, but works Guy usr = new Guy(clip); - usr.take({ - id: 1, - amt: 99999999999999 ether, - max: ray(99999999999999 ether), - who: address(ali), - data: "" - }); + usr.take({id: 1, amt: 99999999999999 ether, max: ray(99999999999999 ether), who: address(ali), data: ""}); } function test_gas_bark_kick() public { @@ -1681,9 +1544,10 @@ contract ClipperTest is DSTest { function test_gas_partial_take() public takeSetup { uint256 preGas = gasleft(); // Bid so owe (= 11 * 5 = 55 RAD) < tab (= 110 RAD) - Guy(ali).take({ - id: 1, - amt: 11 ether, // Half of tab at $110 + Guy(ali) + .take({ + id: 1, + amt: 11 ether, // Half of tab at $110 max: ray(5 ether), who: address(ali), data: "" @@ -1691,15 +1555,15 @@ contract ClipperTest is DSTest { uint256 diffGas = preGas - gasleft(); log_named_uint("partial take gas", diffGas); - assertEq(vat.gem(ilk, ali), 11 ether); // Didn't take whole lot + assertEq(vat.gem(ilk, ali), 11 ether); // Didn't take whole lot assertEq(vat.dai(ali), rad(945 ether)); // Paid half tab (55) - assertEq(vat.gem(ilk, me), 960 ether); // Collateral not returned (yet) + assertEq(vat.gem(ilk, me), 960 ether); // Collateral not returned (yet) // Assert auction DOES NOT end (uint256 pos, uint256 tab, uint256 lot, address usr, uint256 tic, uint256 top) = clip.sales(1); assertEq(pos, 0); - assertEq(tab, rad(55 ether)); // 110 - 5 * 11 - assertEq(lot, 29 ether); // 40 - 11 + assertEq(tab, rad(55 ether)); // 110 - 5 * 11 + assertEq(lot, 29 ether); // 40 - 11 assertEq(usr, me); assertEq(uint256(tic), now); assertEq(top, ray(5 ether)); @@ -1709,19 +1573,13 @@ contract ClipperTest is DSTest { uint256 preGas = gasleft(); // Bid so owe (= 25 * 5 = 125 RAD) > tab (= 110 RAD) // Readjusts slice to be tab/top = 25 - Guy(ali).take({ - id: 1, - amt: 25 ether, - max: ray(5 ether), - who: address(ali), - data: "" - }); + Guy(ali).take({id: 1, amt: 25 ether, max: ray(5 ether), who: address(ali), data: ""}); uint256 diffGas = preGas - gasleft(); log_named_uint("full take gas", diffGas); - assertEq(vat.gem(ilk, ali), 22 ether); // Didn't take whole lot + assertEq(vat.gem(ilk, ali), 22 ether); // Didn't take whole lot assertEq(vat.dai(ali), rad(890 ether)); // Didn't pay more than tab (110) - assertEq(vat.gem(ilk, me), 978 ether); // 960 + (40 - 22) returned to usr + assertEq(vat.gem(ilk, me), 978 ether); // 960 + (40 - 22) returned to usr // Assert auction ends (uint256 pos, uint256 tab, uint256 lot, address usr, uint256 tic, uint256 top) = clip.sales(1); diff --git a/src/test/cure.t.sol b/src/test/cure.t.sol index 17de561f..b0e91148 100644 --- a/src/test/cure.t.sol +++ b/src/test/cure.t.sol @@ -2,12 +2,12 @@ pragma solidity >=0.6.12; -import { DSTest } from "ds-test/test.sol"; -import { Cure } from "../cure.sol"; +import {DSTest} from "ds-test/test.sol"; +import {Cure} from "../cure.sol"; interface Hevm { function warp(uint256) external; - function store(address,bytes32,bytes32) external; + function store(address, bytes32, bytes32) external; } contract SourceMock { @@ -26,8 +26,7 @@ contract CureTest is DSTest { Hevm hevm; Cure cure; - bytes20 constant CHEAT_CODE = - bytes20(uint160(uint256(keccak256('hevm cheat code')))); + bytes20 constant CHEAT_CODE = bytes20(uint160(uint256(keccak256("hevm cheat code")))); function setUp() public { hevm = Hevm(address(CHEAT_CODE)); diff --git a/src/test/dai.t.sol b/src/test/dai.t.sol index 60940c0a..ea10c3ab 100644 --- a/src/test/dai.t.sol +++ b/src/test/dai.t.sol @@ -17,93 +17,101 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -pragma solidity ^0.6.12; +pragma solidity ^0.8.0; + +/** + * @title DAITest + * @dev Test contract for the DAI token + * @dev Implemented vm.expectRevert() into Revert test functions via the standard Vm interface address + */ import "ds-test/test.sol"; import "../dai.sol"; contract TokenUser { - Dai token; + Dai token; + + uint256 internal constant MAX_UINT = type(uint256).max; - constructor(Dai token_) public { + constructor(Dai token_) { token = token_; } - function doTransferFrom(address from, address to, uint amount) - public - returns (bool) - { + function doTransferFrom(address from, address to, uint256 amount) public returns (bool) { return token.transferFrom(from, to, amount); } - function doTransfer(address to, uint amount) - public - returns (bool) - { + function doTransfer(address to, uint256 amount) public returns (bool) { return token.transfer(to, amount); } - function doApprove(address recipient, uint amount) - public - returns (bool) - { + function doApprove(address recipient, uint256 amount) public returns (bool) { return token.approve(recipient, amount); } - function doAllowance(address owner, address spender) - public - view - returns (uint) - { + function doAllowance(address owner, address spender) public view returns (uint256) { return token.allowance(owner, spender); } - function doBalanceOf(address who) public view returns (uint) { + function doBalanceOf(address who) public view returns (uint256) { return token.balanceOf(who); } - function doApprove(address guy) - public - returns (bool) - { - return token.approve(guy, uint(-1)); + function doApprove(address guy) public returns (bool) { + return token.approve(guy, MAX_UINT); } - function doMint(uint wad) public { + + function doMint(uint256 wad) public { token.mint(address(this), wad); } - function doBurn(uint wad) public { + + function doBurn(uint256 wad) public { token.burn(address(this), wad); } - function doMint(address guy, uint wad) public { + + function doMint(address guy, uint256 wad) public { token.mint(guy, wad); } - function doBurn(address guy, uint wad) public { + + function doBurn(address guy, uint256 wad) public { token.burn(guy, wad); } - } +/*////////////////////////////////////////////////////////////// + INTERFACE +//////////////////////////////////////////////////////////////*/ interface Hevm { function warp(uint256) external; } +interface Vm { + function expectRevert() external; + function addr(uint256 privateKey) external returns (address); + function sign(uint256 privateKey, bytes32 digest) external returns (uint8, bytes32, bytes32); +} + contract DaiTest is DSTest { - uint constant initialBalanceThis = 1000; - uint constant initialBalanceCal = 100; + uint256 constant initialBalanceThis = 1000; + uint256 constant initialBalanceCal = 100; + uint256 constant calKey = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80; // any nonzero test key + uint256 internal constant MAX_UINT = type(uint256).max; + uint256 constant delKey = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d; + address cal; + address del; Dai token; Hevm hevm; + Vm private constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); address user1; address user2; address self; - uint amount = 2; - uint fee = 1; - uint nonce = 0; - uint deadline = 0; - address cal = 0x29C76e6aD8f28BB1004902578Fb108c507Be341b; - address del = 0xdd2d5D3f7f1b35b7A0601D6A00DbB7D44Af58479; + uint256 amount = 2; + uint256 fee = 1; + uint256 nonce = 0; + uint256 deadline = 0; bytes32 r = 0x8e30095d9e5439a4f4b8e4b5c94e7639756474d72aded20611464c8f002efb06; bytes32 s = 0x49a0ed09658bc768d6548689bcbaa430cefa57846ef83cb685673a9b9a575ff4; uint8 v = 27; @@ -111,10 +119,11 @@ contract DaiTest is DSTest { bytes32 _s = 0x7e8e641e5e8bef932c3a55e7365e0201196fc6385d942c47d749bf76e73ee46f; uint8 _v = 27; - function setUp() public { - hevm = Hevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + hevm = Hevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); /////// hevm.warp(604411200); + cal = vm.addr(calKey); + del = vm.addr(delKey); token = createToken(); token.mint(address(this), initialBalanceThis); token.mint(cal, initialBalanceCal); @@ -132,7 +141,7 @@ contract DaiTest is DSTest { } function testTransferCost() public logs_gas { - token.transfer(address(0), 10); + assertTrue(token.transfer(address(0), 10)); } function testAllowanceStartsAtZero() public logs_gas { @@ -140,22 +149,24 @@ contract DaiTest is DSTest { } function testValidTransfers() public logs_gas { - uint sentAmount = 250; + uint256 sentAmount = 250; emit log_named_address("token11111", address(token)); - token.transfer(user2, sentAmount); + assertTrue(token.transfer(user2, sentAmount)); assertEq(token.balanceOf(user2), sentAmount); assertEq(token.balanceOf(self), initialBalanceThis - sentAmount); } - function testFailWrongAccountTransfers() public logs_gas { - uint sentAmount = 250; - token.transferFrom(user2, self, sentAmount); + function testRevertIfWrongAccountTransfers() public logs_gas { + uint256 sentAmount = 250; + vm.expectRevert(); + assertTrue(token.transferFrom(user2, self, sentAmount)); } - function testFailInsufficientFundsTransfers() public logs_gas { - uint sentAmount = 250; - token.transfer(user1, initialBalanceThis - sentAmount); - token.transfer(user2, sentAmount + 1); + function testRevertInsufficientFundsTransfers() public logs_gas { + uint256 sentAmount = 250; + assertTrue(token.transfer(user1, initialBalanceThis - sentAmount)); + vm.expectRevert(); + assertTrue(token.transfer(user2, sentAmount + 1)); } function testApproveSetsAllowance() public logs_gas { @@ -168,96 +179,114 @@ contract DaiTest is DSTest { } function testChargesAmountApproved() public logs_gas { - uint amountApproved = 20; + uint256 amountApproved = 20; token.approve(user2, amountApproved); assertTrue(TokenUser(user2).doTransferFrom(self, user2, amountApproved)); assertEq(token.balanceOf(self), initialBalanceThis - amountApproved); } - function testFailTransferWithoutApproval() public logs_gas { - token.transfer(user1, 50); - token.transferFrom(user1, self, 1); + function testRevertTransferWithoutApproval() public logs_gas { + assertTrue(token.transfer(user1, 50)); + vm.expectRevert(); + assertTrue(token.transferFrom(user1, self, 1)); } - function testFailChargeMoreThanApproved() public logs_gas { - token.transfer(user1, 50); + function testRevertChargeMoreThanApproved() public logs_gas { + assertTrue(token.transfer(user1, 50)); TokenUser(user1).doApprove(self, 20); - token.transferFrom(user1, self, 21); + vm.expectRevert(); + assertTrue(token.transferFrom(user1, self, 21)); } + function testTransferFromSelf() public { - token.transferFrom(self, user1, 50); + assertTrue(token.transferFrom(self, user1, 50)); assertEq(token.balanceOf(user1), 50); } - function testFailTransferFromSelfNonArbitrarySize() public { - // you shouldn't be able to evade balance checks by transferring - // to yourself - token.transferFrom(self, self, token.balanceOf(self) + 1); + + function testRevertTransferFromSelfNonArbitrarySize() public { + uint256 _amount = token.balanceOf(self) + 1; + + vm.expectRevert(); + assertTrue(token.transferFrom(self, self, _amount)); } + function testMintself() public { - uint mintAmount = 10; + uint256 mintAmount = 10; token.mint(address(this), mintAmount); assertEq(token.balanceOf(self), initialBalanceThis + mintAmount); } + function testMintGuy() public { - uint mintAmount = 10; + uint256 mintAmount = 10; token.mint(user1, mintAmount); assertEq(token.balanceOf(user1), mintAmount); } - function testFailMintGuyNoAuth() public { + + function testRevertMintGuyNoAuth() public { + vm.expectRevert(); TokenUser(user1).doMint(user2, 10); } + function testMintGuyAuth() public { token.rely(user1); TokenUser(user1).doMint(user2, 10); } function testBurn() public { - uint burnAmount = 10; + uint256 burnAmount = 10; token.burn(address(this), burnAmount); assertEq(token.totalSupply(), initialBalanceThis + initialBalanceCal - burnAmount); } + function testBurnself() public { - uint burnAmount = 10; + uint256 burnAmount = 10; token.burn(address(this), burnAmount); assertEq(token.balanceOf(self), initialBalanceThis - burnAmount); } + function testBurnGuyWithTrust() public { - uint burnAmount = 10; - token.transfer(user1, burnAmount); + uint256 burnAmount = 10; + assertTrue(token.transfer(user1, burnAmount)); assertEq(token.balanceOf(user1), burnAmount); TokenUser(user1).doApprove(self); token.burn(user1, burnAmount); assertEq(token.balanceOf(user1), 0); } + function testBurnAuth() public { - token.transfer(user1, 10); + assertTrue(token.transfer(user1, 10)); token.rely(user1); TokenUser(user1).doBurn(10); } + function testBurnGuyAuth() public { - token.transfer(user2, 10); + assertTrue(token.transfer(user2, 10)); // token.rely(user1); TokenUser(user2).doApprove(user1); TokenUser(user1).doBurn(user2, 10); } - function testFailUntrustedTransferFrom() public { + function testRevertUntrustedTransferFrom() public { assertEq(token.allowance(self, user2), 0); + vm.expectRevert(); TokenUser(user1).doTransferFrom(self, user2, 200); } + function testTrusting() public { assertEq(token.allowance(self, user2), 0); - token.approve(user2, uint(-1)); - assertEq(token.allowance(self, user2), uint(-1)); + token.approve(user2, MAX_UINT); + assertEq(token.allowance(self, user2), MAX_UINT); token.approve(user2, 0); assertEq(token.allowance(self, user2), 0); } + function testTrustedTransferFrom() public { - token.approve(user1, uint(-1)); + token.approve(user1, MAX_UINT); TokenUser(user1).doTransferFrom(self, user2, 200); assertEq(token.balanceOf(user2), 200); } + function testApproveWillModifyAllowance() public { assertEq(token.allowance(self, user1), 0); assertEq(token.balanceOf(user1), 0); @@ -267,15 +296,17 @@ contract DaiTest is DSTest { assertEq(token.balanceOf(user1), 500); assertEq(token.allowance(self, user1), 500); } + function testApproveWillNotModifyAllowance() public { assertEq(token.allowance(self, user1), 0); assertEq(token.balanceOf(user1), 0); - token.approve(user1, uint(-1)); - assertEq(token.allowance(self, user1), uint(-1)); + token.approve(user1, MAX_UINT); + assertEq(token.allowance(self, user1), MAX_UINT); TokenUser(user1).doTransferFrom(self, user1, 1000); assertEq(token.balanceOf(user1), 1000); - assertEq(token.allowance(self, user1), uint(-1)); + assertEq(token.allowance(self, user1), MAX_UINT); } + function testDaiAddress() public { //The dai address generated by hevm //used for signature generation testing @@ -293,31 +324,72 @@ contract DaiTest is DSTest { function testPermit() public { assertEq(token.nonces(cal), 0); assertEq(token.allowance(cal, del), 0); - token.permit(cal, del, 0, 0, true, v, r, s); - assertEq(token.allowance(cal, del),uint(-1)); - assertEq(token.nonces(cal),1); + + bytes32 digest = keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(token.PERMIT_TYPEHASH(), cal, del, 0, 0, true)) + ) + ); + + (uint8 sigV, bytes32 sigR, bytes32 sigS) = vm.sign(calKey, digest); + token.permit(cal, del, 0, 0, true, sigV, sigR, sigS); + + assertEq(token.allowance(cal, del), MAX_UINT); + assertEq(token.nonces(cal), 1); } - function testFailPermitAddress0() public { + function testRevertPermitAddress0() public { v = 0; + vm.expectRevert(); token.permit(address(0), del, 0, 0, true, v, r, s); } function testPermitWithExpiry() public { - assertEq(now, 604411200); - token.permit(cal, del, 0, 604411200 + 1 hours, true, _v, _r, _s); - assertEq(token.allowance(cal, del),uint(-1)); - assertEq(token.nonces(cal),1); + assertEq(block.timestamp, 604411200); + + uint256 expiry = block.timestamp + 1 hours; + + bytes32 digest = keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(token.PERMIT_TYPEHASH(), cal, del, 0, expiry, true)) + ) + ); + + (uint8 sigV, bytes32 sigR, bytes32 sigS) = vm.sign(calKey, digest); + + token.permit(cal, del, 0, expiry, true, sigV, sigR, sigS); + + assertEq(token.allowance(cal, del), MAX_UINT); + assertEq(token.nonces(cal), 1); } - function testFailPermitWithExpiry() public { - hevm.warp(now + 2 hours); - assertEq(now, 604411200 + 2 hours); + function testRevertPermitWithExpiry() public { + hevm.warp(block.timestamp + 2 hours); + assertEq(block.timestamp, 604411200 + 2 hours); + vm.expectRevert(); token.permit(cal, del, 0, 1, true, _v, _r, _s); } - function testFailReplay() public { - token.permit(cal, del, 0, 0, true, v, r, s); - token.permit(cal, del, 0, 0, true, v, r, s); + function testRevertReplay() public { + bytes32 digest = keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(token.PERMIT_TYPEHASH(), cal, del, 0, 0, true)) + ) + ); + + (uint8 sigV, bytes32 sigR, bytes32 sigS) = vm.sign(calKey, digest); + + // First permit should succeed + token.permit(cal, del, 0, 0, true, sigV, sigR, sigS); + + // Second permit with same signature should revert (nonce has incremented) + vm.expectRevert(); + token.permit(cal, del, 0, 0, true, sigV, sigR, sigS); } } diff --git a/src/test/dog.t.sol b/src/test/dog.t.sol index eeaf939f..87246ec1 100644 --- a/src/test/dog.t.sol +++ b/src/test/dog.t.sol @@ -19,33 +19,33 @@ pragma solidity ^0.6.12; -import { DSTest } from "ds-test/test.sol"; -import { Vat } from "../vat.sol"; -import { Dog } from "../dog.sol"; +import {DSTest} from "ds-test/test.sol"; +import {Vat} from "../vat.sol"; +import {Dog} from "../dog.sol"; contract VowMock { - function fess (uint256 due) public {} + function fess(uint256 due) public {} } contract ClipperMock { bytes32 public ilk; + function setIlk(bytes32 wat) external { ilk = wat; } - function kick(uint256, uint256, address, address) - external pure returns (uint256 id) { + + function kick(uint256, uint256, address, address) external pure returns (uint256 id) { id = 42; } } contract DogTest is DSTest { - bytes32 constant ilk = "gold"; address constant usr = address(1337); - uint256 constant THOUSAND = 1E3; - uint256 constant WAD = 1E18; - uint256 constant RAY = 1E27; - uint256 constant RAD = 1E45; + uint256 constant THOUSAND = 1e3; + uint256 constant WAD = 1e18; + uint256 constant RAY = 1e27; + uint256 constant RAD = 1e45; Vat vat; VowMock vow; ClipperMock clip; @@ -203,13 +203,13 @@ contract DogTest is DSTest { // was also dusty and would fit in the remaining hole/Hole room. function test_bark_dusty_vault_dusty_room() public { // Use a chop that will give nice round numbers - uint256 CHOP = 110 * WAD / 100; // 10% + uint256 CHOP = 110 * WAD / 100; // 10% dog.file(ilk, "chop", CHOP); // set both hole_i and Hole to the same value for this test uint256 ROOM = 200; uint256 HOLE = 33 * THOUSAND + ROOM; - dog.file( "Hole", HOLE * RAD); + dog.file("Hole", HOLE * RAD); dog.file(ilk, "hole", HOLE * RAD); // Test using a non-zero rate to ensure the code is handling stability fees correctly. @@ -227,7 +227,7 @@ contract DogTest is DSTest { // Create a small vault uint256 DUST_1 = 30; vat.file(ilk, "dust", DUST_1 * RAD); - setUrn(WAD / 10**4, DUST_1 * RAD / rate); + setUrn(WAD / 10 ** 4, DUST_1 * RAD / rate); // Dust limit goes up! uint256 DUST_2 = 1500; @@ -277,7 +277,7 @@ contract DogTest is DSTest { // This will need to be partially liquidated setUrn(WAD, hole * WAD * WAD / chop); - assertTrue(!try_bark(ilk, usr, address(this))); // should revert, as the auction would be dusty + assertTrue(!try_bark(ilk, usr, address(this))); // should revert, as the auction would be dusty } function test_bark_do_not_create_dusty_auction_Hole() public { @@ -302,6 +302,6 @@ contract DogTest is DSTest { // This will need to be partially liquidated setUrn(WAD, Hole * WAD * WAD / chop); - assertTrue(!try_bark(ilk, usr, address(this))); // should revert, as the auction would be dusty + assertTrue(!try_bark(ilk, usr, address(this))); // should revert, as the auction would be dusty } } diff --git a/src/test/end.t.sol b/src/test/end.t.sol index f6b99bd8..a67d3ccb 100644 --- a/src/test/end.t.sol +++ b/src/test/end.t.sol @@ -24,19 +24,19 @@ import "ds-test/test.sol"; import "ds-token/token.sol"; import "ds-value/value.sol"; -import {Vat} from '../vat.sol'; -import {Cat} from '../cat.sol'; -import {Dog} from '../dog.sol'; -import {Vow} from '../vow.sol'; -import {Pot} from '../pot.sol'; -import {Flipper} from '../flip.sol'; -import {Clipper} from '../clip.sol'; -import {Flapper} from '../flap.sol'; -import {Flopper} from '../flop.sol'; -import {GemJoin} from '../join.sol'; -import {End} from '../end.sol'; -import {Spotter} from '../spot.sol'; -import {Cure} from '../cure.sol'; +import {Vat} from "../vat.sol"; +import {Cat} from "../cat.sol"; +import {Dog} from "../dog.sol"; +import {Vow} from "../vow.sol"; +import {Pot} from "../pot.sol"; +import {Flipper} from "../flip.sol"; +import {Clipper} from "../clip.sol"; +import {Flapper} from "../flap.sol"; +import {Flopper} from "../flop.sol"; +import {GemJoin} from "../join.sol"; +import {End} from "../end.sol"; +import {Spotter} from "../spot.sol"; +import {Cure} from "../cure.sol"; interface Hevm { function warp(uint256) external; @@ -47,31 +47,39 @@ contract Usr { End public end; constructor(Vat vat_, End end_) public { - vat = vat_; - end = end_; + vat = vat_; + end = end_; } - function frob(bytes32 ilk, address u, address v, address w, int dink, int dart) public { + + function frob(bytes32 ilk, address u, address v, address w, int256 dink, int256 dart) public { vat.frob(ilk, u, v, w, dink, dart); } + function flux(bytes32 ilk, address src, address dst, uint256 wad) public { vat.flux(ilk, src, dst, wad); } + function move(address src, address dst, uint256 rad) public { vat.move(src, dst, rad); } + function hope(address usr) public { vat.hope(usr); } - function exit(GemJoin gemA, address usr, uint wad) public { + + function exit(GemJoin gemA, address usr, uint256 wad) public { gemA.exit(usr, wad); } + function free(bytes32 ilk) public { end.free(ilk); } + function pack(uint256 rad) public { end.pack(rad); } - function cash(bytes32 ilk, uint wad) public { + + function cash(bytes32 ilk, uint256 wad) public { end.cash(ilk, wad); } } @@ -79,12 +87,12 @@ contract Usr { contract EndTest is DSTest { Hevm hevm; - Vat vat; - End end; - Vow vow; - Pot pot; - Cat cat; - Dog dog; + Vat vat; + End end; + Vow vow; + Pot pot; + Cat cat; + Dog dog; Spotter spot; @@ -98,53 +106,67 @@ contract EndTest is DSTest { Clipper clip; } - mapping (bytes32 => Ilk) ilks; + mapping(bytes32 => Ilk) ilks; Flapper flap; Flopper flop; - uint constant WAD = 10 ** 18; - uint constant RAY = 10 ** 27; - uint constant MLN = 10 ** 6; + uint256 constant WAD = 10 ** 18; + uint256 constant RAY = 10 ** 27; + uint256 constant MLN = 10 ** 6; - function ray(uint wad) internal pure returns (uint) { + function ray(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 9; } - function rad(uint wad) internal pure returns (uint) { + + function rad(uint256 wad) internal pure returns (uint256) { return wad * RAY; } - function rmul(uint x, uint y) internal pure returns (uint z) { + + function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * y; require(y == 0 || z / y == x); z = z / RAY; } - function min(uint x, uint y) internal pure returns (uint z) { + + function min(uint256 x, uint256 y) internal pure returns (uint256 z) { (x >= y) ? z = y : z = x; } - function dai(address urn) internal view returns (uint) { + + function dai(address urn) internal view returns (uint256) { return vat.dai(urn) / RAY; } - function gem(bytes32 ilk, address urn) internal view returns (uint) { + + function gem(bytes32 ilk, address urn) internal view returns (uint256) { return vat.gem(ilk, urn); } - function ink(bytes32 ilk, address urn) internal view returns (uint) { - (uint ink_, uint art_) = vat.urns(ilk, urn); art_; + + function ink(bytes32 ilk, address urn) internal view returns (uint256) { + (uint256 ink_, uint256 art_) = vat.urns(ilk, urn); + art_; return ink_; } - function art(bytes32 ilk, address urn) internal view returns (uint) { - (uint ink_, uint art_) = vat.urns(ilk, urn); ink_; + + function art(bytes32 ilk, address urn) internal view returns (uint256) { + (uint256 ink_, uint256 art_) = vat.urns(ilk, urn); + ink_; return art_; } - function Art(bytes32 ilk) internal view returns (uint) { - (uint Art_, uint rate_, uint spot_, uint line_, uint dust_) = vat.ilks(ilk); - rate_; spot_; line_; dust_; + + function Art(bytes32 ilk) internal view returns (uint256) { + (uint256 Art_, uint256 rate_, uint256 spot_, uint256 line_, uint256 dust_) = vat.ilks(ilk); + rate_; + spot_; + line_; + dust_; return Art_; } - function balanceOf(bytes32 ilk, address usr) internal view returns (uint) { + + function balanceOf(bytes32 ilk, address usr) internal view returns (uint256) { return ilks[ilk].gem.balanceOf(usr); } - function try_pot_file(bytes32 what, uint data) public returns(bool ok) { + function try_pot_file(bytes32 what, uint256 data) public returns (bool ok) { string memory sig = "file(bytes32, uint)"; (ok,) = address(pot).call(abi.encodeWithSignature(sig, what, data)); } @@ -205,7 +227,7 @@ contract EndTest is DSTest { hevm.warp(604411200); vat = new Vat(); - DSToken gov = new DSToken('GOV'); + DSToken gov = new DSToken("GOV"); flap = new Flapper(address(vat), address(gov)); flop = new Flopper(address(vat), address(gov)); @@ -228,7 +250,7 @@ contract EndTest is DSTest { vow.rely(address(dog)); spot = new Spotter(address(vat)); - vat.file("Line", rad(1_000_000 ether)); + vat.file("Line", rad(1_000_000 ether)); vat.rely(address(spot)); cure = new Cure(); @@ -372,8 +394,8 @@ contract EndTest is DSTest { gold.pip.poke(bytes32(2 * WAD)); end.cage(); end.cage("gold"); - end.skim("gold", urn1); // over-collateralised - end.skim("gold", urn2); // under-collateralised + end.skim("gold", urn1); // over-collateralised + end.skim("gold", urn2); // under-collateralised // local checks assertEq(art("gold", urn1), 0); @@ -448,14 +470,14 @@ contract EndTest is DSTest { ali.frob("gold", urn1, urn1, urn1, 10 ether, 15 ether); // this urn has 0 gem, 10 ink, 15 tab, 15 dai - vat.file("gold", "spot", ray(1 ether)); // now unsafe + vat.file("gold", "spot", ray(1 ether)); // now unsafe - uint auction = cat.bite("gold", urn1); // CDP liquidated - assertEq(vat.vice(), rad(15 ether)); // now there is sin + uint256 auction = cat.bite("gold", urn1); // CDP liquidated + assertEq(vat.vice(), rad(15 ether)); // now there is sin // get 1 dai from ali ali.move(address(ali), address(this), rad(1 ether)); vat.hope(address(gold.flip)); - (,uint lot,,,,,,) = gold.flip.bids(auction); + (, uint256 lot,,,,,,) = gold.flip.bids(auction); gold.flip.tend(auction, lot, rad(1 ether)); // bid 1 dai assertEq(dai(urn1), 14 ether); @@ -465,7 +487,7 @@ contract EndTest is DSTest { end.cage("gold"); end.skip("gold", auction); - assertEq(dai(address(this)), 1 ether); // bid refunded + assertEq(dai(address(this)), 1 ether); // bid refunded vat.move(address(this), urn1, rad(1 ether)); // return 1 dai to ali end.skim("gold", urn1); @@ -525,8 +547,8 @@ contract EndTest is DSTest { address urn1 = address(ali); gold.gemA.join(urn1, 10 ether); ali.frob("gold", urn1, urn1, urn1, 10 ether, 15 ether); - (uint ink1, uint art1) = vat.urns("gold", urn1); // CDP before liquidation - (, uint rate,,,) = vat.ilks("gold"); + (uint256 ink1, uint256 art1) = vat.urns("gold", urn1); // CDP before liquidation + (, uint256 rate,,,) = vat.ilks("gold"); assertEq(vat.gem("gold", urn1), 0); assertEq(rate, ray(1.25 ether)); @@ -542,7 +564,7 @@ contract EndTest is DSTest { { uint256 pos1; address usr1; - uint96 tic1; + uint96 tic1; uint256 top1; (pos1, tab1, lot1, usr1, tic1, top1) = gold.clip.sales(id); assertEq(pos1, 0); @@ -556,7 +578,7 @@ contract EndTest is DSTest { assertEq(dog.Dirt(), tab1); { - (uint ink2, uint art2) = vat.urns("gold", urn1); // CDP after liquidation + (uint256 ink2, uint256 art2) = vat.urns("gold", urn1); // CDP after liquidation assertEq(ink2, 0); assertEq(art2, 0); } @@ -569,10 +591,10 @@ contract EndTest is DSTest { assertEq(end.tag("gold"), ray(0.2 ether)); // par / price = collateral per DAI assertEq(vat.gem("gold", address(gold.clip)), lot1); // From grab in dog.bark() - assertEq(vat.sin(address(vow)), art1 * rate); // From grab in dog.bark() - assertEq(vat.vice(), art1 * rate); // From grab in dog.bark() - assertEq(vat.debt(), art1 * rate); // From frob - assertEq(vat.dai(address(vow)), 0); // vat.suck() hasn't been called + assertEq(vat.sin(address(vow)), art1 * rate); // From grab in dog.bark() + assertEq(vat.vice(), art1 * rate); // From grab in dog.bark() + assertEq(vat.debt(), art1 * rate); // From frob + assertEq(vat.dai(address(vow)), 0); // vat.suck() hasn't been called end.snip("gold", id); @@ -581,29 +603,29 @@ contract EndTest is DSTest { uint256 tab2; uint256 lot2; address usr2; - uint96 tic2; + uint96 tic2; uint256 top2; (pos2, tab2, lot2, usr2, tic2, top2) = gold.clip.sales(id); - assertEq(pos2, 0); - assertEq(tab2, 0); - assertEq(lot2, 0); - assertEq(usr2, address(0)); + assertEq(pos2, 0); + assertEq(tab2, 0); + assertEq(lot2, 0); + assertEq(usr2, address(0)); assertEq(uint256(tic2), 0); assertEq(uint256(top2), 0); } - assertEq(dog.Dirt(), 0); // From clip.yank() - assertEq(vat.gem("gold", address(gold.clip)), 0); // From clip.yank() - assertEq(vat.gem("gold", address(end)), 0); // From grab in end.snip() - assertEq(vat.sin(address(vow)), art1 * rate); // From grab in dog.bark() - assertEq(vat.vice(), art1 * rate); // From grab in dog.bark() - assertEq(vat.debt(), tab1 + art1 * rate); // From frob and suck - assertEq(vat.dai(address(vow)), tab1); // From vat.suck() - assertEq(end.Art("gold") * rate, tab1); // Incrementing total Art in End + assertEq(dog.Dirt(), 0); // From clip.yank() + assertEq(vat.gem("gold", address(gold.clip)), 0); // From clip.yank() + assertEq(vat.gem("gold", address(end)), 0); // From grab in end.snip() + assertEq(vat.sin(address(vow)), art1 * rate); // From grab in dog.bark() + assertEq(vat.vice(), art1 * rate); // From grab in dog.bark() + assertEq(vat.debt(), tab1 + art1 * rate); // From frob and suck + assertEq(vat.dai(address(vow)), tab1); // From vat.suck() + assertEq(end.Art("gold") * rate, tab1); // Incrementing total Art in End - (uint ink3, uint art3) = vat.urns("gold", urn1); // CDP after snip - assertEq(ink3, 10 ether); // All collateral returned to CDP - assertEq(art3, tab1 / rate); // Tab amount of normalized debt transferred back into CDP + (uint256 ink3, uint256 art3) = vat.urns("gold", urn1); // CDP after snip + assertEq(ink3, 10 ether); // All collateral returned to CDP + assertEq(art3, tab1 / rate); // Tab amount of normalized debt transferred back into CDP } // -- Scenario where there is one over-collateralised CDP @@ -702,8 +724,8 @@ contract EndTest is DSTest { gold.pip.poke(bytes32(2 * WAD)); end.cage(); end.cage("gold"); - end.skim("gold", urn1); // over-collateralised - end.skim("gold", urn2); // under-collateralised + end.skim("gold", urn1); // over-collateralised + end.skim("gold", urn2); // under-collateralised // local checks assertEq(art("gold", urn1), 0); @@ -797,8 +819,8 @@ contract EndTest is DSTest { end.cage(); end.cage("gold"); end.cage("coal"); - end.skim("gold", urn1); // over-collateralised - end.skim("coal", urn2); // under-collateralised + end.skim("gold", urn1); // over-collateralised + end.skim("coal", urn2); // under-collateralised hevm.warp(now + 1 hours); end.thaw(); @@ -808,15 +830,15 @@ contract EndTest is DSTest { ali.hope(address(end)); bob.hope(address(end)); - assertEq(vat.debt(), rad(20 ether)); - assertEq(vat.vice(), rad(20 ether)); - assertEq(vat.sin(address(vow)), rad(20 ether)); + assertEq(vat.debt(), rad(20 ether)); + assertEq(vat.vice(), rad(20 ether)); + assertEq(vat.sin(address(vow)), rad(20 ether)); assertEq(end.Art("gold"), 15 ether); - assertEq(end.Art("coal"), 5 ether); + assertEq(end.Art("coal"), 5 ether); - assertEq(end.gap("gold"), 0.0 ether); - assertEq(end.gap("coal"), 1.5 ether); + assertEq(end.gap("gold"), 0.0 ether); + assertEq(end.gap("coal"), 1.5 ether); // there are 7.5 gold and 1 coal // the gold is worth 15 dai and the coal is worth 2 dai @@ -824,7 +846,7 @@ contract EndTest is DSTest { // the total outstanding debt is 20 dai // each dai should get (15/2)/20 gold and (2/2)/20 coal assertEq(end.fix("gold"), ray(0.375 ether)); - assertEq(end.fix("coal"), ray(0.050 ether)); + assertEq(end.fix("coal"), ray(0.05 ether)); assertEq(gem("gold", address(ali)), 0 ether); ali.pack(1 ether); @@ -836,7 +858,7 @@ contract EndTest is DSTest { assertEq(gem("coal", address(bob)), 0.05 ether); ali.exit(gold.gemA, address(ali), 0.375 ether); - bob.exit(coal.gemA, address(bob), 0.05 ether); + bob.exit(coal.gemA, address(bob), 0.05 ether); ali.pack(1 ether); ali.cash("gold", 1 ether); ali.cash("coal", 1 ether); @@ -844,7 +866,7 @@ contract EndTest is DSTest { assertEq(gem("coal", address(ali)), 0.05 ether); ali.exit(gold.gemA, address(ali), 0.375 ether); - ali.exit(coal.gemA, address(ali), 0.05 ether); + ali.exit(coal.gemA, address(ali), 0.05 ether); ali.pack(1 ether); ali.cash("gold", 1 ether); @@ -900,40 +922,48 @@ contract EndTest is DSTest { end.flow("gold"); } - uint256 constant RAD = 10**45; + uint256 constant RAD = 10 ** 45; + function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } + function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, WAD) / y; } + function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, RAY) / y; } + function fix_calc_0(uint256 col, uint256 debt) internal pure returns (uint256) { return rdiv(mul(col, RAY), debt); } + function fix_calc_1(uint256 col, uint256 debt) internal pure returns (uint256) { - return wdiv(mul(col, RAY), (debt / 10**9)); + return wdiv(mul(col, RAY), (debt / 10 ** 9)); } + function fix_calc_2(uint256 col, uint256 debt) internal pure returns (uint256) { return mul(col, RAY) / (debt / RAY); } + function wAssertCloseEnough(uint256 x, uint256 y) internal { uint256 diff = x > y ? x - y : y - x; if (diff == 0) return; uint256 xErr = mul(diff, WAD) / x; uint256 yErr = mul(diff, WAD) / y; - uint256 err = xErr > yErr ? xErr : yErr; - assertTrue(err < WAD / 100_000_000); // Error no more than one part in a hundred million + uint256 err = xErr > yErr ? xErr : yErr; + assertTrue(err < WAD / 100_000_000); // Error no more than one part in a hundred million } - uint256 constant MIN_DEBT = 10**6 * RAD; // Minimum debt for fuzz runs - uint256 constant REDEEM_AMT = 1_000 * WAD; // Amount of DAI to redeem for error checking + uint256 constant MIN_DEBT = 10 ** 6 * RAD; // Minimum debt for fuzz runs + uint256 constant REDEEM_AMT = 1_000 * WAD; // Amount of DAI to redeem for error checking + function test_fuzz_fix_calcs_0_1(uint256 col_seed, uint192 debt_seed) public { - uint256 col = col_seed % (115792 * WAD); // somewhat biased, but not enough to matter - if (col < 10**12) col += 10**12; // At least 10^-6 WAD units of collateral; this makes the fixes almost always non-zero. + uint256 col = col_seed % (115792 * WAD); // somewhat biased, but not enough to matter + if (col < 10 ** 12) col += 10 ** 12; // At least 10^-6 WAD units of collateral; this makes the fixes almost always non-zero. uint256 debt = debt_seed; - if (debt < MIN_DEBT) debt += MIN_DEBT; // consider at least MIN_DEBT of debt + if (debt < MIN_DEBT) debt += MIN_DEBT; // consider at least MIN_DEBT of debt uint256 fix0 = fix_calc_0(col, debt); uint256 fix1 = fix_calc_1(col, debt); @@ -945,11 +975,12 @@ contract EndTest is DSTest { // Assert on percentage error of returned collateral wAssertCloseEnough(col0, col1); } + function test_fuzz_fix_calcs_0_2(uint256 col_seed, uint192 debt_seed) public { - uint256 col = col_seed % (115792 * WAD); // somewhat biased, but not enough to matter - if (col < 10**12) col += 10**12; // At least 10^-6 WAD units of collateral; this makes the fixes almost always non-zero. + uint256 col = col_seed % (115792 * WAD); // somewhat biased, but not enough to matter + if (col < 10 ** 12) col += 10 ** 12; // At least 10^-6 WAD units of collateral; this makes the fixes almost always non-zero. uint256 debt = debt_seed; - if (debt < MIN_DEBT) debt += MIN_DEBT; // consider at least MIN_DEBT of debt + if (debt < MIN_DEBT) debt += MIN_DEBT; // consider at least MIN_DEBT of debt uint256 fix0 = fix_calc_0(col, debt); uint256 fix2 = fix_calc_2(col, debt); @@ -961,11 +992,12 @@ contract EndTest is DSTest { // Assert on percentage error of returned collateral wAssertCloseEnough(col0, col2); } + function test_fuzz_fix_calcs_1_2(uint256 col_seed, uint192 debt_seed) public { - uint256 col = col_seed % (10**14 * WAD); // somewhat biased, but not enough to matter - if (col < 10**12) col += 10**12; // At least 10^-6 WAD units of collateral; this makes the fixes almost always non-zero. + uint256 col = col_seed % (10 ** 14 * WAD); // somewhat biased, but not enough to matter + if (col < 10 ** 12) col += 10 ** 12; // At least 10^-6 WAD units of collateral; this makes the fixes almost always non-zero. uint256 debt = debt_seed; - if (debt < MIN_DEBT) debt += MIN_DEBT; // consider at least MIN_DEBT of debt + if (debt < MIN_DEBT) debt += MIN_DEBT; // consider at least MIN_DEBT of debt uint256 fix1 = fix_calc_1(col, debt); uint256 fix2 = fix_calc_2(col, debt); diff --git a/src/test/flap.t.sol b/src/test/flap.t.sol index 112311f7..038d886b 100644 --- a/src/test/flap.t.sol +++ b/src/test/flap.t.sol @@ -24,39 +24,38 @@ import {DSToken} from "ds-token/token.sol"; import "../flap.sol"; import "../vat.sol"; - interface Hevm { function warp(uint256) external; } contract Guy { Flapper flap; + constructor(Flapper flap_) public { flap = flap_; Vat(address(flap.vat())).hope(address(flap)); DSToken(address(flap.gem())).approve(address(flap)); } - function tend(uint id, uint lot, uint bid) public { + + function tend(uint256 id, uint256 lot, uint256 bid) public { flap.tend(id, lot, bid); } - function deal(uint id) public { + + function deal(uint256 id) public { flap.deal(id); } - function try_tend(uint id, uint lot, uint bid) - public returns (bool ok) - { + + function try_tend(uint256 id, uint256 lot, uint256 bid) public returns (bool ok) { string memory sig = "tend(uint256,uint256,uint256)"; (ok,) = address(flap).call(abi.encodeWithSignature(sig, id, lot, bid)); } - function try_deal(uint id) - public returns (bool ok) - { + + function try_deal(uint256 id) public returns (bool ok) { string memory sig = "deal(uint256)"; (ok,) = address(flap).call(abi.encodeWithSignature(sig, id)); } - function try_tick(uint id) - public returns (bool ok) - { + + function try_tick(uint256 id) public returns (bool ok) { string memory sig = "tick(uint256)"; (ok,) = address(flap).call(abi.encodeWithSignature(sig, id)); } @@ -66,7 +65,7 @@ contract FlapTest is DSTest { Hevm hevm; Flapper flap; - Vat vat; + Vat vat; DSToken gem; address ali; @@ -77,7 +76,7 @@ contract FlapTest is DSTest { hevm.warp(604411200); vat = new Vat(); - gem = new DSToken(''); + gem = new DSToken(""); flap = new Flapper(address(vat), address(gem)); flap.file("lid", 500 ether); @@ -96,21 +95,19 @@ contract FlapTest is DSTest { gem.push(ali, 200 ether); gem.push(bob, 200 ether); } + function test_kick() public { assertEq(vat.dai(address(this)), 1000 ether); - assertEq(vat.dai(address(flap)), 0 ether); - assertEq(flap.fill(), 0 ether); - flap.kick({ lot: 100 ether - , bid: 0 - }); - assertEq(vat.dai(address(this)), 900 ether); - assertEq(vat.dai(address(flap)), 100 ether); - assertEq(flap.fill(), 100 ether); + assertEq(vat.dai(address(flap)), 0 ether); + assertEq(flap.fill(), 0 ether); + flap.kick({lot: 100 ether, bid: 0}); + assertEq(vat.dai(address(this)), 900 ether); + assertEq(vat.dai(address(flap)), 100 ether); + assertEq(flap.fill(), 100 ether); } + function test_tend() public { - uint id = flap.kick({ lot: 100 ether - , bid: 0 - }); + uint256 id = flap.kick({lot: 100 ether, bid: 0}); // lot taken from creator assertEq(vat.dai(address(this)), 900 ether); @@ -118,7 +115,7 @@ contract FlapTest is DSTest { // bid taken from bidder assertEq(gem.balanceOf(ali), 199 ether); // payment remains in auction - assertEq(gem.balanceOf(address(flap)), 1 ether); + assertEq(gem.balanceOf(address(flap)), 1 ether); Guy(bob).tend(id, 100 ether, 2 ether); // bid taken from bidder @@ -126,97 +123,82 @@ contract FlapTest is DSTest { // prev bidder refunded assertEq(gem.balanceOf(ali), 200 ether); // excess remains in auction - assertEq(gem.balanceOf(address(flap)), 2 ether); + assertEq(gem.balanceOf(address(flap)), 2 ether); hevm.warp(now + 5 weeks); Guy(bob).deal(id); // high bidder gets the lot - assertEq(vat.dai(address(flap)), 0 ether); + assertEq(vat.dai(address(flap)), 0 ether); assertEq(vat.dai(bob), 100 ether); // income is burned - assertEq(gem.balanceOf(address(flap)), 0 ether); + assertEq(gem.balanceOf(address(flap)), 0 ether); } + function test_tend_same_bidder() public { - uint id = flap.kick({ lot: 100 ether - , bid: 0 - }); + uint256 id = flap.kick({lot: 100 ether, bid: 0}); Guy(ali).tend(id, 100 ether, 190 ether); assertEq(gem.balanceOf(ali), 10 ether); Guy(ali).tend(id, 100 ether, 200 ether); assertEq(gem.balanceOf(ali), 0); } + function test_beg() public { - uint id = flap.kick({ lot: 100 ether - , bid: 0 - }); - assertTrue( Guy(ali).try_tend(id, 100 ether, 1.00 ether)); + uint256 id = flap.kick({lot: 100 ether, bid: 0}); + assertTrue(Guy(ali).try_tend(id, 100 ether, 1.0 ether)); assertTrue(!Guy(bob).try_tend(id, 100 ether, 1.01 ether)); // high bidder is subject to beg assertTrue(!Guy(ali).try_tend(id, 100 ether, 1.01 ether)); - assertTrue( Guy(bob).try_tend(id, 100 ether, 1.07 ether)); + assertTrue(Guy(bob).try_tend(id, 100 ether, 1.07 ether)); } + function test_tick() public { // start an auction - uint id = flap.kick({ lot: 100 ether - , bid: 0 - }); + uint256 id = flap.kick({lot: 100 ether, bid: 0}); // check no tick assertTrue(!Guy(ali).try_tick(id)); // run past the end hevm.warp(now + 2 weeks); // check not biddable assertTrue(!Guy(ali).try_tend(id, 100 ether, 1 ether)); - assertTrue( Guy(ali).try_tick(id)); + assertTrue(Guy(ali).try_tick(id)); // check biddable - assertTrue( Guy(ali).try_tend(id, 100 ether, 1 ether)); + assertTrue(Guy(ali).try_tend(id, 100 ether, 1 ether)); } + function testFail_kick_over_lid() public { - flap.kick({ lot: 501 ether - , bid: 0 - }); + flap.kick({lot: 501 ether, bid: 0}); } + function testFail_kick_over_lid_2_auctions() public { // Just up to the lid - flap.kick({ lot: 500 ether - , bid: 0 - }); + flap.kick({lot: 500 ether, bid: 0}); // Just over the lid - flap.kick({ lot: 1 - , bid: 0 - }); + flap.kick({lot: 1, bid: 0}); } + function test_deal() public { - uint256 id = flap.kick({ lot: 400 ether - , bid: 0 - }); + uint256 id = flap.kick({lot: 400 ether, bid: 0}); assertEq(flap.fill(), 400 ether); Guy(ali).tend(id, 400 ether, 1 ether); assertEq(flap.fill(), 400 ether); hevm.warp(block.timestamp + 30 days); flap.deal(id); assertEq(flap.fill(), 0); - flap.kick({ lot: 400 ether - , bid: 0 - }); + flap.kick({lot: 400 ether, bid: 0}); assertEq(flap.fill(), 400 ether); } + function test_multiple_auctions() public { - uint256 id1 = flap.kick({ lot: 200 ether - , bid: 0 - }); + uint256 id1 = flap.kick({lot: 200 ether, bid: 0}); assertEq(flap.fill(), 200 ether); - uint256 id2 = flap.kick({ lot: 200 ether - , bid: 0 - }); + uint256 id2 = flap.kick({lot: 200 ether, bid: 0}); assertEq(flap.fill(), 400 ether); Guy(ali).tend(id1, 200 ether, 1 ether); assertEq(flap.fill(), 400 ether); hevm.warp(block.timestamp + 30 days); flap.deal(id1); assertEq(flap.fill(), 200 ether); - flap.kick({ lot: 300 ether - , bid: 0 - }); + flap.kick({lot: 300 ether, bid: 0}); assertEq(flap.fill(), 500 ether); flap.tick(id2); Guy(ali).tend(id2, 200 ether, 1 ether); @@ -225,10 +207,9 @@ contract FlapTest is DSTest { flap.deal(id2); assertEq(flap.fill(), 300 ether); } + function test_mod_lid_in_flight() public { - uint256 id = flap.kick({ lot: 400 ether - , bid: 0 - }); + uint256 id = flap.kick({lot: 400 ether, bid: 0}); assertEq(flap.fill(), 400 ether); assertEq(flap.lid(), 500 ether); @@ -241,10 +222,7 @@ contract FlapTest is DSTest { hevm.warp(block.timestamp + 30 days); flap.deal(id); assertEq(flap.fill(), 0); - flap.kick({ lot: 300 ether - , bid: 0 - }); + flap.kick({lot: 300 ether, bid: 0}); assertEq(flap.fill(), 300 ether); } - } diff --git a/src/test/flip.t.sol b/src/test/flip.t.sol index f817fb45..836963ab 100644 --- a/src/test/flip.t.sol +++ b/src/test/flip.t.sol @@ -4,8 +4,8 @@ pragma solidity >=0.5.12; import "ds-test/test.sol"; -import {Vat} from "../vat.sol"; -import {Cat} from "../cat.sol"; +import {Vat} from "../vat.sol"; +import {Cat} from "../cat.sol"; import {Flipper} from "../flip.sol"; interface Hevm { @@ -14,77 +14,79 @@ interface Hevm { contract Guy { Flipper flip; + constructor(Flipper flip_) public { flip = flip_; } + function hope(address usr) public { Vat(address(flip.vat())).hope(usr); } - function tend(uint id, uint lot, uint bid) public { + + function tend(uint256 id, uint256 lot, uint256 bid) public { flip.tend(id, lot, bid); } - function dent(uint id, uint lot, uint bid) public { + + function dent(uint256 id, uint256 lot, uint256 bid) public { flip.dent(id, lot, bid); } - function deal(uint id) public { + + function deal(uint256 id) public { flip.deal(id); } - function try_tend(uint id, uint lot, uint bid) - public returns (bool ok) - { + + function try_tend(uint256 id, uint256 lot, uint256 bid) public returns (bool ok) { string memory sig = "tend(uint256,uint256,uint256)"; (ok,) = address(flip).call(abi.encodeWithSignature(sig, id, lot, bid)); } - function try_dent(uint id, uint lot, uint bid) - public returns (bool ok) - { + + function try_dent(uint256 id, uint256 lot, uint256 bid) public returns (bool ok) { string memory sig = "dent(uint256,uint256,uint256)"; (ok,) = address(flip).call(abi.encodeWithSignature(sig, id, lot, bid)); } - function try_deal(uint id) - public returns (bool ok) - { + + function try_deal(uint256 id) public returns (bool ok) { string memory sig = "deal(uint256)"; (ok,) = address(flip).call(abi.encodeWithSignature(sig, id)); } - function try_tick(uint id) - public returns (bool ok) - { + + function try_tick(uint256 id) public returns (bool ok) { string memory sig = "tick(uint256)"; (ok,) = address(flip).call(abi.encodeWithSignature(sig, id)); } - function try_yank(uint id) - public returns (bool ok) - { + + function try_yank(uint256 id) public returns (bool ok) { string memory sig = "yank(uint256)"; (ok,) = address(flip).call(abi.encodeWithSignature(sig, id)); } } - contract Gal {} contract Cat_ is Cat { - uint256 constant public RAD = 10 ** 45; - uint256 constant public MLN = 10 ** 6; + uint256 public constant RAD = 10 ** 45; + uint256 public constant MLN = 10 ** 6; - constructor(address vat_) Cat(vat_) public { + constructor(address vat_) public Cat(vat_) { litter = 5 * MLN * RAD; } } contract Vat_ is Vat { - function mint(address usr, uint wad) public { + function mint(address usr, uint256 wad) public { dai[usr] += wad; } - function dai_balance(address usr) public view returns (uint) { + + function dai_balance(address usr) public view returns (uint256) { return dai[usr]; } bytes32 ilk; + function set_ilk(bytes32 ilk_) public { ilk = ilk_; } - function gem_balance(address usr) public view returns (uint) { + + function gem_balance(address usr) public view returns (uint256) { return gem[ilk][usr]; } } @@ -92,8 +94,8 @@ contract Vat_ is Vat { contract FlipTest is DSTest { Hevm hevm; - Vat_ vat; - Cat_ cat; + Vat_ vat; + Cat_ cat; Flipper flip; address ali; @@ -101,9 +103,9 @@ contract FlipTest is DSTest { address gal; address usr = address(0xacab); - uint256 constant public RAY = 10 ** 27; - uint256 constant public RAD = 10 ** 45; - uint256 constant public MLN = 10 ** 6; + uint256 public constant RAY = 10 ** 27; + uint256 public constant RAD = 10 ** 45; + uint256 public constant MLN = 10 ** 6; function setUp() public { hevm = Hevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); @@ -130,34 +132,28 @@ contract FlipTest is DSTest { vat.mint(ali, 200 ether); vat.mint(bob, 200 ether); } - function rad(uint wad) internal pure returns (uint) { + + function rad(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 27; } + function test_kick() public { - flip.kick({ lot: 100 ether - , tab: 50 ether - , usr: usr - , gal: gal - , bid: 0 - }); + flip.kick({lot: 100 ether, tab: 50 ether, usr: usr, gal: gal, bid: 0}); } + function testFail_tend_empty() public { // can't tend on non-existent flip.tend(42, 0, 0); } + function test_tend() public { - uint id = flip.kick({ lot: 100 ether - , tab: 50 ether - , usr: usr - , gal: gal - , bid: 0 - }); + uint256 id = flip.kick({lot: 100 ether, tab: 50 ether, usr: usr, gal: gal, bid: 0}); Guy(ali).tend(id, 100 ether, 1 ether); // bid taken from bidder - assertEq(vat.dai_balance(ali), 199 ether); + assertEq(vat.dai_balance(ali), 199 ether); // gal receives payment - assertEq(vat.dai_balance(gal), 1 ether); + assertEq(vat.dai_balance(gal), 1 ether); Guy(bob).tend(id, 100 ether, 2 ether); // bid taken from bidder @@ -165,51 +161,39 @@ contract FlipTest is DSTest { // prev bidder refunded assertEq(vat.dai_balance(ali), 200 ether); // gal receives excess - assertEq(vat.dai_balance(gal), 2 ether); + assertEq(vat.dai_balance(gal), 2 ether); hevm.warp(now + 5 hours); Guy(bob).deal(id); // bob gets the winnings assertEq(vat.gem_balance(bob), 100 ether); } + function test_tend_later() public { - uint id = flip.kick({ lot: 100 ether - , tab: 50 ether - , usr: usr - , gal: gal - , bid: 0 - }); + uint256 id = flip.kick({lot: 100 ether, tab: 50 ether, usr: usr, gal: gal, bid: 0}); hevm.warp(now + 5 hours); Guy(ali).tend(id, 100 ether, 1 ether); // bid taken from bidder assertEq(vat.dai_balance(ali), 199 ether); // gal receives payment - assertEq(vat.dai_balance(gal), 1 ether); + assertEq(vat.dai_balance(gal), 1 ether); } + function test_dent() public { - uint id = flip.kick({ lot: 100 ether - , tab: 50 ether - , usr: usr - , gal: gal - , bid: 0 - }); - Guy(ali).tend(id, 100 ether, 1 ether); + uint256 id = flip.kick({lot: 100 ether, tab: 50 ether, usr: usr, gal: gal, bid: 0}); + Guy(ali).tend(id, 100 ether, 1 ether); Guy(bob).tend(id, 100 ether, 50 ether); - Guy(ali).dent(id, 95 ether, 50 ether); + Guy(ali).dent(id, 95 ether, 50 ether); // plop the gems assertEq(vat.gem_balance(address(0xacab)), 5 ether); - assertEq(vat.dai_balance(ali), 150 ether); - assertEq(vat.dai_balance(bob), 200 ether); + assertEq(vat.dai_balance(ali), 150 ether); + assertEq(vat.dai_balance(bob), 200 ether); } + function test_tend_dent_same_bidder() public { - uint id = flip.kick({ lot: 100 ether - , tab: 200 ether - , usr: usr - , gal: gal - , bid: 0 - }); + uint256 id = flip.kick({lot: 100 ether, tab: 200 ether, usr: usr, gal: gal, bid: 0}); assertEq(vat.dai_balance(ali), 200 ether); Guy(ali).tend(id, 100 ether, 190 ether); @@ -218,101 +202,76 @@ contract FlipTest is DSTest { assertEq(vat.dai_balance(ali), 0); Guy(ali).dent(id, 80 ether, 200 ether); } + function test_beg() public { - uint id = flip.kick({ lot: 100 ether - , tab: 50 ether - , usr: usr - , gal: gal - , bid: 0 - }); - assertTrue( Guy(ali).try_tend(id, 100 ether, 1.00 ether)); + uint256 id = flip.kick({lot: 100 ether, tab: 50 ether, usr: usr, gal: gal, bid: 0}); + assertTrue(Guy(ali).try_tend(id, 100 ether, 1.0 ether)); assertTrue(!Guy(bob).try_tend(id, 100 ether, 1.01 ether)); // high bidder is subject to beg assertTrue(!Guy(ali).try_tend(id, 100 ether, 1.01 ether)); - assertTrue( Guy(bob).try_tend(id, 100 ether, 1.07 ether)); + assertTrue(Guy(bob).try_tend(id, 100 ether, 1.07 ether)); // can bid by less than beg at flip - assertTrue( Guy(ali).try_tend(id, 100 ether, 49 ether)); - assertTrue( Guy(bob).try_tend(id, 100 ether, 50 ether)); + assertTrue(Guy(ali).try_tend(id, 100 ether, 49 ether)); + assertTrue(Guy(bob).try_tend(id, 100 ether, 50 ether)); assertTrue(!Guy(ali).try_dent(id, 100 ether, 50 ether)); - assertTrue(!Guy(ali).try_dent(id, 99 ether, 50 ether)); - assertTrue( Guy(ali).try_dent(id, 95 ether, 50 ether)); + assertTrue(!Guy(ali).try_dent(id, 99 ether, 50 ether)); + assertTrue(Guy(ali).try_dent(id, 95 ether, 50 ether)); } + function test_deal() public { - uint id = flip.kick({ lot: 100 ether - , tab: 50 ether - , usr: usr - , gal: gal - , bid: 0 - }); + uint256 id = flip.kick({lot: 100 ether, tab: 50 ether, usr: usr, gal: gal, bid: 0}); // only after ttl Guy(ali).tend(id, 100 ether, 1 ether); assertTrue(!Guy(bob).try_deal(id)); hevm.warp(now + 4.1 hours); - assertTrue( Guy(bob).try_deal(id)); + assertTrue(Guy(bob).try_deal(id)); - uint ie = flip.kick({ lot: 100 ether - , tab: 50 ether - , usr: usr - , gal: gal - , bid: 0 - }); + uint256 ie = flip.kick({lot: 100 ether, tab: 50 ether, usr: usr, gal: gal, bid: 0}); // or after end hevm.warp(now + 44 hours); Guy(ali).tend(ie, 100 ether, 1 ether); assertTrue(!Guy(bob).try_deal(ie)); hevm.warp(now + 1 days); - assertTrue( Guy(bob).try_deal(ie)); + assertTrue(Guy(bob).try_deal(ie)); } + function test_tick() public { // start an auction - uint id = flip.kick({ lot: 100 ether - , tab: 50 ether - , usr: usr - , gal: gal - , bid: 0 - }); + uint256 id = flip.kick({lot: 100 ether, tab: 50 ether, usr: usr, gal: gal, bid: 0}); // check no tick assertTrue(!Guy(ali).try_tick(id)); // run past the end hevm.warp(now + 2 weeks); // check not biddable assertTrue(!Guy(ali).try_tend(id, 100 ether, 1 ether)); - assertTrue( Guy(ali).try_tick(id)); + assertTrue(Guy(ali).try_tick(id)); // check biddable - assertTrue( Guy(ali).try_tend(id, 100 ether, 1 ether)); + assertTrue(Guy(ali).try_tend(id, 100 ether, 1 ether)); } + function test_no_deal_after_end() public { // if there are no bids and the auction ends, then it should not // be refundable to the creator. Rather, it ticks indefinitely. - uint id = flip.kick({ lot: 100 ether - , tab: 50 ether - , usr: usr - , gal: gal - , bid: 0 - }); + uint256 id = flip.kick({lot: 100 ether, tab: 50 ether, usr: usr, gal: gal, bid: 0}); assertTrue(!Guy(ali).try_deal(id)); hevm.warp(now + 2 weeks); assertTrue(!Guy(ali).try_deal(id)); - assertTrue( Guy(ali).try_tick(id)); + assertTrue(Guy(ali).try_tick(id)); assertTrue(!Guy(ali).try_deal(id)); } + function test_yank_tend() public { - uint id = flip.kick({ lot: 100 ether - , tab: rad(50 ether) - , usr: usr - , gal: gal - , bid: 0 - }); + uint256 id = flip.kick({lot: 100 ether, tab: rad(50 ether), usr: usr, gal: gal, bid: 0}); Guy(ali).tend(id, 100 ether, 1 ether); // bid taken from bidder assertEq(vat.dai_balance(ali), 199 ether); - assertEq(vat.dai_balance(gal), 1 ether); + assertEq(vat.dai_balance(gal), 1 ether); // we have some amount of litter in the box assertEq(cat.litter(), 5 * MLN * RAD); @@ -321,8 +280,8 @@ contract FlipTest is DSTest { flip.yank(id); // bid is refunded to bidder from caller - assertEq(vat.dai_balance(ali), 200 ether); - assertEq(vat.dai_balance(address(this)), 0 ether); + assertEq(vat.dai_balance(ali), 200 ether); + assertEq(vat.dai_balance(address(this)), 0 ether); // gems go to caller assertEq(vat.gem_balance(address(this)), 1000 ether); @@ -330,20 +289,16 @@ contract FlipTest is DSTest { // cat.scoop(tab) is called decrementing the litter accumulator assertEq(cat.litter(), (5 * MLN * RAD) - rad(50 ether)); } + function test_yank_dent() public { - uint id = flip.kick({ lot: 100 ether - , tab: 50 ether - , usr: usr - , gal: gal - , bid: 0 - }); + uint256 id = flip.kick({lot: 100 ether, tab: 50 ether, usr: usr, gal: gal, bid: 0}); // we have some amount of litter in the box assertEq(cat.litter(), 5 * MLN * RAD); - Guy(ali).tend(id, 100 ether, 1 ether); + Guy(ali).tend(id, 100 ether, 1 ether); Guy(bob).tend(id, 100 ether, 50 ether); - Guy(ali).dent(id, 95 ether, 50 ether); + Guy(ali).dent(id, 95 ether, 50 ether); // cannot yank in the dent phase assertTrue(!Guy(ali).try_yank(id)); diff --git a/src/test/flop.t.sol b/src/test/flop.t.sol index ce866ab6..d7596f2b 100644 --- a/src/test/flop.t.sol +++ b/src/test/flop.t.sol @@ -17,73 +17,78 @@ pragma solidity ^0.6.12; -import {DSTest} from "ds-test/test.sol"; +import {DSTest} from "ds-test/test.sol"; import {DSToken} from "ds-token/token.sol"; import "../flop.sol"; import "../vat.sol"; - interface Hevm { function warp(uint256) external; } contract Guy { Flopper flop; + constructor(Flopper flop_) public { flop = flop_; Vat(address(flop.vat())).hope(address(flop)); DSToken(address(flop.gem())).approve(address(flop)); } - function dent(uint id, uint lot, uint bid) public { + + function dent(uint256 id, uint256 lot, uint256 bid) public { flop.dent(id, lot, bid); } - function deal(uint id) public { + + function deal(uint256 id) public { flop.deal(id); } - function try_dent(uint id, uint lot, uint bid) - public returns (bool ok) - { + + function try_dent(uint256 id, uint256 lot, uint256 bid) public returns (bool ok) { string memory sig = "dent(uint256,uint256,uint256)"; (ok,) = address(flop).call(abi.encodeWithSignature(sig, id, lot, bid)); } - function try_deal(uint id) - public returns (bool ok) - { + + function try_deal(uint256 id) public returns (bool ok) { string memory sig = "deal(uint256)"; (ok,) = address(flop).call(abi.encodeWithSignature(sig, id)); } - function try_tick(uint id) - public returns (bool ok) - { + + function try_tick(uint256 id) public returns (bool ok) { string memory sig = "tick(uint256)"; (ok,) = address(flop).call(abi.encodeWithSignature(sig, id)); } } contract Gal { - uint public Ash; - function sub(uint x, uint y) internal pure returns (uint z) { + uint256 public Ash; + + function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } - function kick(Flopper flop, uint lot, uint bid) external returns (uint) { + + function kick(Flopper flop, uint256 lot, uint256 bid) external returns (uint256) { Ash += bid; return flop.kick(address(this), lot, bid); } - function kiss(uint rad) external { + + function kiss(uint256 rad) external { Ash = sub(Ash, rad); } + function cage(Flopper flop) external { flop.cage(); } } -contract Vatish is DSToken('') { - uint constant ONE = 10 ** 27; +contract Vatish is DSToken("") { + uint256 constant ONE = 10 ** 27; + function hope(address usr) public { - approve(usr, uint(-1)); + approve(usr, uint256(-1)); } - function dai(address usr) public view returns (uint) { - return balanceOf[usr]; + + function dai(address usr) public view returns (uint256) { + return balanceOf[usr]; } } @@ -91,21 +96,21 @@ contract FlopTest is DSTest { Hevm hevm; Flopper flop; - Vat vat; + Vat vat; DSToken gem; address ali; address bob; address gal; - function kiss(uint) public pure { } // arbitrary callback + function kiss(uint256) public pure {} // arbitrary callback function setUp() public { hevm = Hevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); hevm.warp(604411200); vat = new Vat(); - gem = new DSToken(''); + gem = new DSToken(""); flop = new Flopper(address(vat), address(gem)); @@ -129,7 +134,14 @@ contract FlopTest is DSTest { function test_kick() public { assertEq(vat.dai(gal), 0); assertEq(gem.balanceOf(gal), 0 ether); - uint id = Gal(gal).kick(flop, /*lot*/ 200 ether, /*bid*/ 5000 ether); + uint256 id = Gal(gal) + .kick( + flop, + /*lot*/ + 200 ether, + /*bid*/ + 5000 ether + ); // no value transferred assertEq(vat.dai(gal), 0); assertEq(gem.balanceOf(gal), 0 ether); @@ -144,13 +156,20 @@ contract FlopTest is DSTest { } function test_dent() public { - uint id = Gal(gal).kick(flop, /*lot*/ 200 ether, /*bid*/ 10 ether); + uint256 id = Gal(gal) + .kick( + flop, + /*lot*/ + 200 ether, + /*bid*/ + 10 ether + ); Guy(ali).dent(id, 100 ether, 10 ether); // bid taken from bidder assertEq(vat.dai(ali), 190 ether); // gal receives payment - assertEq(vat.dai(gal), 10 ether); + assertEq(vat.dai(gal), 10 ether); assertEq(Gal(gal).Ash(), 0 ether); Guy(bob).dent(id, 80 ether, 10 ether); @@ -162,7 +181,7 @@ contract FlopTest is DSTest { assertEq(vat.dai(gal), 10 ether); hevm.warp(now + 5 weeks); - assertEq(gem.totalSupply(), 0 ether); + assertEq(gem.totalSupply(), 0 ether); gem.setOwner(address(flop)); Guy(bob).deal(id); // gems minted on demand @@ -172,8 +191,15 @@ contract FlopTest is DSTest { } function test_dent_Ash_less_than_bid() public { - uint id = Gal(gal).kick(flop, /*lot*/ 200 ether, /*bid*/ 10 ether); - assertEq(vat.dai(gal), 0 ether); + uint256 id = Gal(gal) + .kick( + flop, + /*lot*/ + 200 ether, + /*bid*/ + 10 ether + ); + assertEq(vat.dai(gal), 0 ether); Gal(gal).kiss(1 ether); assertEq(Gal(gal).Ash(), 9 ether); @@ -182,7 +208,7 @@ contract FlopTest is DSTest { // bid taken from bidder assertEq(vat.dai(ali), 190 ether); // gal receives payment - assertEq(vat.dai(gal), 10 ether); + assertEq(vat.dai(gal), 10 ether); assertEq(Gal(gal).Ash(), 0 ether); Guy(bob).dent(id, 80 ether, 10 ether); @@ -194,7 +220,7 @@ contract FlopTest is DSTest { assertEq(vat.dai(gal), 10 ether); hevm.warp(now + 5 weeks); - assertEq(gem.totalSupply(), 0 ether); + assertEq(gem.totalSupply(), 0 ether); gem.setOwner(address(flop)); Guy(bob).deal(id); // gems minted on demand @@ -204,7 +230,14 @@ contract FlopTest is DSTest { } function test_dent_same_bidder() public { - uint id = Gal(gal).kick(flop, /*lot*/ 200 ether, /*bid*/ 200 ether); + uint256 id = Gal(gal) + .kick( + flop, + /*lot*/ + 200 ether, + /*bid*/ + 200 ether + ); Guy(ali).dent(id, 100 ether, 200 ether); assertEq(vat.dai(ali), 0); @@ -213,29 +246,43 @@ contract FlopTest is DSTest { function test_tick() public { // start an auction - uint id = Gal(gal).kick(flop, /*lot*/ 200 ether, /*bid*/ 10 ether); + uint256 id = Gal(gal) + .kick( + flop, + /*lot*/ + 200 ether, + /*bid*/ + 10 ether + ); // check no tick assertTrue(!Guy(ali).try_tick(id)); // run past the end hevm.warp(now + 2 weeks); // check not biddable assertTrue(!Guy(ali).try_dent(id, 100 ether, 10 ether)); - assertTrue( Guy(ali).try_tick(id)); + assertTrue(Guy(ali).try_tick(id)); // check biddable - (, uint _lot,,,) = flop.bids(id); + (, uint256 _lot,,,) = flop.bids(id); // tick should increase the lot by pad (50%) and restart the auction assertEq(_lot, 300 ether); - assertTrue( Guy(ali).try_dent(id, 100 ether, 10 ether)); + assertTrue(Guy(ali).try_dent(id, 100 ether, 10 ether)); } function test_no_deal_after_end() public { // if there are no bids and the auction ends, then it should not // be refundable to the creator. Rather, it ticks indefinitely. - uint id = Gal(gal).kick(flop, /*lot*/ 200 ether, /*bid*/ 10 ether); + uint256 id = Gal(gal) + .kick( + flop, + /*lot*/ + 200 ether, + /*bid*/ + 10 ether + ); assertTrue(!Guy(ali).try_deal(id)); hevm.warp(now + 2 weeks); assertTrue(!Guy(ali).try_deal(id)); - assertTrue( Guy(ali).try_tick(id)); + assertTrue(Guy(ali).try_tick(id)); assertTrue(!Guy(ali).try_deal(id)); } @@ -243,7 +290,14 @@ contract FlopTest is DSTest { // yanking the auction should refund the last bidder's dai, credit a // corresponding amount of sin to the caller of cage, and delete the auction. // in practice, gal == (caller of cage) == (vow address) - uint id = Gal(gal).kick(flop, /*lot*/ 200 ether, /*bid*/ 10 ether); + uint256 id = Gal(gal) + .kick( + flop, + /*lot*/ + 200 ether, + /*bid*/ + 10 ether + ); // confrim initial state expectations assertEq(vat.dai(ali), 200 ether); @@ -255,9 +309,9 @@ contract FlopTest is DSTest { Guy(bob).dent(id, 80 ether, 10 ether); // confirm the proper state updates have occurred - assertEq(vat.dai(ali), 200 ether); // ali's dai balance is unchanged + assertEq(vat.dai(ali), 200 ether); // ali's dai balance is unchanged assertEq(vat.dai(bob), 190 ether); - assertEq(vat.dai(gal), 10 ether); + assertEq(vat.dai(gal), 10 ether); assertEq(vat.sin(address(this)), 1000 ether); Gal(gal).cage(flop); @@ -265,9 +319,9 @@ contract FlopTest is DSTest { // confirm final state assertEq(vat.dai(ali), 200 ether); - assertEq(vat.dai(bob), 200 ether); // bob's bid has been refunded - assertEq(vat.dai(gal), 10 ether); - assertEq(vat.sin(gal), 10 ether); // sin assigned to caller of cage() + assertEq(vat.dai(bob), 200 ether); // bob's bid has been refunded + assertEq(vat.dai(gal), 10 ether); + assertEq(vat.sin(gal), 10 ether); // sin assigned to caller of cage() (uint256 _bid, uint256 _lot, address _guy, uint48 _tic, uint48 _end) = flop.bids(id); assertEq(_bid, 0); assertEq(_lot, 0); @@ -280,7 +334,14 @@ contract FlopTest is DSTest { // with no bidder to refund, yanking the auction should simply create equal // amounts of dai (credited to the gal) and sin (credited to the caller of cage) // in practice, gal == (caller of cage) == (vow address) - uint id = Gal(gal).kick(flop, /*lot*/ 200 ether, /*bid*/ 10 ether); + uint256 id = Gal(gal) + .kick( + flop, + /*lot*/ + 200 ether, + /*bid*/ + 10 ether + ); // confrim initial state expectations assertEq(vat.dai(ali), 200 ether); @@ -294,8 +355,8 @@ contract FlopTest is DSTest { // confirm final state assertEq(vat.dai(ali), 200 ether); assertEq(vat.dai(bob), 200 ether); - assertEq(vat.dai(gal), 10 ether); - assertEq(vat.sin(gal), 10 ether); // sin assigned to caller of cage() + assertEq(vat.dai(gal), 10 ether); + assertEq(vat.sin(gal), 10 ether); // sin assigned to caller of cage() (uint256 _bid, uint256 _lot, address _guy, uint48 _tic, uint48 _end) = flop.bids(id); assertEq(_bid, 0); assertEq(_lot, 0); diff --git a/src/test/fork.t.sol b/src/test/fork.t.sol index 91f37aae..cddfaaa2 100644 --- a/src/test/fork.t.sol +++ b/src/test/fork.t.sol @@ -20,13 +20,15 @@ pragma solidity ^0.6.12; import "ds-test/test.sol"; import "ds-token/token.sol"; -import {Vat} from '../vat.sol'; +import {Vat} from "../vat.sol"; contract Usr { Vat public vat; + constructor(Vat vat_) public { vat = vat_; } + function try_call(address addr, bytes calldata data) external returns (bool) { bytes memory _data = data; assembly { @@ -37,7 +39,8 @@ contract Usr { revert(free, 32) } } - function can_frob(bytes32 ilk, address u, address v, address w, int dink, int dart) public returns (bool) { + + function can_frob(bytes32 ilk, address u, address v, address w, int256 dink, int256 dart) public returns (bool) { string memory sig = "frob(bytes32,address,address,address,int256,int256)"; bytes memory data = abi.encodeWithSignature(sig, ilk, u, v, w, dink, dart); @@ -47,7 +50,8 @@ contract Usr { ok = abi.decode(success, (bool)); if (ok) return true; } - function can_fork(bytes32 ilk, address src, address dst, int dink, int dart) public returns (bool) { + + function can_fork(bytes32 ilk, address src, address dst, int256 dink, int256 dart) public returns (bool) { string memory sig = "fork(bytes32,address,address,int256,int256)"; bytes memory data = abi.encodeWithSignature(sig, ilk, src, dst, dink, dart); @@ -57,12 +61,15 @@ contract Usr { ok = abi.decode(success, (bool)); if (ok) return true; } - function frob(bytes32 ilk, address u, address v, address w, int dink, int dart) public { + + function frob(bytes32 ilk, address u, address v, address w, int256 dink, int256 dart) public { vat.frob(ilk, u, v, w, dink, dart); } - function fork(bytes32 ilk, address src, address dst, int dink, int dart) public { + + function fork(bytes32 ilk, address src, address dst, int256 dink, int256 dart) public { vat.fork(ilk, src, dst, dink, dart); } + function hope(address usr) public { vat.hope(usr); } @@ -76,10 +83,11 @@ contract ForkTest is DSTest { address a; address b; - function ray(uint wad) internal pure returns (uint) { + function ray(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 9; } - function rad(uint wad) internal pure returns (uint) { + + function rad(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 27; } @@ -91,37 +99,41 @@ contract ForkTest is DSTest { b = address(bob); vat.init("gems"); - vat.file("gems", "spot", ray(0.5 ether)); + vat.file("gems", "spot", ray(0.5 ether)); vat.file("gems", "line", rad(1000 ether)); - vat.file("Line", rad(1000 ether)); + vat.file("Line", rad(1000 ether)); vat.slip("gems", a, 8 ether); } + function test_fork_to_self() public { ali.frob("gems", a, a, a, 8 ether, 4 ether); - assertTrue( ali.can_fork("gems", a, a, 8 ether, 4 ether)); - assertTrue( ali.can_fork("gems", a, a, 4 ether, 2 ether)); + assertTrue(ali.can_fork("gems", a, a, 8 ether, 4 ether)); + assertTrue(ali.can_fork("gems", a, a, 4 ether, 2 ether)); assertTrue(!ali.can_fork("gems", a, a, 9 ether, 4 ether)); } + function test_give_to_other() public { ali.frob("gems", a, a, a, 8 ether, 4 ether); assertTrue(!ali.can_fork("gems", a, b, 8 ether, 4 ether)); bob.hope(address(ali)); - assertTrue( ali.can_fork("gems", a, b, 8 ether, 4 ether)); + assertTrue(ali.can_fork("gems", a, b, 8 ether, 4 ether)); } + function test_fork_to_other() public { ali.frob("gems", a, a, a, 8 ether, 4 ether); bob.hope(address(ali)); - assertTrue( ali.can_fork("gems", a, b, 4 ether, 2 ether)); + assertTrue(ali.can_fork("gems", a, b, 4 ether, 2 ether)); assertTrue(!ali.can_fork("gems", a, b, 4 ether, 3 ether)); assertTrue(!ali.can_fork("gems", a, b, 4 ether, 1 ether)); } + function test_fork_dust() public { ali.frob("gems", a, a, a, 8 ether, 4 ether); bob.hope(address(ali)); - assertTrue( ali.can_fork("gems", a, b, 4 ether, 2 ether)); + assertTrue(ali.can_fork("gems", a, b, 4 ether, 2 ether)); vat.file("gems", "dust", rad(1 ether)); - assertTrue( ali.can_fork("gems", a, b, 2 ether, 1 ether)); + assertTrue(ali.can_fork("gems", a, b, 2 ether, 1 ether)); assertTrue(!ali.can_fork("gems", a, b, 1 ether, 0.5 ether)); } } diff --git a/src/test/jug.t.sol b/src/test/jug.t.sol index f5395d4b..3a118b0d 100644 --- a/src/test/jug.t.sol +++ b/src/test/jug.t.sol @@ -22,52 +22,50 @@ import "ds-test/test.sol"; import {Jug} from "../jug.sol"; import {Vat} from "../vat.sol"; - interface Hevm { function warp(uint256) external; } interface VatLike { - function ilks(bytes32) external view returns ( - uint256 Art, - uint256 rate, - uint256 spot, - uint256 line, - uint256 dust - ); + function ilks(bytes32) external view returns (uint256 Art, uint256 rate, uint256 spot, uint256 line, uint256 dust); } contract Rpow is Jug { - constructor(address vat_) public Jug(vat_){} + constructor(address vat_) public Jug(vat_) {} - function pRpow(uint x, uint n, uint b) public pure returns(uint) { + function pRpow(uint256 x, uint256 n, uint256 b) public pure returns (uint256) { return _rpow(x, n, b); } } - contract JugTest is DSTest { Hevm hevm; Jug jug; - Vat vat; + Vat vat; - function rad(uint wad_) internal pure returns (uint) { + function rad(uint256 wad_) internal pure returns (uint256) { return wad_ * 10 ** 27; } - function wad(uint rad_) internal pure returns (uint) { + + function wad(uint256 rad_) internal pure returns (uint256) { return rad_ / 10 ** 27; } - function rho(bytes32 ilk) internal view returns (uint) { - (uint duty, uint rho_) = jug.ilks(ilk); duty; + + function rho(bytes32 ilk) internal view returns (uint256) { + (uint256 duty, uint256 rho_) = jug.ilks(ilk); + duty; return rho_; } - function Art(bytes32 ilk) internal view returns (uint ArtV) { + + function Art(bytes32 ilk) internal view returns (uint256 ArtV) { (ArtV,,,,) = VatLike(address(vat)).ilks(ilk); } - function rate(bytes32 ilk) internal view returns (uint rateV) { + + function rate(bytes32 ilk) internal view returns (uint256 rateV) { (, rateV,,,) = VatLike(address(vat)).ilks(ilk); } - function line(bytes32 ilk) internal view returns (uint lineV) { + + function line(bytes32 ilk) internal view returns (uint256 lineV) { (,,, lineV,) = VatLike(address(vat)).ilks(ilk); } @@ -77,31 +75,33 @@ contract JugTest is DSTest { hevm = Hevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); hevm.warp(604411200); - vat = new Vat(); + vat = new Vat(); jug = new Jug(address(vat)); vat.rely(address(jug)); vat.init("i"); draw("i", 100 ether); } - function draw(bytes32 ilk, uint dai) internal { + + function draw(bytes32 ilk, uint256 dai) internal { vat.file("Line", vat.Line() + rad(dai)); vat.file(ilk, "line", line(ilk) + rad(dai)); vat.file(ilk, "spot", 10 ** 27 * 10000 ether); address self = address(this); - vat.slip(ilk, self, 10 ** 27 * 1 ether); - vat.frob(ilk, self, self, self, int(1 ether), int(dai)); + vat.slip(ilk, self, 10 ** 27 * 1 ether); + vat.frob(ilk, self, self, self, int256(1 ether), int256(dai)); } function test_drip_setup() public { hevm.warp(0); - assertEq(uint(now), 0); + assertEq(uint256(now), 0); hevm.warp(1); - assertEq(uint(now), 1); + assertEq(uint256(now), 1); hevm.warp(2); - assertEq(uint(now), 2); + assertEq(uint256(now), 2); assertEq(Art("i"), 100 ether); } + function test_drip_updates_rho() public { jug.init("i"); assertEq(rho("i"), now); @@ -117,54 +117,60 @@ contract JugTest is DSTest { jug.drip("i"); assertEq(rho("i"), now); } + function test_drip_file() public { jug.init("i"); jug.file("i", "duty", 10 ** 27); jug.drip("i"); - jug.file("i", "duty", 1000000564701133626865910626); // 5% / day + jug.file("i", "duty", 1000000564701133626865910626); // 5% / day } + function test_drip_0d() public { jug.init("i"); - jug.file("i", "duty", 1000000564701133626865910626); // 5% / day + jug.file("i", "duty", 1000000564701133626865910626); // 5% / day assertEq(vat.dai(ali), rad(0 ether)); jug.drip("i"); assertEq(vat.dai(ali), rad(0 ether)); } + function test_drip_1d() public { jug.init("i"); jug.file("vow", ali); - jug.file("i", "duty", 1000000564701133626865910626); // 5% / day + jug.file("i", "duty", 1000000564701133626865910626); // 5% / day hevm.warp(now + 1 days); assertEq(wad(vat.dai(ali)), 0 ether); jug.drip("i"); assertEq(wad(vat.dai(ali)), 5 ether); } + function test_drip_2d() public { jug.init("i"); jug.file("vow", ali); - jug.file("i", "duty", 1000000564701133626865910626); // 5% / day + jug.file("i", "duty", 1000000564701133626865910626); // 5% / day hevm.warp(now + 2 days); assertEq(wad(vat.dai(ali)), 0 ether); jug.drip("i"); assertEq(wad(vat.dai(ali)), 10.25 ether); } + function test_drip_3d() public { jug.init("i"); jug.file("vow", ali); - jug.file("i", "duty", 1000000564701133626865910626); // 5% / day + jug.file("i", "duty", 1000000564701133626865910626); // 5% / day hevm.warp(now + 3 days); assertEq(wad(vat.dai(ali)), 0 ether); jug.drip("i"); assertEq(wad(vat.dai(ali)), 15.7625 ether); } + function test_drip_negative_3d() public { jug.init("i"); jug.file("vow", ali); - jug.file("i", "duty", 999999706969857929985428567); // -2.5% / day + jug.file("i", "duty", 999999706969857929985428567); // -2.5% / day hevm.warp(now + 3 days); assertEq(wad(vat.dai(address(this))), 100 ether); vat.move(address(this), ali, rad(100 ether)); @@ -177,17 +183,18 @@ contract JugTest is DSTest { jug.init("i"); jug.file("vow", ali); - jug.file("i", "duty", 1000000564701133626865910626); // 5% / day + jug.file("i", "duty", 1000000564701133626865910626); // 5% / day hevm.warp(now + 1 days); jug.drip("i"); assertEq(wad(vat.dai(ali)), 5 ether); - jug.file("i", "duty", 1000001103127689513476993127); // 10% / day + jug.file("i", "duty", 1000001103127689513476993127); // 10% / day hevm.warp(now + 1 days); jug.drip("i"); - assertEq(wad(vat.dai(ali)), 15.5 ether); - assertEq(wad(vat.debt()), 115.5 ether); + assertEq(wad(vat.dai(ali)), 15.5 ether); + assertEq(wad(vat.debt()), 115.5 ether); assertEq(rate("i") / 10 ** 9, 1.155 ether); } + function test_drip_base() public { vat.init("j"); draw("j", 100 ether); @@ -196,29 +203,32 @@ contract JugTest is DSTest { jug.init("j"); jug.file("vow", ali); - jug.file("i", "duty", 1050000000000000000000000000); // 5% / second - jug.file("j", "duty", 1000000000000000000000000000); // 0% / second - jug.file("base", uint(50000000000000000000000000)); // 5% / second + jug.file("i", "duty", 1050000000000000000000000000); // 5% / second + jug.file("j", "duty", 1000000000000000000000000000); // 0% / second + jug.file("base", uint256(50000000000000000000000000)); // 5% / second hevm.warp(now + 1); jug.drip("i"); assertEq(wad(vat.dai(ali)), 10 ether); } + function test_file_duty() public { jug.init("i"); hevm.warp(now + 1); jug.drip("i"); jug.file("i", "duty", 1); } + function testFail_file_duty() public { jug.init("i"); hevm.warp(now + 1); jug.file("i", "duty", 1); } + function test_rpow() public { Rpow r = new Rpow(address(vat)); - uint result = r.pRpow(uint(1000234891009084238901289093), uint(3724), uint(1e27)); + uint256 result = r.pRpow(uint256(1000234891009084238901289093), uint256(3724), uint256(1e27)); // python calc = 2.397991232255757e27 = 2397991232255757e12 // expect 10 decimal precision - assertEq(result / uint(1e17), uint(2397991232255757e12) / 1e17); + assertEq(result / uint256(1e17), uint256(2397991232255757e12) / 1e17); } } diff --git a/src/test/pot.t.sol b/src/test/pot.t.sol index 26dacaa9..229988f0 100644 --- a/src/test/pot.t.sol +++ b/src/test/pot.t.sol @@ -18,8 +18,8 @@ pragma solidity ^0.6.12; import "ds-test/test.sol"; -import {Vat} from '../vat.sol'; -import {Pot} from '../pot.sol'; +import {Vat} from "../vat.sol"; +import {Pot} from "../pot.sol"; interface Hevm { function warp(uint256) external; @@ -35,10 +35,11 @@ contract DSRTest is DSTest { address self; address potb; - function rad(uint wad_) internal pure returns (uint) { + function rad(uint256 wad_) internal pure returns (uint256) { return wad_ * 10 ** 27; } - function wad(uint rad_) internal pure returns (uint) { + + function wad(uint256 rad_) internal pure returns (uint256) { return rad_ / 10 ** 27; } @@ -58,44 +59,48 @@ contract DSRTest is DSTest { vat.suck(self, self, rad(100 ether)); vat.hope(address(pot)); } + function test_save_0d() public { assertEq(vat.dai(self), rad(100 ether)); pot.join(100 ether); - assertEq(wad(vat.dai(self)), 0 ether); - assertEq(pot.pie(self), 100 ether); + assertEq(wad(vat.dai(self)), 0 ether); + assertEq(pot.pie(self), 100 ether); pot.drip(); pot.exit(100 ether); assertEq(wad(vat.dai(self)), 100 ether); } + function test_save_1d() public { pot.join(100 ether); - pot.file("dsr", uint(1000000564701133626865910626)); // 5% / day + pot.file("dsr", uint256(1000000564701133626865910626)); // 5% / day hevm.warp(now + 1 days); pot.drip(); assertEq(pot.pie(self), 100 ether); pot.exit(100 ether); assertEq(wad(vat.dai(self)), 105 ether); } + function test_drip_multi() public { pot.join(100 ether); - pot.file("dsr", uint(1000000564701133626865910626)); // 5% / day + pot.file("dsr", uint256(1000000564701133626865910626)); // 5% / day hevm.warp(now + 1 days); pot.drip(); - assertEq(wad(vat.dai(potb)), 105 ether); - pot.file("dsr", uint(1000001103127689513476993127)); // 10% / day + assertEq(wad(vat.dai(potb)), 105 ether); + pot.file("dsr", uint256(1000001103127689513476993127)); // 10% / day hevm.warp(now + 1 days); pot.drip(); assertEq(wad(vat.sin(vow)), 15.5 ether); assertEq(wad(vat.dai(potb)), 115.5 ether); - assertEq(pot.Pie(), 100 ether); + assertEq(pot.Pie(), 100 ether); assertEq(pot.chi() / 10 ** 9, 1.155 ether); } + function test_drip_multi_inBlock() public { pot.drip(); - uint rho = pot.rho(); + uint256 rho = pot.rho(); assertEq(rho, now); hevm.warp(now + 1 days); rho = pot.rho(); @@ -107,24 +112,26 @@ contract DSRTest is DSTest { rho = pot.rho(); assertEq(rho, now); } + function test_save_multi() public { pot.join(100 ether); - pot.file("dsr", uint(1000000564701133626865910626)); // 5% / day + pot.file("dsr", uint256(1000000564701133626865910626)); // 5% / day hevm.warp(now + 1 days); pot.drip(); pot.exit(50 ether); assertEq(wad(vat.dai(self)), 52.5 ether); - assertEq(pot.Pie(), 50.0 ether); + assertEq(pot.Pie(), 50.0 ether); - pot.file("dsr", uint(1000001103127689513476993127)); // 10% / day + pot.file("dsr", uint256(1000001103127689513476993127)); // 10% / day hevm.warp(now + 1 days); pot.drip(); pot.exit(50 ether); assertEq(wad(vat.dai(self)), 110.25 ether); - assertEq(pot.Pie(), 0.00 ether); + assertEq(pot.Pie(), 0.0 ether); } + function test_fresh_chi() public { - uint rho = pot.rho(); + uint256 rho = pot.rho(); assertEq(rho, now); hevm.warp(now + 1 days); assertEq(rho, now - 1 days); @@ -135,19 +142,22 @@ contract DSRTest is DSTest { // if we exit in the same transaction we should not earn DSR assertEq(wad(vat.dai(self)), 100 ether); } + function testFail_stale_chi() public { - pot.file("dsr", uint(1000000564701133626865910626)); // 5% / day + pot.file("dsr", uint256(1000000564701133626865910626)); // 5% / day pot.drip(); hevm.warp(now + 1 days); pot.join(100 ether); } + function test_file() public { hevm.warp(now + 1); pot.drip(); - pot.file("dsr", uint(1)); + pot.file("dsr", uint256(1)); } + function testFail_file() public { hevm.warp(now + 1); - pot.file("dsr", uint(1)); + pot.file("dsr", uint256(1)); } } diff --git a/src/test/vat.t.sol b/src/test/vat.t.sol index d59356fa..878a04ea 100644 --- a/src/test/vat.t.sol +++ b/src/test/vat.t.sol @@ -20,52 +20,56 @@ pragma solidity ^0.6.12; import "ds-test/test.sol"; import "ds-token/token.sol"; -import {Vat} from '../vat.sol'; -import {Cat} from '../cat.sol'; -import {Vow} from '../vow.sol'; -import {Jug} from '../jug.sol'; -import {GemJoin, DaiJoin} from '../join.sol'; - -import {Flipper} from './flip.t.sol'; -import {Flopper} from './flop.t.sol'; -import {Flapper} from './flap.t.sol'; +import {Vat} from "../vat.sol"; +import {Cat} from "../cat.sol"; +import {Vow} from "../vow.sol"; +import {Jug} from "../jug.sol"; +import {GemJoin, DaiJoin} from "../join.sol"; +import {Flipper} from "./flip.t.sol"; +import {Flopper} from "./flop.t.sol"; +import {Flapper} from "./flap.t.sol"; interface Hevm { function warp(uint256) external; - function store(address,bytes32,bytes32) external; + function store(address, bytes32, bytes32) external; } contract TestVat is Vat { uint256 constant ONE = 10 ** 27; - function mint(address usr, uint wad) public { + + function mint(address usr, uint256 wad) public { dai[usr] += wad * ONE; debt += wad * ONE; } } contract TestVow is Vow { - constructor(address vat, address flapper, address flopper) - public Vow(vat, flapper, flopper) {} + constructor(address vat, address flapper, address flopper) public Vow(vat, flapper, flopper) {} + // Total deficit - function Awe() public view returns (uint) { + function Awe() public view returns (uint256) { return vat.sin(address(this)); } + // Total surplus - function Joy() public view returns (uint) { + function Joy() public view returns (uint256) { return vat.dai(address(this)); } + // Unqueued, pre-auction debt - function Woe() public view returns (uint) { + function Woe() public view returns (uint256) { return sub(sub(Awe(), Sin), Ash); } } contract Usr { Vat public vat; + constructor(Vat vat_) public { vat = vat_; } + function try_call(address addr, bytes calldata data) external returns (bool) { bytes memory _data = data; assembly { @@ -76,7 +80,8 @@ contract Usr { revert(free, 32) } } - function can_frob(bytes32 ilk, address u, address v, address w, int dink, int dart) public returns (bool) { + + function can_frob(bytes32 ilk, address u, address v, address w, int256 dink, int256 dart) public returns (bool) { string memory sig = "frob(bytes32,address,address,address,int256,int256)"; bytes memory data = abi.encodeWithSignature(sig, ilk, u, v, w, dink, dart); @@ -86,7 +91,8 @@ contract Usr { ok = abi.decode(success, (bool)); if (ok) return true; } - function can_fork(bytes32 ilk, address src, address dst, int dink, int dart) public returns (bool) { + + function can_fork(bytes32 ilk, address src, address dst, int256 dink, int256 dart) public returns (bool) { string memory sig = "fork(bytes32,address,address,int256,int256)"; bytes memory data = abi.encodeWithSignature(sig, ilk, src, dst, dink, dart); @@ -96,33 +102,35 @@ contract Usr { ok = abi.decode(success, (bool)); if (ok) return true; } - function frob(bytes32 ilk, address u, address v, address w, int dink, int dart) public { + + function frob(bytes32 ilk, address u, address v, address w, int256 dink, int256 dart) public { vat.frob(ilk, u, v, w, dink, dart); } - function fork(bytes32 ilk, address src, address dst, int dink, int dart) public { + + function fork(bytes32 ilk, address src, address dst, int256 dink, int256 dart) public { vat.fork(ilk, src, dst, dink, dart); } + function hope(address usr) public { vat.hope(usr); } } - contract FrobTest is DSTest { TestVat vat; DSToken gold; - Jug jug; + Jug jug; GemJoin gemA; address me; - function try_frob(bytes32 ilk, int ink, int art) public returns (bool ok) { + function try_frob(bytes32 ilk, int256 ink, int256 art) public returns (bool ok) { string memory sig = "frob(bytes32,address,address,address,int256,int256)"; address self = address(this); (ok,) = address(vat).call(abi.encodeWithSignature(sig, ilk, self, self, self, ink, art)); } - function ray(uint wad) internal pure returns (uint) { + function ray(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 9; } @@ -135,9 +143,9 @@ contract FrobTest is DSTest { vat.init("gold"); gemA = new GemJoin(address(vat), "gold", address(gold)); - vat.file("gold", "spot", ray(1 ether)); + vat.file("gold", "spot", ray(1 ether)); vat.file("gold", "line", rad(1000 ether)); - vat.file("Line", rad(1000 ether)); + vat.file("Line", rad(1000 ether)); jug = new Jug(address(vat)); jug.init("gold"); vat.rely(address(jug)); @@ -153,99 +161,110 @@ contract FrobTest is DSTest { me = address(this); } - function gem(bytes32 ilk, address urn) internal view returns (uint) { + function gem(bytes32 ilk, address urn) internal view returns (uint256) { return vat.gem(ilk, urn); } - function ink(bytes32 ilk, address urn) internal view returns (uint) { - (uint ink_, uint art_) = vat.urns(ilk, urn); art_; + + function ink(bytes32 ilk, address urn) internal view returns (uint256) { + (uint256 ink_, uint256 art_) = vat.urns(ilk, urn); + art_; return ink_; } - function art(bytes32 ilk, address urn) internal view returns (uint) { - (uint ink_, uint art_) = vat.urns(ilk, urn); ink_; + + function art(bytes32 ilk, address urn) internal view returns (uint256) { + (uint256 ink_, uint256 art_) = vat.urns(ilk, urn); + ink_; return art_; } function test_setup() public { assertEq(gold.balanceOf(address(gemA)), 1000 ether); - assertEq(gem("gold", address(this)), 1000 ether); + assertEq(gem("gold", address(this)), 1000 ether); } + function test_join() public { address urn = address(this); gold.mint(500 ether); - assertEq(gold.balanceOf(address(this)), 500 ether); - assertEq(gold.balanceOf(address(gemA)), 1000 ether); - gemA.join(urn, 500 ether); - assertEq(gold.balanceOf(address(this)), 0 ether); - assertEq(gold.balanceOf(address(gemA)), 1500 ether); - gemA.exit(urn, 250 ether); - assertEq(gold.balanceOf(address(this)), 250 ether); - assertEq(gold.balanceOf(address(gemA)), 1250 ether); + assertEq(gold.balanceOf(address(this)), 500 ether); + assertEq(gold.balanceOf(address(gemA)), 1000 ether); + gemA.join(urn, 500 ether); + assertEq(gold.balanceOf(address(this)), 0 ether); + assertEq(gold.balanceOf(address(gemA)), 1500 ether); + gemA.exit(urn, 250 ether); + assertEq(gold.balanceOf(address(this)), 250 ether); + assertEq(gold.balanceOf(address(gemA)), 1250 ether); } + function test_lock() public { - assertEq(ink("gold", address(this)), 0 ether); + assertEq(ink("gold", address(this)), 0 ether); assertEq(gem("gold", address(this)), 1000 ether); vat.frob("gold", me, me, me, 6 ether, 0); - assertEq(ink("gold", address(this)), 6 ether); + assertEq(ink("gold", address(this)), 6 ether); assertEq(gem("gold", address(this)), 994 ether); vat.frob("gold", me, me, me, -6 ether, 0); - assertEq(ink("gold", address(this)), 0 ether); + assertEq(ink("gold", address(this)), 0 ether); assertEq(gem("gold", address(this)), 1000 ether); } + function test_calm() public { // calm means that the debt ceiling is not exceeded // it's ok to increase debt as long as you remain calm - vat.file("gold", 'line', rad(10 ether)); - assertTrue( try_frob("gold", 10 ether, 9 ether)); + vat.file("gold", "line", rad(10 ether)); + assertTrue(try_frob("gold", 10 ether, 9 ether)); // only if under debt ceiling - assertTrue(!try_frob("gold", 0 ether, 2 ether)); + assertTrue(!try_frob("gold", 0 ether, 2 ether)); } + function test_cool() public { // cool means that the debt has decreased // it's ok to be over the debt ceiling as long as you're cool - vat.file("gold", 'line', rad(10 ether)); - assertTrue(try_frob("gold", 10 ether, 8 ether)); - vat.file("gold", 'line', rad(5 ether)); + vat.file("gold", "line", rad(10 ether)); + assertTrue(try_frob("gold", 10 ether, 8 ether)); + vat.file("gold", "line", rad(5 ether)); // can decrease debt when over ceiling - assertTrue(try_frob("gold", 0 ether, -1 ether)); + assertTrue(try_frob("gold", 0 ether, -1 ether)); } + function test_safe() public { // safe means that the cdp is not risky // you can't frob a cdp into unsafe - vat.frob("gold", me, me, me, 10 ether, 5 ether); // safe draw - assertTrue(!try_frob("gold", 0 ether, 6 ether)); // unsafe draw + vat.frob("gold", me, me, me, 10 ether, 5 ether); // safe draw + assertTrue(!try_frob("gold", 0 ether, 6 ether)); // unsafe draw } + function test_nice() public { // nice means that the collateral has increased or the debt has // decreased. remaining unsafe is ok as long as you're nice vat.frob("gold", me, me, me, 10 ether, 10 ether); - vat.file("gold", 'spot', ray(0.5 ether)); // now unsafe + vat.file("gold", "spot", ray(0.5 ether)); // now unsafe // debt can't increase if unsafe - assertTrue(!try_frob("gold", 0 ether, 1 ether)); + assertTrue(!try_frob("gold", 0 ether, 1 ether)); // debt can decrease - assertTrue( try_frob("gold", 0 ether, -1 ether)); + assertTrue(try_frob("gold", 0 ether, -1 ether)); // ink can't decrease - assertTrue(!try_frob("gold", -1 ether, 0 ether)); + assertTrue(!try_frob("gold", -1 ether, 0 ether)); // ink can increase - assertTrue( try_frob("gold", 1 ether, 0 ether)); + assertTrue(try_frob("gold", 1 ether, 0 ether)); // cdp is still unsafe // ink can't decrease, even if debt decreases more assertTrue(!this.try_frob("gold", -2 ether, -4 ether)); // debt can't increase, even if ink increases more - assertTrue(!this.try_frob("gold", 5 ether, 1 ether)); + assertTrue(!this.try_frob("gold", 5 ether, 1 ether)); // ink can decrease if end state is safe - assertTrue( this.try_frob("gold", -1 ether, -4 ether)); - vat.file("gold", 'spot', ray(0.4 ether)); // now unsafe + assertTrue(this.try_frob("gold", -1 ether, -4 ether)); + vat.file("gold", "spot", ray(0.4 ether)); // now unsafe // debt can increase if end state is safe - assertTrue( this.try_frob("gold", 5 ether, 1 ether)); + assertTrue(this.try_frob("gold", 5 ether, 1 ether)); } - function rad(uint wad) internal pure returns (uint) { + function rad(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 27; } + function test_alt_callers() public { Usr ali = new Usr(vat); Usr bob = new Usr(vat); @@ -255,48 +274,48 @@ contract FrobTest is DSTest { address b = address(bob); address c = address(che); - vat.slip("gold", a, int(rad(20 ether))); - vat.slip("gold", b, int(rad(20 ether))); - vat.slip("gold", c, int(rad(20 ether))); + vat.slip("gold", a, int256(rad(20 ether))); + vat.slip("gold", b, int256(rad(20 ether))); + vat.slip("gold", c, int256(rad(20 ether))); ali.frob("gold", a, a, a, 10 ether, 5 ether); // anyone can lock - assertTrue( ali.can_frob("gold", a, a, a, 1 ether, 0 ether)); - assertTrue( bob.can_frob("gold", a, b, b, 1 ether, 0 ether)); - assertTrue( che.can_frob("gold", a, c, c, 1 ether, 0 ether)); + assertTrue(ali.can_frob("gold", a, a, a, 1 ether, 0 ether)); + assertTrue(bob.can_frob("gold", a, b, b, 1 ether, 0 ether)); + assertTrue(che.can_frob("gold", a, c, c, 1 ether, 0 ether)); // but only with their own gems - assertTrue(!ali.can_frob("gold", a, b, a, 1 ether, 0 ether)); - assertTrue(!bob.can_frob("gold", a, c, b, 1 ether, 0 ether)); - assertTrue(!che.can_frob("gold", a, a, c, 1 ether, 0 ether)); + assertTrue(!ali.can_frob("gold", a, b, a, 1 ether, 0 ether)); + assertTrue(!bob.can_frob("gold", a, c, b, 1 ether, 0 ether)); + assertTrue(!che.can_frob("gold", a, a, c, 1 ether, 0 ether)); // only the lad can free - assertTrue( ali.can_frob("gold", a, a, a, -1 ether, 0 ether)); - assertTrue(!bob.can_frob("gold", a, b, b, -1 ether, 0 ether)); - assertTrue(!che.can_frob("gold", a, c, c, -1 ether, 0 ether)); + assertTrue(ali.can_frob("gold", a, a, a, -1 ether, 0 ether)); + assertTrue(!bob.can_frob("gold", a, b, b, -1 ether, 0 ether)); + assertTrue(!che.can_frob("gold", a, c, c, -1 ether, 0 ether)); // the lad can free to anywhere - assertTrue( ali.can_frob("gold", a, b, a, -1 ether, 0 ether)); - assertTrue( ali.can_frob("gold", a, c, a, -1 ether, 0 ether)); + assertTrue(ali.can_frob("gold", a, b, a, -1 ether, 0 ether)); + assertTrue(ali.can_frob("gold", a, c, a, -1 ether, 0 ether)); // only the lad can draw - assertTrue( ali.can_frob("gold", a, a, a, 0 ether, 1 ether)); - assertTrue(!bob.can_frob("gold", a, b, b, 0 ether, 1 ether)); - assertTrue(!che.can_frob("gold", a, c, c, 0 ether, 1 ether)); + assertTrue(ali.can_frob("gold", a, a, a, 0 ether, 1 ether)); + assertTrue(!bob.can_frob("gold", a, b, b, 0 ether, 1 ether)); + assertTrue(!che.can_frob("gold", a, c, c, 0 ether, 1 ether)); // the lad can draw to anywhere - assertTrue( ali.can_frob("gold", a, a, b, 0 ether, 1 ether)); - assertTrue( ali.can_frob("gold", a, a, c, 0 ether, 1 ether)); + assertTrue(ali.can_frob("gold", a, a, b, 0 ether, 1 ether)); + assertTrue(ali.can_frob("gold", a, a, c, 0 ether, 1 ether)); vat.mint(address(bob), 1 ether); vat.mint(address(che), 1 ether); // anyone can wipe - assertTrue( ali.can_frob("gold", a, a, a, 0 ether, -1 ether)); - assertTrue( bob.can_frob("gold", a, b, b, 0 ether, -1 ether)); - assertTrue( che.can_frob("gold", a, c, c, 0 ether, -1 ether)); + assertTrue(ali.can_frob("gold", a, a, a, 0 ether, -1 ether)); + assertTrue(bob.can_frob("gold", a, b, b, 0 ether, -1 ether)); + assertTrue(che.can_frob("gold", a, c, c, 0 ether, -1 ether)); // but only with their own dai - assertTrue(!ali.can_frob("gold", a, a, b, 0 ether, -1 ether)); - assertTrue(!bob.can_frob("gold", a, b, c, 0 ether, -1 ether)); - assertTrue(!che.can_frob("gold", a, c, a, 0 ether, -1 ether)); + assertTrue(!ali.can_frob("gold", a, a, b, 0 ether, -1 ether)); + assertTrue(!bob.can_frob("gold", a, b, c, 0 ether, -1 ether)); + assertTrue(!che.can_frob("gold", a, c, a, 0 ether, -1 ether)); } function test_hope() public { @@ -308,32 +327,32 @@ contract FrobTest is DSTest { address b = address(bob); address c = address(che); - vat.slip("gold", a, int(rad(20 ether))); - vat.slip("gold", b, int(rad(20 ether))); - vat.slip("gold", c, int(rad(20 ether))); + vat.slip("gold", a, int256(rad(20 ether))); + vat.slip("gold", b, int256(rad(20 ether))); + vat.slip("gold", c, int256(rad(20 ether))); ali.frob("gold", a, a, a, 10 ether, 5 ether); // only owner can do risky actions - assertTrue( ali.can_frob("gold", a, a, a, 0 ether, 1 ether)); - assertTrue(!bob.can_frob("gold", a, b, b, 0 ether, 1 ether)); - assertTrue(!che.can_frob("gold", a, c, c, 0 ether, 1 ether)); + assertTrue(ali.can_frob("gold", a, a, a, 0 ether, 1 ether)); + assertTrue(!bob.can_frob("gold", a, b, b, 0 ether, 1 ether)); + assertTrue(!che.can_frob("gold", a, c, c, 0 ether, 1 ether)); ali.hope(address(bob)); // unless they hope another user - assertTrue( ali.can_frob("gold", a, a, a, 0 ether, 1 ether)); - assertTrue( bob.can_frob("gold", a, b, b, 0 ether, 1 ether)); - assertTrue(!che.can_frob("gold", a, c, c, 0 ether, 1 ether)); + assertTrue(ali.can_frob("gold", a, a, a, 0 ether, 1 ether)); + assertTrue(bob.can_frob("gold", a, b, b, 0 ether, 1 ether)); + assertTrue(!che.can_frob("gold", a, c, c, 0 ether, 1 ether)); } function test_dust() public { - assertTrue( try_frob("gold", 9 ether, 1 ether)); + assertTrue(try_frob("gold", 9 ether, 1 ether)); vat.file("gold", "dust", rad(5 ether)); - assertTrue(!try_frob("gold", 5 ether, 2 ether)); - assertTrue( try_frob("gold", 0 ether, 5 ether)); + assertTrue(!try_frob("gold", 5 ether, 2 ether)); + assertTrue(try_frob("gold", 0 ether, 5 ether)); assertTrue(!try_frob("gold", 0 ether, -5 ether)); - assertTrue( try_frob("gold", 0 ether, -6 ether)); + assertTrue(try_frob("gold", 0 ether, -6 ether)); } } @@ -349,63 +368,71 @@ contract JoinTest is DSTest { vat = new TestVat(); vat.init("eth"); - gem = new DSToken("Gem"); + gem = new DSToken("Gem"); gemA = new GemJoin(address(vat), "gem", address(gem)); vat.rely(address(gemA)); - dai = new DSToken("Dai"); + dai = new DSToken("Dai"); daiA = new DaiJoin(address(vat), address(dai)); vat.rely(address(daiA)); dai.setOwner(address(daiA)); me = address(this); } + function try_cage(address a) public payable returns (bool ok) { string memory sig = "cage()"; (ok,) = a.call(abi.encodeWithSignature(sig)); } - function try_join_gem(address usr, uint wad) public returns (bool ok) { + + function try_join_gem(address usr, uint256 wad) public returns (bool ok) { string memory sig = "join(address,uint256)"; (ok,) = address(gemA).call(abi.encodeWithSignature(sig, usr, wad)); } - function try_exit_dai(address usr, uint wad) public returns (bool ok) { + + function try_exit_dai(address usr, uint256 wad) public returns (bool ok) { string memory sig = "exit(address,uint256)"; (ok,) = address(daiA).call(abi.encodeWithSignature(sig, usr, wad)); } + function test_gem_join() public { gem.mint(20 ether); gem.approve(address(gemA), 20 ether); - assertTrue( try_join_gem(address(this), 10 ether)); + assertTrue(try_join_gem(address(this), 10 ether)); assertEq(vat.gem("gem", me), 10 ether); - assertTrue( try_cage(address(gemA))); + assertTrue(try_cage(address(gemA))); assertTrue(!try_join_gem(address(this), 10 ether)); assertEq(vat.gem("gem", me), 10 ether); } - function rad(uint wad) internal pure returns (uint) { + + function rad(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 27; } + function test_dai_exit() public { address urn = address(this); vat.mint(address(this), 100 ether); vat.hope(address(daiA)); - assertTrue( try_exit_dai(urn, 40 ether)); + assertTrue(try_exit_dai(urn, 40 ether)); assertEq(dai.balanceOf(address(this)), 40 ether); - assertEq(vat.dai(me), rad(60 ether)); - assertTrue( try_cage(address(daiA))); + assertEq(vat.dai(me), rad(60 ether)); + assertTrue(try_cage(address(daiA))); assertTrue(!try_exit_dai(urn, 40 ether)); assertEq(dai.balanceOf(address(this)), 40 ether); - assertEq(vat.dai(me), rad(60 ether)); + assertEq(vat.dai(me), rad(60 ether)); } + function test_dai_exit_join() public { address urn = address(this); vat.mint(address(this), 100 ether); vat.hope(address(daiA)); daiA.exit(urn, 60 ether); - dai.approve(address(daiA), uint(-1)); + dai.approve(address(daiA), uint256(-1)); daiA.join(urn, 30 ether); - assertEq(dai.balanceOf(address(this)), 30 ether); - assertEq(vat.dai(me), rad(70 ether)); + assertEq(dai.balanceOf(address(this)), 30 ether); + assertEq(vat.dai(me), rad(70 ether)); } + function test_cage_no_access() public { gemA.deny(address(this)); assertTrue(!try_cage(address(gemA))); @@ -418,23 +445,17 @@ interface FlipLike { struct Bid { uint256 bid; uint256 lot; - address guy; // high bidder - uint48 tic; // expiry time - uint48 end; + address guy; // high bidder + uint48 tic; // expiry time + uint48 end; address urn; address gal; uint256 tab; } - function bids(uint) external view returns ( - uint256 bid, - uint256 lot, - address guy, - uint48 tic, - uint48 end, - address usr, - address gal, - uint256 tab - ); + function bids(uint256) + external + view + returns (uint256 bid, uint256 lot, address guy, uint48 tic, uint48 end, address usr, address gal, uint256 tab); } contract BiteTest is DSTest { @@ -442,9 +463,9 @@ contract BiteTest is DSTest { TestVat vat; TestVow vow; - Cat cat; + Cat cat; DSToken gold; - Jug jug; + Jug jug; GemJoin gemA; @@ -461,28 +482,33 @@ contract BiteTest is DSTest { uint256 constant RAY = 10 ** 27; uint256 constant RAD = 10 ** 45; - function try_frob(bytes32 ilk, int ink, int art) public returns (bool ok) { + function try_frob(bytes32 ilk, int256 ink, int256 art) public returns (bool ok) { string memory sig = "frob(bytes32,address,address,address,int256,int256)"; address self = address(this); (ok,) = address(vat).call(abi.encodeWithSignature(sig, ilk, self, self, self, ink, art)); } - function ray(uint wad) internal pure returns (uint) { + function ray(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 9; } - function rad(uint wad) internal pure returns (uint) { + + function rad(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 27; } - function gem(bytes32 ilk, address urn) internal view returns (uint) { + function gem(bytes32 ilk, address urn) internal view returns (uint256) { return vat.gem(ilk, urn); } - function ink(bytes32 ilk, address urn) internal view returns (uint) { - (uint ink_, uint art_) = vat.urns(ilk, urn); art_; + + function ink(bytes32 ilk, address urn) internal view returns (uint256) { + (uint256 ink_, uint256 art_) = vat.urns(ilk, urn); + art_; return ink_; } - function art(bytes32 ilk, address urn) internal view returns (uint) { - (uint ink_, uint art_) = vat.urns(ilk, urn); ink_; + + function art(bytes32 ilk, address urn) internal view returns (uint256) { + (uint256 ink_, uint256 art_) = vat.urns(ilk, urn); + ink_; return art_; } @@ -490,7 +516,7 @@ contract BiteTest is DSTest { hevm = Hevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); hevm.warp(604411200); - gov = new DSToken('GOV'); + gov = new DSToken("GOV"); gov.mint(100 ether); vat = new TestVat(); @@ -526,7 +552,7 @@ contract BiteTest is DSTest { vat.file("gold", "spot", ray(1 ether)); vat.file("gold", "line", rad(1000 ether)); - vat.file("Line", rad(1000 ether)); + vat.file("Line", rad(1000 ether)); flip = new Flipper(address(vat), address(cat), "gold"); flip.rely(address(cat)); cat.rely(address(flip)); @@ -546,111 +572,114 @@ contract BiteTest is DSTest { } function test_set_dunk_multiple_ilks() public { - cat.file("gold", "dunk", rad(111111 ether)); + cat.file("gold", "dunk", rad(111111 ether)); (,, uint256 goldDunk) = cat.ilks("gold"); assertEq(goldDunk, rad(111111 ether)); cat.file("silver", "dunk", rad(222222 ether)); (,, uint256 silverDunk) = cat.ilks("silver"); assertEq(silverDunk, rad(222222 ether)); } + function test_cat_set_box() public { assertEq(cat.box(), rad((10 ether) * MLN)); cat.file("box", rad((20 ether) * MLN)); assertEq(cat.box(), rad((20 ether) * MLN)); } + function test_bite_under_dunk() public { - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 40 ether, 100 ether); // tag=4, mat=2 - vat.file("gold", 'spot', ray(2 ether)); // now unsafe + vat.file("gold", "spot", ray(2 ether)); // now unsafe cat.file("gold", "dunk", rad(111 ether)); cat.file("gold", "chop", 1.1 ether); - uint auction = cat.bite("gold", address(this)); + uint256 auction = cat.bite("gold", address(this)); // the full CDP is liquidated assertEq(ink("gold", address(this)), 0); assertEq(art("gold", address(this)), 0); // all debt goes to the vow assertEq(vow.Awe(), rad(100 ether)); // auction is for all collateral - (, uint lot,,,,,, uint tab) = flip.bids(auction); - assertEq(lot, 40 ether); - assertEq(tab, rad(110 ether)); + (, uint256 lot,,,,,, uint256 tab) = flip.bids(auction); + assertEq(lot, 40 ether); + assertEq(tab, rad(110 ether)); } + function test_bite_over_dunk() public { - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 40 ether, 100 ether); // tag=4, mat=2 - vat.file("gold", 'spot', ray(2 ether)); // now unsafe + vat.file("gold", "spot", ray(2 ether)); // now unsafe cat.file("gold", "chop", 1.1 ether); cat.file("gold", "dunk", rad(82.5 ether)); - uint auction = cat.bite("gold", address(this)); + uint256 auction = cat.bite("gold", address(this)); // the CDP is partially liquidated assertEq(ink("gold", address(this)), 10 ether); assertEq(art("gold", address(this)), 25 ether); // a fraction of the debt goes to the vow assertEq(vow.Awe(), rad(75 ether)); // auction is for a fraction of the collateral - (, uint lot,,,,,, uint tab) = FlipLike(address(flip)).bids(auction); - assertEq(lot, 30 ether); - assertEq(tab, rad(82.5 ether)); + (, uint256 lot,,,,,, uint256 tab) = FlipLike(address(flip)).bids(auction); + assertEq(lot, 30 ether); + assertEq(tab, rad(82.5 ether)); } function test_happy_bite() public { // spot = tag / (par . mat) // tag=5, mat=2 - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 40 ether, 100 ether); // tag=4, mat=2 - vat.file("gold", 'spot', ray(2 ether)); // now unsafe + vat.file("gold", "spot", ray(2 ether)); // now unsafe cat.file("gold", "chop", 1.1 ether); - assertEq(ink("gold", address(this)), 40 ether); + assertEq(ink("gold", address(this)), 40 ether); assertEq(art("gold", address(this)), 100 ether); assertEq(vow.Woe(), 0 ether); assertEq(gem("gold", address(this)), 960 ether); - cat.file("gold", "dunk", rad(200 ether)); // => bite everything + cat.file("gold", "dunk", rad(200 ether)); // => bite everything assertEq(cat.litter(), 0); - uint auction = cat.bite("gold", address(this)); + uint256 auction = cat.bite("gold", address(this)); assertEq(cat.litter(), rad(110 ether)); assertEq(ink("gold", address(this)), 0); assertEq(art("gold", address(this)), 0); - assertEq(vow.sin(now), rad(100 ether)); + assertEq(vow.sin(now), rad(100 ether)); assertEq(gem("gold", address(this)), 960 ether); assertEq(vat.dai(address(vow)), rad(0 ether)); - vat.mint(address(this), 100 ether); // magic up some dai for bidding - flip.tend(auction, 40 ether, rad(1 ether)); + vat.mint(address(this), 100 ether); // magic up some dai for bidding + flip.tend(auction, 40 ether, rad(1 ether)); flip.tend(auction, 40 ether, rad(110 ether)); - assertEq(vat.dai(address(this)), rad(90 ether)); + assertEq(vat.dai(address(this)), rad(90 ether)); assertEq(gem("gold", address(this)), 960 ether); - flip.dent(auction, 38 ether, rad(110 ether)); - assertEq(vat.dai(address(this)), rad(90 ether)); + flip.dent(auction, 38 ether, rad(110 ether)); + assertEq(vat.dai(address(this)), rad(90 ether)); assertEq(gem("gold", address(this)), 962 ether); - assertEq(vow.sin(now), rad(100 ether)); + assertEq(vow.sin(now), rad(100 ether)); hevm.warp(now + 4 hours); assertEq(cat.litter(), rad(110 ether)); flip.deal(auction); assertEq(cat.litter(), 0); - assertEq(vat.dai(address(vow)), rad(110 ether)); + assertEq(vat.dai(address(vow)), rad(110 ether)); } // tests a partial lot liquidation because it would fill the literbox function test_partial_litterbox() public { // spot = tag / (par . mat) // tag=5, mat=2 - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 100 ether, 150 ether); // tag=4, mat=2 - vat.file("gold", 'spot', ray(1 ether)); // now unsafe + vat.file("gold", "spot", ray(1 ether)); // now unsafe assertEq(ink("gold", address(this)), 100 ether); assertEq(art("gold", address(this)), 150 ether); @@ -661,22 +690,22 @@ contract BiteTest is DSTest { cat.file("gold", "dunk", rad(100 ether)); assertEq(cat.box(), rad(75 ether)); assertEq(cat.litter(), 0); - uint auction = cat.bite("gold", address(this)); + uint256 auction = cat.bite("gold", address(this)); assertEq(ink("gold", address(this)), 50 ether); assertEq(art("gold", address(this)), 75 ether); assertEq(vow.sin(now), rad(75 ether)); assertEq(gem("gold", address(this)), 900 ether); - assertEq(vat.dai(address(this)), rad(150 ether)); - assertEq(vat.dai(address(vow)), rad(0 ether)); + assertEq(vat.dai(address(this)), rad(150 ether)); + assertEq(vat.dai(address(vow)), rad(0 ether)); flip.tend(auction, 50 ether, rad(1 ether)); assertEq(cat.litter(), rad(75 ether)); assertEq(vat.dai(address(this)), rad(149 ether)); flip.tend(auction, 50 ether, rad(75 ether)); assertEq(vat.dai(address(this)), rad(75 ether)); - assertEq(gem("gold", address(this)), 900 ether); + assertEq(gem("gold", address(this)), 900 ether); flip.dent(auction, 25 ether, rad(75 ether)); assertEq(cat.litter(), rad(75 ether)); assertEq(vat.dai(address(this)), rad(75 ether)); @@ -686,20 +715,20 @@ contract BiteTest is DSTest { hevm.warp(now + 4 hours); flip.deal(auction); assertEq(cat.litter(), 0); - assertEq(gem("gold", address(this)), 950 ether); - assertEq(vat.dai(address(this)), rad(75 ether)); - assertEq(vat.dai(address(vow)), rad(75 ether)); + assertEq(gem("gold", address(this)), 950 ether); + assertEq(vat.dai(address(this)), rad(75 ether)); + assertEq(vat.dai(address(vow)), rad(75 ether)); } // tests a partial lot liquidation because it would fill the literbox function test_partial_litterbox_realistic_values() public { // spot = tag / (par . mat) // tag=5, mat=2 - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 100 ether, 150 ether); // tag=4, mat=2 - vat.file("gold", 'spot', ray(1 ether)); // now unsafe + vat.file("gold", "spot", ray(1 ether)); // now unsafe cat.file("gold", "chop", 1.13 ether); assertEq(ink("gold", address(this)), 100 ether); @@ -714,37 +743,37 @@ contract BiteTest is DSTest { jug.file("gold", "duty", EIGHT_PCT); hevm.warp(now + 10 days); jug.drip("gold"); - (, uint rate,,,) = vat.ilks("gold"); + (, uint256 rate,,,) = vat.ilks("gold"); - uint vowBalance = vat.dai(address(vow)); // Balance updates after vat.fold is called from jug + uint256 vowBalance = vat.dai(address(vow)); // Balance updates after vat.fold is called from jug cat.file("box", rad(75 ether)); cat.file("gold", "dunk", rad(100 ether)); assertEq(cat.box(), rad(75 ether)); assertEq(cat.litter(), 0); - uint auction = cat.bite("gold", address(this)); - (,,,,,,,uint tab) = flip.bids(auction); + uint256 auction = cat.bite("gold", address(this)); + (,,,,,,, uint256 tab) = flip.bids(auction); assertTrue(cat.box() - cat.litter() < ray(1 ether)); // Rounding error to fill box - assertEq(cat.litter(), tab); // tab = 74.9999... RAD + assertEq(cat.litter(), tab); // tab = 74.9999... RAD uint256 dart = rad(75 ether) * WAD / rate / 1.13 ether; // room / rate / chop uint256 dink = 100 ether * dart / 150 ether; assertEq(ink("gold", address(this)), 100 ether - dink); // Taken in vat.grab assertEq(art("gold", address(this)), 150 ether - dart); // Taken in vat.grab - assertEq(vow.sin(now), dart * rate); + assertEq(vow.sin(now), dart * rate); assertEq(gem("gold", address(this)), 900 ether); assertEq(vat.dai(address(this)), rad(150 ether)); - assertEq(vat.dai(address(vow)), vowBalance); - flip.tend(auction, dink, rad( 1 ether)); + assertEq(vat.dai(address(vow)), vowBalance); + flip.tend(auction, dink, rad(1 ether)); assertEq(cat.litter(), tab); assertEq(vat.dai(address(this)), rad(149 ether)); flip.tend(auction, dink, tab); assertEq(vat.dai(address(this)), rad(150 ether) - tab); - assertEq(gem("gold", address(this)), 900 ether); + assertEq(gem("gold", address(this)), 900 ether); flip.dent(auction, 25 ether, tab); assertEq(cat.litter(), tab); assertEq(vat.dai(address(this)), rad(150 ether) - tab); @@ -754,20 +783,20 @@ contract BiteTest is DSTest { hevm.warp(now + 4 hours); flip.deal(auction); assertEq(cat.litter(), 0); - assertEq(gem("gold", address(this)), 900 ether + dink); // (flux another 25 wad into gem) - assertEq(vat.dai(address(this)), rad(150 ether) - tab); - assertEq(vat.dai(address(vow)), vowBalance + tab); + assertEq(gem("gold", address(this)), 900 ether + dink); // (flux another 25 wad into gem) + assertEq(vat.dai(address(this)), rad(150 ether) - tab); + assertEq(vat.dai(address(vow)), vowBalance + tab); } // tests a partial lot liquidation that fill litterbox function testFail_fill_litterbox() public { // spot = tag / (par . mat) // tag=5, mat=2 - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 100 ether, 150 ether); // tag=4, mat=2 - vat.file("gold", 'spot', ray(1 ether)); // now unsafe + vat.file("gold", "spot", ray(1 ether)); // now unsafe assertEq(ink("gold", address(this)), 100 ether); assertEq(art("gold", address(this)), 150 ether); @@ -793,18 +822,18 @@ contract BiteTest is DSTest { function testFail_dusty_litterbox() public { // spot = tag / (par . mat) // tag=5, mat=2 - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 50 ether, 80 ether + 1); // tag=4, mat=2 - vat.file("gold", 'spot', ray(1 ether)); // now unsafe + vat.file("gold", "spot", ray(1 ether)); // now unsafe assertEq(ink("gold", address(this)), 50 ether); assertEq(art("gold", address(this)), 80 ether + 1); assertEq(vow.Woe(), 0 ether); assertEq(gem("gold", address(this)), 950 ether); - cat.file("box", rad(100 ether)); + cat.file("box", rad(100 ether)); vat.file("gold", "dust", rad(20 ether)); cat.file("gold", "dunk", rad(100 ether)); @@ -819,11 +848,11 @@ contract BiteTest is DSTest { // spot = tag / (par . mat) // tag=5, mat=2 - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 100 ether, 150 ether); // tag=4, mat=2 - vat.file("gold", 'spot', ray(1 ether)); // now unsafe + vat.file("gold", "spot", ray(1 ether)); // now unsafe assertEq(ink("gold", address(this)), 100 ether); assertEq(art("gold", address(this)), 150 ether); @@ -840,11 +869,11 @@ contract BiteTest is DSTest { function test_partial_litterbox_multiple_bites() public { // spot = tag / (par . mat) // tag=5, mat=2 - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 100 ether, 150 ether); // tag=4, mat=2 - vat.file("gold", 'spot', ray(1 ether)); // now unsafe + vat.file("gold", "spot", ray(1 ether)); // now unsafe assertEq(ink("gold", address(this)), 100 ether); assertEq(art("gold", address(this)), 150 ether); @@ -855,7 +884,7 @@ contract BiteTest is DSTest { cat.file("gold", "dunk", rad(100 ether)); assertEq(cat.box(), rad(75 ether)); assertEq(cat.litter(), 0); - uint auction = cat.bite("gold", address(this)); + uint256 auction = cat.bite("gold", address(this)); assertEq(cat.litter(), rad(75 ether)); assertEq(ink("gold", address(this)), 50 ether); assertEq(art("gold", address(this)), 75 ether); @@ -863,14 +892,14 @@ contract BiteTest is DSTest { assertEq(gem("gold", address(this)), 900 ether); assertEq(vat.dai(address(this)), rad(150 ether)); - assertEq(vat.dai(address(vow)), rad(0 ether)); - flip.tend(auction, 50 ether, rad( 1 ether)); + assertEq(vat.dai(address(vow)), rad(0 ether)); + flip.tend(auction, 50 ether, rad(1 ether)); assertEq(cat.litter(), rad(75 ether)); assertEq(vat.dai(address(this)), rad(149 ether)); flip.tend(auction, 50 ether, rad(75 ether)); assertEq(vat.dai(address(this)), rad(75 ether)); - assertEq(gem("gold", address(this)), 900 ether); + assertEq(gem("gold", address(this)), 900 ether); flip.dent(auction, 25 ether, rad(75 ether)); assertEq(cat.litter(), rad(75 ether)); assertEq(vat.dai(address(this)), rad(75 ether)); @@ -885,8 +914,8 @@ contract BiteTest is DSTest { flip.deal(auction); assertEq(cat.litter(), 0); assertEq(gem("gold", address(this)), 950 ether); - assertEq(vat.dai(address(this)), rad(75 ether)); - assertEq(vat.dai(address(vow)), rad(75 ether)); + assertEq(vat.dai(address(this)), rad(75 ether)); + assertEq(vat.dai(address(vow)), rad(75 ether)); // now bite more auction = cat.bite("gold", address(this)); @@ -897,14 +926,14 @@ contract BiteTest is DSTest { assertEq(gem("gold", address(this)), 950 ether); assertEq(vat.dai(address(this)), rad(75 ether)); - assertEq(vat.dai(address(vow)), rad(75 ether)); - flip.tend(auction, 50 ether, rad( 1 ether)); + assertEq(vat.dai(address(vow)), rad(75 ether)); + flip.tend(auction, 50 ether, rad(1 ether)); assertEq(cat.litter(), rad(75 ether)); assertEq(vat.dai(address(this)), rad(74 ether)); flip.tend(auction, 50 ether, rad(75 ether)); assertEq(vat.dai(address(this)), 0); - assertEq(gem("gold", address(this)), 950 ether); + assertEq(gem("gold", address(this)), 950 ether); flip.dent(auction, 25 ether, rad(75 ether)); assertEq(cat.litter(), rad(75 ether)); assertEq(vat.dai(address(this)), 0); @@ -914,20 +943,20 @@ contract BiteTest is DSTest { hevm.warp(now + 4 hours); flip.deal(auction); assertEq(cat.litter(), 0); - assertEq(gem("gold", address(this)), 1000 ether); + assertEq(gem("gold", address(this)), 1000 ether); assertEq(vat.dai(address(this)), 0); - assertEq(vat.dai(address(vow)), rad(150 ether)); + assertEq(vat.dai(address(vow)), rad(150 ether)); } function testFail_null_auctions_dart_realistic_values() public { vat.file("gold", "dust", rad(100 ether)); vat.file("gold", "spot", ray(2.5 ether)); vat.file("gold", "line", rad(2000 ether)); - vat.file("Line", rad(2000 ether)); + vat.file("Line", rad(2000 ether)); vat.fold("gold", address(vow), int256(ray(0.25 ether))); vat.frob("gold", me, me, me, 800 ether, 2000 ether); - vat.file("gold", 'spot', ray(1 ether)); // now unsafe + vat.file("gold", "spot", ray(1 ether)); // now unsafe // slightly contrived value to leave tiny amount of room post-liquidation cat.file("box", rad(1130 ether) + 1); @@ -935,7 +964,7 @@ contract BiteTest is DSTest { cat.file("gold", "chop", 1.13 ether); cat.bite("gold", me); assertEq(cat.litter(), rad(1130 ether)); - uint room = cat.box() - cat.litter(); + uint256 room = cat.box() - cat.litter(); assertEq(room, 1); (, uint256 rate,,,) = vat.ilks("gold"); (, uint256 chop,) = cat.ilks("gold"); @@ -953,15 +982,15 @@ contract BiteTest is DSTest { vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 100 ether, 200 ether); - vat.file("gold", 'spot', ray(1 ether)); // now unsafe + vat.file("gold", "spot", ray(1 ether)); // now unsafe // contrived value to leave tiny amount of room post-liquidation cat.file("box", rad(113 ether) + 2); - cat.file("gold", "dunk", rad(113 ether)); + cat.file("gold", "dunk", rad(113 ether)); cat.file("gold", "chop", 1.13 ether); cat.bite("gold", me); assertEq(cat.litter(), rad(113 ether)); - uint room = cat.box() - cat.litter(); + uint256 room = cat.box() - cat.litter(); assertEq(room, 2); (, uint256 rate,,,) = vat.ilks("gold"); (, uint256 chop,) = cat.ilks("gold"); @@ -980,7 +1009,7 @@ contract BiteTest is DSTest { cat.file("gold", "dunk", rad(50 ether)); vat.frob("gold", me, me, me, 1, 100 ether); - vat.file("gold", 'spot', 1); // massive price crash, now unsafe + vat.file("gold", "spot", 1); // massive price crash, now unsafe // This should leave us with 0 dink value, and fail cat.bite("gold", me); @@ -989,15 +1018,15 @@ contract BiteTest is DSTest { function testFail_null_auctions_dink_artificial_values_2() public { vat.file("gold", "spot", ray(2000 ether)); vat.file("gold", "line", rad(20000 ether)); - vat.file("Line", rad(20000 ether)); + vat.file("Line", rad(20000 ether)); vat.frob("gold", me, me, me, 10 ether, 15000 ether); - cat.file("box", rad(1000000 ether)); // plenty of room + cat.file("box", rad(1000000 ether)); // plenty of room // misconfigured dunk (e.g. precision factor incorrect in spell) cat.file("gold", "dunk", rad(100)); - vat.file("gold", 'spot', ray(1000 ether)); // now unsafe + vat.file("gold", "spot", ray(1000 ether)); // now unsafe // This should leave us with 0 dink value, and fail cat.bite("gold", me); @@ -1006,10 +1035,10 @@ contract BiteTest is DSTest { function testFail_null_spot_value() public { // spot = tag / (par . mat) // tag=5, mat=2 - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 100 ether, 150 ether); - vat.file("gold", 'spot', ray(1 ether)); // now unsafe + vat.file("gold", "spot", ray(1 ether)); // now unsafe assertEq(ink("gold", address(this)), 100 ether); assertEq(art("gold", address(this)), 150 ether); @@ -1025,7 +1054,7 @@ contract BiteTest is DSTest { assertEq(vow.sin(now), rad(75 ether)); assertEq(gem("gold", address(this)), 900 ether); - vat.file("gold", 'spot', 0); + vat.file("gold", "spot", 0); // this should fail because spot is 0 cat.bite("gold", address(this)); @@ -1034,7 +1063,7 @@ contract BiteTest is DSTest { function testFail_vault_is_safe() public { // spot = tag / (par . mat) // tag=5, mat=2 - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 100 ether, 150 ether); assertEq(ink("gold", address(this)), 100 ether); @@ -1050,34 +1079,34 @@ contract BiteTest is DSTest { } function test_floppy_bite() public { - vat.file("gold", 'spot', ray(2.5 ether)); + vat.file("gold", "spot", ray(2.5 ether)); vat.frob("gold", me, me, me, 40 ether, 100 ether); - vat.file("gold", 'spot', ray(2 ether)); // now unsafe + vat.file("gold", "spot", ray(2 ether)); // now unsafe - cat.file("gold", "dunk", rad(200 ether)); // => bite everything - assertEq(vow.sin(now), rad( 0 ether)); + cat.file("gold", "dunk", rad(200 ether)); // => bite everything + assertEq(vow.sin(now), rad(0 ether)); cat.bite("gold", address(this)); assertEq(vow.sin(now), rad(100 ether)); assertEq(vow.Sin(), rad(100 ether)); vow.flog(now); - assertEq(vow.Sin(), rad( 0 ether)); + assertEq(vow.Sin(), rad(0 ether)); assertEq(vow.Woe(), rad(100 ether)); - assertEq(vow.Joy(), rad( 0 ether)); - assertEq(vow.Ash(), rad( 0 ether)); + assertEq(vow.Joy(), rad(0 ether)); + assertEq(vow.Ash(), rad(0 ether)); vow.file("sump", rad(10 ether)); vow.file("dump", 2000 ether); - uint f1 = vow.flop(); - assertEq(vow.Woe(), rad(90 ether)); - assertEq(vow.Joy(), rad( 0 ether)); - assertEq(vow.Ash(), rad(10 ether)); + uint256 f1 = vow.flop(); + assertEq(vow.Woe(), rad(90 ether)); + assertEq(vow.Joy(), rad(0 ether)); + assertEq(vow.Ash(), rad(10 ether)); flop.dent(f1, 1000 ether, rad(10 ether)); - assertEq(vow.Woe(), rad(90 ether)); - assertEq(vow.Joy(), rad( 0 ether)); - assertEq(vow.Ash(), rad( 0 ether)); + assertEq(vow.Woe(), rad(90 ether)); + assertEq(vow.Joy(), rad(0 ether)); + assertEq(vow.Ash(), rad(0 ether)); - assertEq(gov.balanceOf(address(this)), 100 ether); + assertEq(gov.balanceOf(address(this)), 100 ether); hevm.warp(now + 4 hours); gov.setOwner(address(flop)); flop.deal(f1); @@ -1087,41 +1116,49 @@ contract BiteTest is DSTest { function test_flappy_bite() public { // get some surplus vat.mint(address(vow), 100 ether); - assertEq(vat.dai(address(vow)), rad(100 ether)); + assertEq(vat.dai(address(vow)), rad(100 ether)); assertEq(gov.balanceOf(address(this)), 100 ether); vow.file("bump", rad(100 ether)); assertEq(vow.Awe(), 0 ether); - uint id = vow.flap(); + uint256 id = vow.flap(); - assertEq(vat.dai(address(this)), rad(0 ether)); + assertEq(vat.dai(address(this)), rad(0 ether)); assertEq(gov.balanceOf(address(this)), 100 ether); flap.tend(id, rad(100 ether), 10 ether); hevm.warp(now + 4 hours); gov.setOwner(address(flap)); flap.deal(id); - assertEq(vat.dai(address(this)), rad(100 ether)); - assertEq(gov.balanceOf(address(this)), 90 ether); + assertEq(vat.dai(address(this)), rad(100 ether)); + assertEq(gov.balanceOf(address(this)), 90 ether); } } contract FoldTest is DSTest { Vat vat; - function ray(uint wad) internal pure returns (uint) { + function ray(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 9; } - function rad(uint wad) internal pure returns (uint) { + + function rad(uint256 wad) internal pure returns (uint256) { return wad * 10 ** 27; } - function tab(bytes32 ilk, address urn) internal view returns (uint) { - (uint ink_, uint art_) = vat.urns(ilk, urn); ink_; - (uint Art_, uint rate, uint spot, uint line, uint dust) = vat.ilks(ilk); - Art_; spot; line; dust; + + function tab(bytes32 ilk, address urn) internal view returns (uint256) { + (uint256 ink_, uint256 art_) = vat.urns(ilk, urn); + ink_; + (uint256 Art_, uint256 rate, uint256 spot, uint256 line, uint256 dust) = vat.ilks(ilk); + Art_; + spot; + line; + dust; return art_ * rate; } - function jam(bytes32 ilk, address urn) internal view returns (uint) { - (uint ink_, uint art_) = vat.urns(ilk, urn); art_; + + function jam(bytes32 ilk, address urn) internal view returns (uint256) { + (uint256 ink_, uint256 art_) = vat.urns(ilk, urn); + art_; return ink_; } @@ -1131,22 +1168,24 @@ contract FoldTest is DSTest { vat.file("Line", rad(100 ether)); vat.file("gold", "line", rad(100 ether)); } - function draw(bytes32 ilk, uint dai) internal { + + function draw(bytes32 ilk, uint256 dai) internal { vat.file("Line", rad(dai)); vat.file(ilk, "line", rad(dai)); vat.file(ilk, "spot", 10 ** 27 * 10000 ether); address self = address(this); - vat.slip(ilk, self, 10 ** 27 * 1 ether); - vat.frob(ilk, self, self, self, int(1 ether), int(dai)); + vat.slip(ilk, self, 10 ** 27 * 1 ether); + vat.frob(ilk, self, self, self, int256(1 ether), int256(dai)); } + function test_fold() public { address self = address(this); - address ali = address(bytes20("ali")); + address ali = address(bytes20("ali")); draw("gold", 1 ether); - assertEq(tab("gold", self), rad(1.00 ether)); - vat.fold("gold", ali, int(ray(0.05 ether))); + assertEq(tab("gold", self), rad(1.0 ether)); + vat.fold("gold", ali, int256(ray(0.05 ether))); assertEq(tab("gold", self), rad(1.05 ether)); - assertEq(vat.dai(ali), rad(0.05 ether)); + assertEq(vat.dai(ali), rad(0.05 ether)); } } diff --git a/src/test/vow.t.sol b/src/test/vow.t.sol index b88027d0..6b108efa 100644 --- a/src/test/vow.t.sol +++ b/src/test/vow.t.sol @@ -19,18 +19,19 @@ pragma solidity ^0.6.12; import "ds-test/test.sol"; -import {Flopper as Flop} from './flop.t.sol'; -import {Flapper as Flap} from './flap.t.sol'; -import {TestVat as Vat} from './vat.t.sol'; -import {Vow} from '../vow.sol'; +import {Flopper as Flop} from "./flop.t.sol"; +import {Flapper as Flap} from "./flap.t.sol"; +import {TestVat as Vat} from "./vat.t.sol"; +import {Vow} from "../vow.sol"; interface Hevm { function warp(uint256) external; } contract Gem { - mapping (address => uint256) public balanceOf; - function mint(address usr, uint rad) public { + mapping(address => uint256) public balanceOf; + + function mint(address usr, uint256 rad) public { balanceOf[usr] += rad; } } @@ -38,11 +39,11 @@ contract Gem { contract VowTest is DSTest { Hevm hevm; - Vat vat; - Vow vow; + Vat vat; + Vow vow; Flop flop; Flap flap; - Gem gov; + Gem gov; function setUp() public { hevm = Hevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); @@ -50,7 +51,7 @@ contract VowTest is DSTest { vat = new Vat(); - gov = new Gem(); + gov = new Gem(); flop = new Flop(address(vat), address(gov)); flap = new Flap(address(vat), address(gov)); @@ -66,14 +67,16 @@ contract VowTest is DSTest { vat.hope(address(flop)); } - function try_flog(uint era) internal returns (bool ok) { + function try_flog(uint256 era) internal returns (bool ok) { string memory sig = "flog(uint256)"; (ok,) = address(vow).call(abi.encodeWithSignature(sig, era)); } - function try_dent(uint id, uint lot, uint bid) internal returns (bool ok) { + + function try_dent(uint256 id, uint256 lot, uint256 bid) internal returns (bool ok) { string memory sig = "dent(uint256,uint256,uint256)"; (ok,) = address(flop).call(abi.encodeWithSignature(sig, id, lot, bid)); } + function try_call(address addr, bytes calldata data) external returns (bool) { bytes memory _data = data; assembly { @@ -84,6 +87,7 @@ contract VowTest is DSTest { revert(free, 32) } } + function can_flap() public returns (bool) { string memory sig = "flap()"; bytes memory data = abi.encodeWithSignature(sig); @@ -94,6 +98,7 @@ contract VowTest is DSTest { ok = abi.decode(success, (bool)); if (ok) return true; } + function can_flop() public returns (bool) { string memory sig = "flop()"; bytes memory data = abi.encodeWithSignature(sig); @@ -105,21 +110,24 @@ contract VowTest is DSTest { if (ok) return true; } - uint constant ONE = 10 ** 27; - function rad(uint wad) internal pure returns (uint) { + uint256 constant ONE = 10 ** 27; + + function rad(uint256 wad) internal pure returns (uint256) { return wad * ONE; } - function suck(address who, uint wad) internal { + function suck(address who, uint256 wad) internal { vow.fess(rad(wad)); - vat.init(''); + vat.init(""); vat.suck(address(vow), who, rad(wad)); } - function flog(uint wad) internal { - suck(address(0), wad); // suck dai into the zero address + + function flog(uint256 wad) internal { + suck(address(0), wad); // suck dai into the zero address vow.flog(now); } - function heal(uint wad) internal { + + function heal(uint256 wad) internal { vow.heal(rad(wad)); } @@ -133,8 +141,8 @@ contract VowTest is DSTest { assertEq(vat.can(address(vow), address(flap)), 1); assertEq(vat.can(address(vow), address(newFlap)), 0); - vow.file('flapper', address(newFlap)); - vow.file('flopper', address(newFlop)); + vow.file("flapper", address(newFlap)); + vow.file("flopper", address(newFlop)); assertEq(address(vow.flapper()), address(newFlap)); assertEq(address(vow.flopper()), address(newFlop)); @@ -145,37 +153,37 @@ contract VowTest is DSTest { function test_flog_wait() public { assertEq(vow.wait(), 0); - vow.file('wait', uint(100 seconds)); + vow.file("wait", uint256(100 seconds)); assertEq(vow.wait(), 100 seconds); - uint tic = now; - vow.fess(100 ether); - hevm.warp(tic + 99 seconds); - assertTrue(!try_flog(tic) ); - hevm.warp(tic + 100 seconds); - assertTrue( try_flog(tic) ); + uint256 tic = now; + vow.fess(100 ether); + hevm.warp(tic + 99 seconds); + assertTrue(!try_flog(tic)); + hevm.warp(tic + 100 seconds); + assertTrue(try_flog(tic)); } function test_no_reflop() public { flog(100 ether); - assertTrue( can_flop() ); + assertTrue(can_flop()); vow.flop(); - assertTrue(!can_flop() ); + assertTrue(!can_flop()); } function test_no_flop_pending_joy() public { flog(200 ether); vat.mint(address(vow), 100 ether); - assertTrue(!can_flop() ); + assertTrue(!can_flop()); heal(100 ether); - assertTrue( can_flop() ); + assertTrue(can_flop()); } function test_flap() public { vat.mint(address(vow), 100 ether); - assertTrue( can_flap() ); + assertTrue(can_flap()); } function test_no_flap_pending_sin() public { @@ -183,50 +191,53 @@ contract VowTest is DSTest { flog(100 ether); vat.mint(address(vow), 50 ether); - assertTrue(!can_flap() ); + assertTrue(!can_flap()); } + function test_no_flap_nonzero_woe() public { vow.file("bump", uint256(0 ether)); flog(100 ether); vat.mint(address(vow), 50 ether); - assertTrue(!can_flap() ); + assertTrue(!can_flap()); } + function test_no_flap_pending_flop() public { flog(100 ether); vow.flop(); vat.mint(address(vow), 100 ether); - assertTrue(!can_flap() ); + assertTrue(!can_flap()); } + function test_no_flap_pending_heal() public { flog(100 ether); - uint id = vow.flop(); + uint256 id = vow.flop(); vat.mint(address(this), 100 ether); flop.dent(id, 0 ether, rad(100 ether)); - assertTrue(!can_flap() ); + assertTrue(!can_flap()); } function test_no_surplus_after_good_flop() public { flog(100 ether); - uint id = vow.flop(); + uint256 id = vow.flop(); vat.mint(address(this), 100 ether); - flop.dent(id, 0 ether, rad(100 ether)); // flop succeeds.. + flop.dent(id, 0 ether, rad(100 ether)); // flop succeeds.. - assertTrue(!can_flap() ); + assertTrue(!can_flap()); } function test_multiple_flop_dents() public { flog(100 ether); - uint id = vow.flop(); + uint256 id = vow.flop(); vat.mint(address(this), 100 ether); - assertTrue(try_dent(id, 2 ether, rad(100 ether))); + assertTrue(try_dent(id, 2 ether, rad(100 ether))); vat.mint(address(this), 100 ether); - assertTrue(try_dent(id, 1 ether, rad(100 ether))); + assertTrue(try_dent(id, 1 ether, rad(100 ether))); } } diff --git a/src/vat.sol b/src/vat.sol index ff90bbed..12164cb6 100644 --- a/src/vat.sol +++ b/src/vat.sol @@ -25,44 +25,60 @@ pragma solidity ^0.6.12; contract Vat { // --- Auth --- - mapping (address => uint) public wards; - function rely(address usr) external auth { require(live == 1, "Vat/not-live"); wards[usr] = 1; } - function deny(address usr) external auth { require(live == 1, "Vat/not-live"); wards[usr] = 0; } - modifier auth { + mapping(address => uint256) public wards; + + function rely(address usr) external auth { + require(live == 1, "Vat/not-live"); + wards[usr] = 1; + } + + function deny(address usr) external auth { + require(live == 1, "Vat/not-live"); + wards[usr] = 0; + } + modifier auth() { require(wards[msg.sender] == 1, "Vat/not-authorized"); _; } - mapping(address => mapping (address => uint)) public can; - function hope(address usr) external { can[msg.sender][usr] = 1; } - function nope(address usr) external { can[msg.sender][usr] = 0; } + mapping(address => mapping(address => uint256)) public can; + + function hope(address usr) external { + can[msg.sender][usr] = 1; + } + + function nope(address usr) external { + can[msg.sender][usr] = 0; + } + function wish(address bit, address usr) internal view returns (bool) { return either(bit == usr, can[bit][usr] == 1); } // --- Data --- struct Ilk { - uint256 Art; // Total Normalised Debt [wad] - uint256 rate; // Accumulated Rates [ray] - uint256 spot; // Price with Safety Margin [ray] - uint256 line; // Debt Ceiling [rad] - uint256 dust; // Urn Debt Floor [rad] + uint256 Art; // Total Normalised Debt [wad] + uint256 rate; // Accumulated Rates [ray] + uint256 spot; // Price with Safety Margin [ray] + uint256 line; // Debt Ceiling [rad] + uint256 dust; // Urn Debt Floor [rad] } + struct Urn { - uint256 ink; // Locked Collateral [wad] - uint256 art; // Normalised Debt [wad] + uint256 ink; // Locked Collateral [wad] + uint256 art; // Normalised Debt [wad] } - mapping (bytes32 => Ilk) public ilks; - mapping (bytes32 => mapping (address => Urn )) public urns; - mapping (bytes32 => mapping (address => uint)) public gem; // [wad] - mapping (address => uint256) public dai; // [rad] - mapping (address => uint256) public sin; // [rad] + mapping(bytes32 => Ilk) public ilks; + mapping(bytes32 => mapping(address => Urn)) public urns; + mapping(bytes32 => mapping(address => uint256)) public gem; // [wad] + mapping(address => uint256) public dai; // [rad] + mapping(address => uint256) public sin; // [rad] - uint256 public debt; // Total Dai Issued [rad] - uint256 public vice; // Total Unbacked Dai [rad] - uint256 public Line; // Total Debt Ceiling [rad] - uint256 public live; // Active Flag + uint256 public debt; // Total Dai Issued [rad] + uint256 public vice; // Total Unbacked Dai [rad] + uint256 public Line; // Total Debt Ceiling [rad] + uint256 public live; // Active Flag // --- Init --- constructor() public { @@ -71,28 +87,33 @@ contract Vat { } // --- Math --- - function _add(uint x, int y) internal pure returns (uint z) { - z = x + uint(y); + function _add(uint256 x, int256 y) internal pure returns (uint256 z) { + z = x + uint256(y); require(y >= 0 || z <= x); require(y <= 0 || z >= x); } - function _sub(uint x, int y) internal pure returns (uint z) { - z = x - uint(y); + + function _sub(uint256 x, int256 y) internal pure returns (uint256 z) { + z = x - uint256(y); require(y <= 0 || z <= x); require(y >= 0 || z >= x); } - function _mul(uint x, int y) internal pure returns (int z) { - z = int(x) * y; - require(int(x) >= 0); - require(y == 0 || z / y == int(x)); + + function _mul(uint256 x, int256 y) internal pure returns (int256 z) { + z = int256(x) * y; + require(int256(x) >= 0); + require(y == 0 || z / y == int256(x)); } - function _add(uint x, uint y) internal pure returns (uint z) { + + function _add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } - function _sub(uint x, uint y) internal pure returns (uint z) { + + function _sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } - function _mul(uint x, uint y) internal pure returns (uint z) { + + function _mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } @@ -101,18 +122,21 @@ contract Vat { require(ilks[ilk].rate == 0, "Vat/ilk-already-init"); ilks[ilk].rate = 10 ** 27; } - function file(bytes32 what, uint data) external auth { + + function file(bytes32 what, uint256 data) external auth { require(live == 1, "Vat/not-live"); if (what == "Line") Line = data; else revert("Vat/file-unrecognized-param"); } - function file(bytes32 ilk, bytes32 what, uint data) external auth { + + function file(bytes32 ilk, bytes32 what, uint256 data) external auth { require(live == 1, "Vat/not-live"); if (what == "spot") ilks[ilk].spot = data; else if (what == "line") ilks[ilk].line = data; else if (what == "dust") ilks[ilk].dust = data; else revert("Vat/file-unrecognized-param"); } + function cage() external auth { live = 0; } @@ -121,11 +145,13 @@ contract Vat { function slip(bytes32 ilk, address usr, int256 wad) external auth { gem[ilk][usr] = _add(gem[ilk][usr], wad); } + function flux(bytes32 ilk, address src, address dst, uint256 wad) external { require(wish(src, msg.sender), "Vat/not-allowed"); gem[ilk][src] = _sub(gem[ilk][src], wad); gem[ilk][dst] = _add(gem[ilk][dst], wad); } + function move(address src, address dst, uint256 rad) external { require(wish(src, msg.sender), "Vat/not-allowed"); dai[src] = _sub(dai[src], rad); @@ -133,14 +159,15 @@ contract Vat { } function either(bool x, bool y) internal pure returns (bool z) { - assembly{ z := or(x, y)} + assembly { z := or(x, y) } } + function both(bool x, bool y) internal pure returns (bool z) { - assembly{ z := and(x, y)} + assembly { z := and(x, y) } } // --- CDP Manipulation --- - function frob(bytes32 i, address u, address v, address w, int dink, int dart) external { + function frob(bytes32 i, address u, address v, address w, int256 dink, int256 dart) external { // system is live require(live == 1, "Vat/not-live"); @@ -153,9 +180,9 @@ contract Vat { urn.art = _add(urn.art, dart); ilk.Art = _add(ilk.Art, dart); - int dtab = _mul(ilk.rate, dart); - uint tab = _mul(ilk.rate, urn.art); - debt = _add(debt, dtab); + int256 dtab = _mul(ilk.rate, dart); + uint256 tab = _mul(ilk.rate, urn.art); + debt = _add(debt, dtab); // either debt has decreased, or debt ceilings are not exceeded require(either(dart <= 0, both(_mul(ilk.Art, ilk.rate) <= ilk.line, debt <= Line)), "Vat/ceiling-exceeded"); @@ -173,13 +200,14 @@ contract Vat { require(either(urn.art == 0, tab >= ilk.dust), "Vat/dust"); gem[i][v] = _sub(gem[i][v], dink); - dai[w] = _add(dai[w], dtab); + dai[w] = _add(dai[w], dtab); urns[i][u] = urn; - ilks[i] = ilk; + ilks[i] = ilk; } + // --- CDP Fungibility --- - function fork(bytes32 ilk, address src, address dst, int dink, int dart) external { + function fork(bytes32 ilk, address src, address dst, int256 dink, int256 dart) external { Urn storage u = urns[ilk][src]; Urn storage v = urns[ilk][dst]; Ilk storage i = ilks[ilk]; @@ -189,8 +217,8 @@ contract Vat { v.ink = _add(v.ink, dink); v.art = _add(v.art, dart); - uint utab = _mul(u.art, i.rate); - uint vtab = _mul(v.art, i.rate); + uint256 utab = _mul(u.art, i.rate); + uint256 vtab = _mul(v.art, i.rate); // both sides consent require(both(wish(src, msg.sender), wish(dst, msg.sender)), "Vat/not-allowed"); @@ -203,8 +231,9 @@ contract Vat { require(either(utab >= i.dust, u.art == 0), "Vat/dust-src"); require(either(vtab >= i.dust, v.art == 0), "Vat/dust-dst"); } + // --- CDP Confiscation --- - function grab(bytes32 i, address u, address v, address w, int dink, int dart) external auth { + function grab(bytes32 i, address u, address v, address w, int256 dink, int256 dart) external auth { Urn storage urn = urns[i][u]; Ilk storage ilk = ilks[i]; @@ -212,35 +241,36 @@ contract Vat { urn.art = _add(urn.art, dart); ilk.Art = _add(ilk.Art, dart); - int dtab = _mul(ilk.rate, dart); + int256 dtab = _mul(ilk.rate, dart); gem[i][v] = _sub(gem[i][v], dink); - sin[w] = _sub(sin[w], dtab); - vice = _sub(vice, dtab); + sin[w] = _sub(sin[w], dtab); + vice = _sub(vice, dtab); } // --- Settlement --- - function heal(uint rad) external { + function heal(uint256 rad) external { address u = msg.sender; sin[u] = _sub(sin[u], rad); dai[u] = _sub(dai[u], rad); - vice = _sub(vice, rad); - debt = _sub(debt, rad); + vice = _sub(vice, rad); + debt = _sub(debt, rad); } - function suck(address u, address v, uint rad) external auth { + + function suck(address u, address v, uint256 rad) external auth { sin[u] = _add(sin[u], rad); dai[v] = _add(dai[v], rad); - vice = _add(vice, rad); - debt = _add(debt, rad); + vice = _add(vice, rad); + debt = _add(debt, rad); } // --- Rates --- - function fold(bytes32 i, address u, int rate) external auth { + function fold(bytes32 i, address u, int256 rate) external auth { require(live == 1, "Vat/not-live"); Ilk storage ilk = ilks[i]; ilk.rate = _add(ilk.rate, rate); - int rad = _mul(ilk.Art, rate); - dai[u] = _add(dai[u], rad); - debt = _add(debt, rad); + int256 rad = _mul(ilk.Art, rate); + dai[u] = _add(dai[u], rad); + debt = _add(debt, rad); } } diff --git a/src/vow.sol b/src/vow.sol index f28d6997..bd497653 100644 --- a/src/vow.sol +++ b/src/vow.sol @@ -24,20 +24,20 @@ pragma solidity ^0.6.12; // New deployments of this contract will need to include custom events (TO DO). interface FlopLike { - function kick(address gal, uint lot, uint bid) external returns (uint); + function kick(address gal, uint256 lot, uint256 bid) external returns (uint256); function cage() external; - function live() external returns (uint); + function live() external returns (uint256); } interface FlapLike { - function kick(uint lot, uint bid) external returns (uint); - function cage(uint) external; - function live() external returns (uint); + function kick(uint256 lot, uint256 bid) external returns (uint256); + function cage(uint256) external; + function live() external returns (uint256); } interface VatLike { - function dai (address) external view returns (uint); - function sin (address) external view returns (uint); + function dai(address) external view returns (uint256); + function sin(address) external view returns (uint256); function heal(uint256) external; function hope(address) external; function nope(address) external; @@ -45,36 +45,43 @@ interface VatLike { contract Vow { // --- Auth --- - mapping (address => uint) public wards; - function rely(address usr) external auth { require(live == 1, "Vow/not-live"); wards[usr] = 1; } - function deny(address usr) external auth { wards[usr] = 0; } - modifier auth { + mapping(address => uint256) public wards; + + function rely(address usr) external auth { + require(live == 1, "Vow/not-live"); + wards[usr] = 1; + } + + function deny(address usr) external auth { + wards[usr] = 0; + } + modifier auth() { require(wards[msg.sender] == 1, "Vow/not-authorized"); _; } // --- Data --- - VatLike public vat; // CDP Engine - FlapLike public flapper; // Surplus Auction House - FlopLike public flopper; // Debt Auction House + VatLike public vat; // CDP Engine + FlapLike public flapper; // Surplus Auction House + FlopLike public flopper; // Debt Auction House - mapping (uint256 => uint256) public sin; // debt queue - uint256 public Sin; // Queued debt [rad] - uint256 public Ash; // On-auction debt [rad] + mapping(uint256 => uint256) public sin; // debt queue + uint256 public Sin; // Queued debt [rad] + uint256 public Ash; // On-auction debt [rad] - uint256 public wait; // Flop delay [seconds] - uint256 public dump; // Flop initial lot size [wad] - uint256 public sump; // Flop fixed bid size [rad] + uint256 public wait; // Flop delay [seconds] + uint256 public dump; // Flop initial lot size [wad] + uint256 public sump; // Flop fixed bid size [rad] - uint256 public bump; // Flap fixed lot size [rad] - uint256 public hump; // Surplus buffer [rad] + uint256 public bump; // Flap fixed lot size [rad] + uint256 public hump; // Surplus buffer [rad] - uint256 public live; // Active Flag + uint256 public live; // Active Flag // --- Init --- constructor(address vat_, address flapper_, address flopper_) public { wards[msg.sender] = 1; - vat = VatLike(vat_); + vat = VatLike(vat_); flapper = FlapLike(flapper_); flopper = FlopLike(flopper_); vat.hope(flapper_); @@ -82,18 +89,20 @@ contract Vow { } // --- Math --- - function add(uint x, uint y) internal pure returns (uint z) { + function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } - function sub(uint x, uint y) internal pure returns (uint z) { + + function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } - function min(uint x, uint y) internal pure returns (uint z) { + + function min(uint256 x, uint256 y) internal pure returns (uint256 z) { return x <= y ? x : y; } // --- Administration --- - function file(bytes32 what, uint data) external auth { + function file(bytes32 what, uint256 data) external auth { if (what == "wait") wait = data; else if (what == "bump") bump = data; else if (what == "sump") sump = data; @@ -107,30 +116,34 @@ contract Vow { vat.nope(address(flapper)); flapper = FlapLike(data); vat.hope(data); + } else if (what == "flopper") { + flopper = FlopLike(data); + } else { + revert("Vow/file-unrecognized-param"); } - else if (what == "flopper") flopper = FlopLike(data); - else revert("Vow/file-unrecognized-param"); } // Push to debt-queue - function fess(uint tab) external auth { + function fess(uint256 tab) external auth { sin[now] = add(sin[now], tab); Sin = add(Sin, tab); } + // Pop from debt-queue - function flog(uint era) external { + function flog(uint256 era) external { require(add(era, wait) <= now, "Vow/wait-not-finished"); Sin = sub(Sin, sin[era]); sin[era] = 0; } // Debt settlement - function heal(uint rad) external { + function heal(uint256 rad) external { require(rad <= vat.dai(address(this)), "Vow/insufficient-surplus"); require(rad <= sub(sub(vat.sin(address(this)), Sin), Ash), "Vow/insufficient-debt"); vat.heal(rad); } - function kiss(uint rad) external { + + function kiss(uint256 rad) external { require(rad <= Ash, "Vow/not-enough-ash"); require(rad <= vat.dai(address(this)), "Vow/insufficient-surplus"); Ash = sub(Ash, rad); @@ -138,14 +151,15 @@ contract Vow { } // Debt auction - function flop() external returns (uint id) { + function flop() external returns (uint256 id) { require(sump <= sub(sub(vat.sin(address(this)), Sin), Ash), "Vow/insufficient-debt"); require(vat.dai(address(this)) == 0, "Vow/surplus-not-zero"); Ash = add(Ash, sump); id = flopper.kick(address(this), dump, sump); } + // Surplus auction - function flap() external returns (uint id) { + function flap() external returns (uint256 id) { require(vat.dai(address(this)) >= add(add(vat.sin(address(this)), bump), hump), "Vow/insufficient-surplus"); require(sub(sub(vat.sin(address(this)), Sin), Ash) == 0, "Vow/debt-not-zero"); id = flapper.kick(bump, 0);