Skip to content

Commit ee2d18e

Browse files
committed
cancellation tests
1 parent 294045c commit ee2d18e

8 files changed

Lines changed: 186 additions & 94 deletions

offchain/deposit_signal_proof.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ async fn main() -> Result<()> {
2222
let data = bytes!();
2323
let sender = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
2424
let amount = U256::from(4000000000000000000_u128);
25-
let relayer = Address::ZERO;
2625

2726
let (provider, _, _) = get_provider()?;
2827

@@ -38,7 +37,10 @@ async fn main() -> Result<()> {
3837
println!("Deployed ETH bridge at address: {}", eth_bridge.address());
3938

4039
println!("Sending ETH deposit...");
41-
let builder = eth_bridge.deposit(sender, data, bytes!()).value(amount);
40+
let zero_canceler = Address::ZERO;
41+
let builder = eth_bridge
42+
.deposit(sender, data, bytes!(), zero_canceler)
43+
.value(amount);
4244
let tx = builder.send().await?.get_receipt().await?;
4345

4446
// Get deposit ID from the transaction receipt logs

offchain/sample_deposit_proof.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ mod utils;
77
use utils::{deploy_eth_bridge, deploy_signal_service, get_proofs, get_provider, SignalProof};
88

99
use alloy::hex::decode;
10-
use alloy::primitives::{Address, Bytes, FixedBytes, U256};
10+
use alloy::primitives::{address, Address, Bytes, FixedBytes, U256};
1111
use std::fs;
1212

1313
fn expand_vector(vec: Vec<Bytes>, name: &str) -> String {
@@ -28,6 +28,7 @@ fn create_deposit_call(
2828
amount: U256,
2929
data: &str,
3030
context: &str,
31+
canceler: &str,
3132
id: &FixedBytes<32>,
3233
) -> String {
3334
let mut result = String::new();
@@ -50,6 +51,7 @@ fn create_deposit_call(
5051
result += format!("\t\tdeposit.amount = {};\n", amount).as_str();
5152
result += format!("\t\tdeposit.data = bytes(hex\"{}\");\n", data).as_str();
5253
result += format!("\t\tdeposit.context = bytes(hex\"{}\");\n", context).as_str();
54+
result += format!("\t\tdeposit.canceler = address({});\n", canceler).as_str();
5355
result += format!("\t\t_createDeposit(\n\t\t\taccountProof,\n\t\t\tstorageProof,\n\t\t\tdeposit,\n\t\t\tbytes32({}),\n\t\t\tbytes32({})\n\t\t);\n", proof.slot, id).as_str();
5456
return result;
5557
}
@@ -76,7 +78,8 @@ fn deposit_specification() -> Vec<DepositSpecification> {
7678
"5932a71200000000000000000000000000000000000000000000000000000000000004d2", // (valid) call to `someNonPayableFunction(1234)`
7779
];
7880

79-
let zero_canceler = Address::ZERO;
81+
// _randomAddress("canceler");
82+
let canceler = address!("0xf9f5C5411F0bEf1880cE3B051BD14196479764D2");
8083

8184
let mut specifications = vec![];
8285
for amount in amounts {
@@ -86,7 +89,7 @@ fn deposit_specification() -> Vec<DepositSpecification> {
8689
amount: U256::from(amount),
8790
data: data.to_string(),
8891
context: String::from(""),
89-
canceler: zero_canceler,
92+
canceler,
9093
});
9194
}
9295
}
@@ -145,6 +148,7 @@ async fn main() -> Result<()> {
145148
d.amount,
146149
d.data.as_str(),
147150
d.context.as_str(),
151+
&d.canceler.to_string(),
148152
id,
149153
)
150154
.as_str();
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
import {CrossChainDepositExists} from "./CrossChainDepositExists.t.sol";
5+
import {IETHBridge} from "src/protocol/IETHBridge.sol";
6+
7+
/// This contract describes behaviours that should be valid when the deposit is cancellable.
8+
abstract contract DepositIsCancellable is CrossChainDepositExists {
9+
function test_cancelDeposit_shouldSucceed() public {
10+
IETHBridge.ETHDeposit memory deposit = sampleDepositProof.getEthDeposit(_depositIdx());
11+
bytes memory proof = abi.encode(sampleDepositProof.getDepositSignalProof(_depositIdx()));
12+
vm.prank(cancellerAddress);
13+
bridge.cancelDeposit(deposit, cancellationRecipient, HEIGHT, proof);
14+
}
15+
16+
function test_cancelDeposit_shouldSetClaimedFlag() public {
17+
IETHBridge.ETHDeposit memory deposit = sampleDepositProof.getEthDeposit(_depositIdx());
18+
bytes memory proof = abi.encode(sampleDepositProof.getDepositSignalProof(_depositIdx()));
19+
(, bytes32 id) = sampleDepositProof.getDepositInternals(_depositIdx());
20+
21+
assertFalse(bridge.processed(id), "deposit already marked as claimed");
22+
23+
vm.prank(cancellerAddress);
24+
bridge.cancelDeposit(deposit, cancellationRecipient, HEIGHT, proof);
25+
assertTrue(bridge.processed(id), "deposit not marked as claimed");
26+
}
27+
28+
function test_cancelDeposit_shouldEmitEvent() public {
29+
IETHBridge.ETHDeposit memory deposit = sampleDepositProof.getEthDeposit(_depositIdx());
30+
bytes memory proof = abi.encode(sampleDepositProof.getDepositSignalProof(_depositIdx()));
31+
(, bytes32 id) = sampleDepositProof.getDepositInternals(_depositIdx());
32+
33+
vm.expectEmit();
34+
emit IETHBridge.DepositCancelled(id, cancellationRecipient);
35+
36+
vm.prank(cancellerAddress);
37+
bridge.cancelDeposit(deposit, cancellationRecipient, HEIGHT, proof);
38+
}
39+
40+
function test_cancelDeposit_shouldSendETH() public {
41+
IETHBridge.ETHDeposit memory deposit = sampleDepositProof.getEthDeposit(_depositIdx());
42+
bytes memory proof = abi.encode(sampleDepositProof.getDepositSignalProof(_depositIdx()));
43+
44+
uint256 initialCancellationRecipientBalance = cancellationRecipient.balance;
45+
uint256 initialRecipientBalance = recipient.balance;
46+
uint256 initialBridgeBalance = address(bridge).balance;
47+
48+
vm.prank(cancellerAddress);
49+
bridge.cancelDeposit(deposit, cancellationRecipient, HEIGHT, proof);
50+
assertEq(recipient.balance, initialRecipientBalance, "recipient balance mismatch");
51+
assertEq(
52+
cancellationRecipient.balance,
53+
initialCancellationRecipientBalance + deposit.amount,
54+
"cancel recipient balance mismatch"
55+
);
56+
assertEq(address(bridge).balance, initialBridgeBalance - deposit.amount, "bridge balance mismatch");
57+
}
58+
59+
function test_cancelDeposit_shouldRevertWhen_CancellerIsNotCaller() public {
60+
IETHBridge.ETHDeposit memory deposit = sampleDepositProof.getEthDeposit(_depositIdx());
61+
bytes memory proof = abi.encode(sampleDepositProof.getDepositSignalProof(_depositIdx()));
62+
63+
vm.expectRevert(IETHBridge.OnlyCanceler.selector);
64+
vm.prank(_randomAddress("notCanceller"));
65+
bridge.cancelDeposit(deposit, cancellationRecipient, HEIGHT, proof);
66+
}
67+
}

test/ETHBridge/CrossChainDepositExists.t.sol

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ abstract contract CrossChainDepositExists is UniversalTest {
1515
// the sample deposit is to this address
1616
address recipient = _randomAddress("recipient");
1717

18+
// the recipient that receives the cancelled deposit
19+
address cancellationRecipient = _randomAddress("cancellationRecipient");
20+
1821
uint256 HEIGHT = 1;
1922

2023
function setUp() public virtual override {

test/ETHBridge/EnumeratedScenarios.t.sol

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.28;
33

4+
import {DepositIsCancellable} from "./CancellableScenarios.t.sol";
45
import {BridgeHasNoEther, BridgeSufficientlyCapitalized} from "./CapitalizationScenarios.t.sol";
56
import {DepositIsClaimable, DepositIsNotClaimable} from "./ClaimableScenarios.t.sol";
67
import {DepositIsInvalidContractCall, DepositIsValidContractCall} from "./ContractCallValidityScenarios.t.sol";
@@ -41,6 +42,17 @@ contract SimpleDepositToEOA is
4142
}
4243
}
4344

45+
contract CancelDepositToEOA is
46+
NonzeroETH_NoCalldata,
47+
RecipientIsAnEOA,
48+
BridgeSufficientlyCapitalized,
49+
DepositIsCancellable
50+
{
51+
function setUp() public override(CrossChainDepositExists, BridgeSufficientlyCapitalized) {
52+
super.setUp();
53+
}
54+
}
55+
4456
// Same transfer as above, but the bridge does not have ETH. It should fail.
4557
contract SimpleDepositToEOA_BridgeUndercollateralized is
4658
NonzeroETH_NoCalldata,

test/ETHBridge/InitialState.t.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {SampleDepositProof} from "./SampleDepositProof.t.sol";
77
import {ETHBridge} from "src/protocol/ETHBridge.sol";
88
import {SignalService} from "src/protocol/SignalService.sol";
99

10+
import {console} from "forge-std/console.sol";
11+
1012
abstract contract InitialState is Test {
1113
ETHBridge bridge;
1214
SignalService signalService;
@@ -16,7 +18,7 @@ abstract contract InitialState is Test {
1618
bytes anyRelayer = new bytes(0);
1719

1820
// zero address means deposit is uncancellable
19-
address nonCancellableAddress = address(0);
21+
address cancellerAddress = _randomAddress("canceler");
2022

2123
address trustedCommitmentPublisher = _randomAddress("trustedCommitmentPublisher");
2224

0 commit comments

Comments
 (0)