Skip to content

Commit 8498a09

Browse files
committed
feat: extract cancel thaw escrow to its own function
Signed-off-by: Tomás Migone <[email protected]>
1 parent a065804 commit 8498a09

File tree

4 files changed

+75
-27
lines changed

4 files changed

+75
-27
lines changed

packages/horizon/contracts/interfaces/IPaymentsEscrow.sol

+14-3
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ interface IPaymentsEscrow {
3838
* @notice Emitted when a payer cancels an escrow thawing
3939
* @param payer The address of the payer
4040
* @param receiver The address of the receiver
41+
* @param tokensThawing The amount of tokens that were being thawed
42+
* @param thawEndTimestamp The timestamp at which the thawing period was ending
4143
*/
42-
event CancelThaw(address indexed payer, address indexed receiver);
44+
event CancelThaw(address indexed payer, address indexed receiver, uint256 tokensThawing, uint256 thawEndTimestamp);
4345

4446
/**
4547
* @notice Emitted when a payer thaws funds from the escrow for a payer-collector-receiver tuple
@@ -145,20 +147,29 @@ interface IPaymentsEscrow {
145147
/**
146148
* @notice Thaw a specific amount of escrow from a payer-collector-receiver's escrow account.
147149
* The payer is the transaction caller.
148-
* If `tokens` is zero and funds were already thawing it will cancel the thawing.
149150
* Note that repeated calls to this function will overwrite the previous thawing amount
150151
* and reset the thawing period.
151152
* @dev Requirements:
152153
* - `tokens` must be less than or equal to the available balance
153154
*
154-
* Emits a {Thaw} event. If `tokens` is zero it will emit a {CancelThaw} event.
155+
* Emits a {Thaw} event.
155156
*
156157
* @param collector The address of the collector
157158
* @param receiver The address of the receiver
158159
* @param tokens The amount of tokens to thaw
159160
*/
160161
function thaw(address collector, address receiver, uint256 tokens) external;
161162

163+
/**
164+
* @notice Cancels the thawing of escrow from a payer-collector-receiver's escrow account.
165+
* @param collector The address of the collector
166+
* @param receiver The address of the receiver
167+
* @dev Requirements:
168+
* - The payer must be thawing funds
169+
* Emits a {CancelThaw} event.
170+
*/
171+
function cancelThaw(address collector, address receiver) external;
172+
162173
/**
163174
* @notice Withdraws all thawed escrow from a payer-collector-receiver's escrow account.
164175
* The payer is the transaction caller.

packages/horizon/contracts/payments/PaymentsEscrow.sol

+17-12
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,9 @@ contract PaymentsEscrow is Initializable, MulticallUpgradeable, GraphDirectory,
7878
* @notice See {IPaymentsEscrow-thaw}
7979
*/
8080
function thaw(address collector, address receiver, uint256 tokens) external override notPaused {
81-
EscrowAccount storage account = escrowAccounts[msg.sender][collector][receiver];
82-
83-
// if amount thawing is zero and requested amount is zero this is an invalid request.
84-
// otherwise if amount thawing is greater than zero and requested amount is zero this
85-
// is a cancel thaw request.
86-
if (tokens == 0) {
87-
require(account.tokensThawing != 0, PaymentsEscrowNotThawing());
88-
account.tokensThawing = 0;
89-
account.thawEndTimestamp = 0;
90-
emit CancelThaw(msg.sender, receiver);
91-
return;
92-
}
81+
require(tokens > 0, PaymentsEscrowInvalidZeroTokens());
9382

83+
EscrowAccount storage account = escrowAccounts[msg.sender][collector][receiver];
9484
require(account.balance >= tokens, PaymentsEscrowInsufficientBalance(account.balance, tokens));
9585

9686
account.tokensThawing = tokens;
@@ -99,6 +89,21 @@ contract PaymentsEscrow is Initializable, MulticallUpgradeable, GraphDirectory,
9989
emit Thaw(msg.sender, collector, receiver, tokens, account.thawEndTimestamp);
10090
}
10191

92+
/**
93+
* @notice See {IPaymentsEscrow-cancelThaw}
94+
*/
95+
function cancelThaw(address collector, address receiver) external override notPaused {
96+
EscrowAccount storage account = escrowAccounts[msg.sender][collector][receiver];
97+
require(account.tokensThawing != 0, PaymentsEscrowNotThawing());
98+
99+
uint256 tokensThawing = account.tokensThawing;
100+
uint256 thawEndTimestamp = account.thawEndTimestamp;
101+
account.tokensThawing = 0;
102+
account.thawEndTimestamp = 0;
103+
104+
emit CancelThaw(msg.sender, receiver, tokensThawing, thawEndTimestamp);
105+
}
106+
102107
/**
103108
* @notice See {IPaymentsEscrow-withdraw}
104109
*/

packages/horizon/test/escrow/GraphEscrow.t.sol

+13
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,19 @@ contract GraphEscrowTest is HorizonStakingSharedTest, PaymentsEscrowSharedTest {
5656
assertEq(thawEndTimestamp, expectedThawEndTimestamp);
5757
}
5858

59+
function _cancelThawEscrow(address collector, address receiver) internal {
60+
(, address msgSender, ) = vm.readCallers();
61+
(, uint256 amountThawingBefore, uint256 thawEndTimestampBefore) = escrow.escrowAccounts(msgSender, collector, receiver);
62+
63+
vm.expectEmit(address(escrow));
64+
emit IPaymentsEscrow.CancelThaw(msgSender, receiver, amountThawingBefore, thawEndTimestampBefore);
65+
escrow.cancelThaw(collector, receiver);
66+
67+
(, uint256 amountThawing, uint256 thawEndTimestamp) = escrow.escrowAccounts(msgSender, collector, receiver);
68+
assertEq(amountThawing, 0);
69+
assertEq(thawEndTimestamp, 0);
70+
}
71+
5972
struct CollectPaymentData {
6073
uint256 escrowBalance;
6174
uint256 paymentsBalance;

packages/horizon/test/escrow/thaw.t.sol

+31-12
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,32 @@ import "forge-std/Test.sol";
66
import { GraphEscrowTest } from "./GraphEscrow.t.sol";
77

88
contract GraphEscrowThawTest is GraphEscrowTest {
9-
109
/*
1110
* TESTS
1211
*/
1312

1413
function testThaw_Tokens(uint256 amount) public useGateway useDeposit(amount) {
14+
amount = bound(amount, 1, type(uint256).max);
1515
_thawEscrow(users.verifier, users.indexer, amount);
1616
}
1717

18-
function testThaw_RevertWhen_InsufficientThawAmount(
19-
uint256 amount
20-
) public useGateway useDeposit(amount) {
21-
bytes memory expectedError = abi.encodeWithSignature("PaymentsEscrowNotThawing()");
18+
function testThaw_Tokens_SuccesiveCalls(uint256 amount) public useGateway {
19+
amount = bound(amount, 2, type(uint256).max - 10);
20+
_depositTokens(users.verifier, users.indexer, amount);
21+
22+
uint256 firstAmountToThaw = (amount + 2 - 1) / 2;
23+
uint256 secondAmountToThaw = (amount + 10 - 1) / 10;
24+
_thawEscrow(users.verifier, users.indexer, firstAmountToThaw);
25+
_thawEscrow(users.verifier, users.indexer, secondAmountToThaw);
26+
27+
(, address msgSender, ) = vm.readCallers();
28+
(, uint256 amountThawing, uint256 thawEndTimestamp) = escrow.escrowAccounts(msgSender, users.verifier, users.indexer);
29+
assertEq(amountThawing, secondAmountToThaw);
30+
assertEq(thawEndTimestamp, block.timestamp + withdrawEscrowThawingPeriod);
31+
}
32+
33+
function testThaw_Tokens_RevertWhen_AmountIsZero() public useGateway {
34+
bytes memory expectedError = abi.encodeWithSignature("PaymentsEscrowInvalidZeroTokens()");
2235
vm.expectRevert(expectedError);
2336
escrow.thaw(users.verifier, users.indexer, 0);
2437
}
@@ -28,17 +41,23 @@ contract GraphEscrowThawTest is GraphEscrowTest {
2841
uint256 overAmount
2942
) public useGateway useDeposit(amount) {
3043
overAmount = bound(overAmount, amount + 1, type(uint256).max);
31-
bytes memory expectedError = abi.encodeWithSignature("PaymentsEscrowInsufficientBalance(uint256,uint256)", amount, overAmount);
44+
bytes memory expectedError = abi.encodeWithSignature(
45+
"PaymentsEscrowInsufficientBalance(uint256,uint256)",
46+
amount,
47+
overAmount
48+
);
3249
vm.expectRevert(expectedError);
3350
escrow.thaw(users.verifier, users.indexer, overAmount);
3451
}
3552

3653
function testThaw_CancelRequest(uint256 amount) public useGateway useDeposit(amount) {
37-
escrow.thaw(users.verifier, users.indexer, amount);
38-
escrow.thaw(users.verifier, users.indexer, 0);
54+
_thawEscrow(users.verifier, users.indexer, amount);
55+
_cancelThawEscrow(users.verifier, users.indexer);
56+
}
3957

40-
(, uint256 amountThawing,uint256 thawEndTimestamp) = escrow.escrowAccounts(users.gateway, users.verifier, users.indexer);
41-
assertEq(amountThawing, 0);
42-
assertEq(thawEndTimestamp, 0);
58+
function testThaw_CancelRequest_RevertWhen_NoThawing(uint256 amount) public useGateway useDeposit(amount) {
59+
bytes memory expectedError = abi.encodeWithSignature("PaymentsEscrowNotThawing()");
60+
vm.expectRevert(expectedError);
61+
escrow.cancelThaw(users.verifier, users.indexer);
4362
}
44-
}
63+
}

0 commit comments

Comments
 (0)