Skip to content

Commit

Permalink
🚸 escrow: return reserve on external stream cancel
Browse files Browse the repository at this point in the history
Co-authored-by: danilo neves cruz <cruzdanilo@gmail.com>
  • Loading branch information
itofarina and cruzdanilo committed Oct 11, 2023
1 parent 2cd9c82 commit 0182437
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/thin-bugs-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@exactly/protocol": patch
---

🚸 escrow: return reserve on external stream cancel
8 changes: 4 additions & 4 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ DebtPreviewerTest:testPreviewMaxRatioWithdrawWithSameAssetLeverage() (gas: 10205
DebtPreviewerTest:testPreviewSameAssetInvalidLeverageShouldCapRatio() (gas: 910754)
EscrowedEXATest:testCancelExternalStreams() (gas: 452302)
EscrowedEXATest:testCancelExternalStreamsWithesEXACancel() (gas: 903873)
EscrowedEXATest:testCancelFromStreamAndGetReserveBack() (gas: 457589)
EscrowedEXATest:testCancelFromStreamJustCreated() (gas: 412791)
EscrowedEXATest:testCancelFromStreamAndGetReserveBack() (gas: 451714)
EscrowedEXATest:testCancelFromStreamJustCreated() (gas: 404796)
EscrowedEXATest:testCancelShouldDeleteReserves() (gas: 471143)
EscrowedEXATest:testCancelShouldGiveReservesBack() (gas: 676562)
EscrowedEXATest:testCancelTwiceShouldRevert() (gas: 456028)
Expand All @@ -122,10 +122,10 @@ EscrowedEXATest:testVestToAnother() (gas: 403826)
EscrowedEXATest:testVestToAnotherAndCancel() (gas: 489580)
EscrowedEXATest:testVestWithPermitReserve() (gas: 458876)
EscrowedEXATest:testVestZero() (gas: 14151)
EscrowedEXATest:testWithdrawFromStreamAndGetReserveBack() (gas: 329816)
EscrowedEXATest:testWithdrawFromStreamAndGetReserveBack() (gas: 329850)
EscrowedEXATest:testWithdrawFromUnknownStream() (gas: 898481)
EscrowedEXATest:testWithdrawMaxFromMultipleStreams() (gas: 1007617)
EscrowedEXATest:testWithdrawMaxShouldGiveReserveBackWhenDepleted() (gas: 327828)
EscrowedEXATest:testWithdrawMaxShouldGiveReserveBackWhenDepleted() (gas: 327862)
EscrowedEXATest:testWithdrawMaxWithInvalidSender() (gas: 339700)
InterestRateModelTest:testFixedBorrowRate() (gas: 8089)
InterestRateModelTest:testFloatingBorrowRate() (gas: 6236)
Expand Down
16 changes: 11 additions & 5 deletions contracts/periphery/EscrowedEXA.sol
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,7 @@ contract EscrowedEXA is ERC20VotesUpgradeable, AccessControlUpgradeable {
/// @param streamId streamId to withdraw from.
function withdrawMax(uint256 streamId) internal {
if (sablier.withdrawableAmountOf(streamId) != 0) sablier.withdrawMax(streamId, msg.sender);
if (sablier.isDepleted(streamId)) {
uint256 reserve = reserves[streamId];
delete reserves[streamId];
exa.safeTransfer(msg.sender, reserve);
}
if (sablier.isDepleted(streamId)) returnReserve(streamId, msg.sender);
}

/// @notice Checks if a stream is valid through its reserve. Reverts with `InvalidStream` if it is not.
Expand All @@ -170,6 +166,15 @@ contract EscrowedEXA is ERC20VotesUpgradeable, AccessControlUpgradeable {
if (reserves[streamId] == 0) revert InvalidStream();
}

/// @notice Returns the reserve to the recipient.
/// @param streamId streamId of the reserve to return.
/// @param recipient recipient of the reserve.
function returnReserve(uint256 streamId, address recipient) internal {
uint256 reserve = reserves[streamId];
delete reserves[streamId];
exa.safeTransfer(recipient, reserve);
}

/// @notice Hook called when a recipient cancels a stream.
/// @notice Mints esEXA to the recipient with the remaining EXA received from the canceled stream.
/// @param streamId streamId of the cancelled stream.
Expand All @@ -179,6 +184,7 @@ contract EscrowedEXA is ERC20VotesUpgradeable, AccessControlUpgradeable {
assert(msg.sender == address(sablier));
checkStream(streamId);
_mint(recipient, senderAmount);
returnReserve(streamId, recipient);
}

/// @notice Sets the vesting period.
Expand Down
17 changes: 7 additions & 10 deletions test/EscrowedEXA.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -416,18 +416,17 @@ contract EscrowedEXATest is ForkTest {
uint256 amount = 1_000 ether;
uint256 reserve = amount.mulWadDown(esEXA.reserveRatio());
esEXA.mint(amount, address(this));
uint256[] memory streams = new uint256[](1);
streams[0] = esEXA.vest(uint128(amount), address(this));
uint256 streamId = esEXA.vest(uint128(amount), address(this));

uint256 exaBefore = exa.balanceOf(address(this));
vm.warp(block.timestamp + esEXA.vestingPeriod() / 2);

esEXA.sablier().cancel(streams[0]);

assertEq(esEXA.balanceOf(address(this)), amount / 2, "half esEXA sholud be back");
esEXA.sablier().cancel(streamId);

esEXA.withdrawMax(streams);
assertEq(exa.balanceOf(address(this)), exaBefore + amount / 2 + reserve, "amount/2 + reserve should be back");
assertEq(esEXA.balanceOf(address(this)), amount / 2, "half esEXA should be back");
assertEq(exa.balanceOf(address(this)), exaBefore + reserve, "reserve should be back");
esEXA.sablier().withdrawMax(streamId, address(this));
assertEq(exa.balanceOf(address(this)), exaBefore + reserve + amount / 2, "amount/2 should be back");
}

function testCancelFromStreamJustCreated() external {
Expand All @@ -441,9 +440,7 @@ contract EscrowedEXATest is ForkTest {

esEXA.sablier().cancel(streams[0]);

assertEq(esEXA.balanceOf(address(this)), amount, "amount esEXA sholud be back");

esEXA.withdrawMax(streams);
assertEq(esEXA.balanceOf(address(this)), amount, "amount esEXA should be back");
assertEq(exa.balanceOf(address(this)), exaBefore + reserve, "reserve should be back");
}

Expand Down

0 comments on commit 0182437

Please sign in to comment.