Skip to content

Commit 6786c29

Browse files
authored
Merge pull request #2041 from kleros/fix/ETH-transfer
Contracts: use SafeSend for ETH transfers
2 parents 05c3f28 + c5a894a commit 6786c29

15 files changed

+125
-37
lines changed

contracts/deploy/00-home-chain-arbitration-neo.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
3232
const disputeKit = await deployUpgradable(deployments, "DisputeKitClassicNeo", {
3333
from: deployer,
3434
contract: "DisputeKitClassic",
35-
args: [deployer, ZeroAddress],
35+
args: [deployer, ZeroAddress, weth.target],
3636
log: true,
3737
});
3838

@@ -81,6 +81,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
8181
ethers.toBeHex(5), // Extra data for sortition module will return the default value of K
8282
sortitionModule.address,
8383
nft.target,
84+
weth.target,
8485
],
8586
log: true,
8687
}); // nonce+2 (implementation), nonce+3 (proxy)

contracts/deploy/00-home-chain-arbitration-university.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
2727
const disputeKit = await deployUpgradable(deployments, "DisputeKitClassicUniversity", {
2828
from: deployer,
2929
contract: "DisputeKitClassic",
30-
args: [deployer, ZeroAddress],
30+
args: [deployer, ZeroAddress, weth.target],
3131
log: true,
3232
});
3333

contracts/deploy/00-home-chain-arbitration.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
3737

3838
const disputeKit = await deployUpgradable(deployments, "DisputeKitClassic", {
3939
from: deployer,
40-
args: [deployer, ZeroAddress],
40+
args: [deployer, ZeroAddress, weth.target],
4141
log: true,
4242
});
4343

@@ -74,6 +74,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
7474
[0, 0, 0, 10], // evidencePeriod, commitPeriod, votePeriod, appealPeriod
7575
ethers.toBeHex(5), // Extra data for sortition module will return the default value of K
7676
sortitionModule.address,
77+
weth.target,
7778
],
7879
log: true,
7980
}); // nonce+2 (implementation), nonce+3 (proxy)
@@ -105,23 +106,23 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
105106
// Extra dispute kits
106107
const disputeKitShutter = await deployUpgradable(deployments, "DisputeKitShutter", {
107108
from: deployer,
108-
args: [deployer, core.target],
109+
args: [deployer, core.target, weth.target],
109110
log: true,
110111
});
111112
await core.addNewDisputeKit(disputeKitShutter.address);
112113
await core.enableDisputeKits(Courts.GENERAL, [2], true); // enable disputeKitShutter on the General Court
113114

114115
const disputeKitGated = await deployUpgradable(deployments, "DisputeKitGated", {
115116
from: deployer,
116-
args: [deployer, core.target],
117+
args: [deployer, core.target, weth.target],
117118
log: true,
118119
});
119120
await core.addNewDisputeKit(disputeKitGated.address);
120121
await core.enableDisputeKits(Courts.GENERAL, [3], true); // enable disputeKitGated on the General Court
121122

122123
const disputeKitGatedShutter = await deployUpgradable(deployments, "DisputeKitGatedShutter", {
123124
from: deployer,
124-
args: [deployer, core.target],
125+
args: [deployer, core.target, weth.target],
125126
log: true,
126127
});
127128
await core.addNewDisputeKit(disputeKitGatedShutter.address);

contracts/src/arbitration/KlerosCore.sol

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ contract KlerosCore is KlerosCoreBase {
3030
/// @param _timesPerPeriod The `timesPerPeriod` property value of the general court.
3131
/// @param _sortitionExtraData The extra data for sortition module.
3232
/// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.
33+
/// @param _wNative The wrapped native token address, typically wETH.
3334
function initialize(
3435
address _governor,
3536
address _guardian,
@@ -40,7 +41,8 @@ contract KlerosCore is KlerosCoreBase {
4041
uint256[4] memory _courtParameters,
4142
uint256[4] memory _timesPerPeriod,
4243
bytes memory _sortitionExtraData,
43-
ISortitionModule _sortitionModuleAddress
44+
ISortitionModule _sortitionModuleAddress,
45+
address _wNative
4446
) external reinitializer(1) {
4547
__KlerosCoreBase_initialize(
4648
_governor,
@@ -52,7 +54,8 @@ contract KlerosCore is KlerosCoreBase {
5254
_courtParameters,
5355
_timesPerPeriod,
5456
_sortitionExtraData,
55-
_sortitionModuleAddress
57+
_sortitionModuleAddress,
58+
_wNative
5659
);
5760
}
5861

contracts/src/arbitration/KlerosCoreBase.sol

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import {ISortitionModule} from "./interfaces/ISortitionModule.sol";
88
import {Initializable} from "../proxy/Initializable.sol";
99
import {UUPSProxiable} from "../proxy/UUPSProxiable.sol";
1010
import {SafeERC20, IERC20} from "../libraries/SafeERC20.sol";
11+
import {SafeSend} from "../libraries/SafeSend.sol";
1112
import "../libraries/Constants.sol";
1213

1314
/// @title KlerosCoreBase
1415
/// Core arbitrator contract for Kleros v2.
1516
/// Note that this contract trusts the PNK token, the dispute kit and the sortition module contracts.
1617
abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable {
1718
using SafeERC20 for IERC20;
19+
using SafeSend for address payable;
1820

1921
// ************************************* //
2022
// * Enums / Structs * //
@@ -99,6 +101,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
99101
Dispute[] public disputes; // The disputes.
100102
mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.
101103
bool public paused; // Whether asset withdrawals are paused.
104+
address public wNative; // The wrapped native token for safeSend().
102105

103106
// ************************************* //
104107
// * Events * //
@@ -199,13 +202,15 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
199202
uint256[4] memory _courtParameters,
200203
uint256[4] memory _timesPerPeriod,
201204
bytes memory _sortitionExtraData,
202-
ISortitionModule _sortitionModuleAddress
205+
ISortitionModule _sortitionModuleAddress,
206+
address _wNative
203207
) internal onlyInitializing {
204208
governor = _governor;
205209
guardian = _guardian;
206210
pinakion = _pinakion;
207211
jurorProsecutionModule = _jurorProsecutionModule;
208212
sortitionModule = _sortitionModuleAddress;
213+
wNative = _wNative;
209214

210215
// NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a dispute kit is not supported.
211216
disputeKits.push();
@@ -802,7 +807,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
802807
// No one was coherent, send the rewards to the governor.
803808
if (round.feeToken == NATIVE_CURRENCY) {
804809
// The dispute fees were paid in ETH
805-
payable(governor).send(round.totalFeesForJurors);
810+
payable(governor).safeSend(round.totalFeesForJurors, wNative);
806811
} else {
807812
// The dispute fees were paid in ERC20
808813
round.feeToken.safeTransfer(governor, round.totalFeesForJurors);
@@ -854,7 +859,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
854859
pinakion.safeTransfer(account, pnkReward);
855860
if (round.feeToken == NATIVE_CURRENCY) {
856861
// The dispute fees were paid in ETH
857-
payable(account).send(feeReward);
862+
payable(account).safeSend(feeReward, wNative);
858863
} else {
859864
// The dispute fees were paid in ERC20
860865
round.feeToken.safeTransfer(account, feeReward);
@@ -880,7 +885,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
880885
if (leftoverFeeReward != 0) {
881886
if (round.feeToken == NATIVE_CURRENCY) {
882887
// The dispute fees were paid in ETH
883-
payable(governor).send(leftoverFeeReward);
888+
payable(governor).safeSend(leftoverFeeReward, wNative);
884889
} else {
885890
// The dispute fees were paid in ERC20
886891
round.feeToken.safeTransfer(governor, leftoverFeeReward);

contracts/src/arbitration/KlerosCoreNeo.sol

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ contract KlerosCoreNeo is KlerosCoreBase {
3939
/// @param _sortitionExtraData The extra data for sortition module.
4040
/// @param _sortitionModuleAddress The sortition module responsible for sortition of the jurors.
4141
/// @param _jurorNft NFT contract to vet the jurors.
42+
/// @param _wNative The wrapped native token address, typically wETH.
4243
function initialize(
4344
address _governor,
4445
address _guardian,
@@ -50,7 +51,8 @@ contract KlerosCoreNeo is KlerosCoreBase {
5051
uint256[4] memory _timesPerPeriod,
5152
bytes memory _sortitionExtraData,
5253
ISortitionModule _sortitionModuleAddress,
53-
IERC721 _jurorNft
54+
IERC721 _jurorNft,
55+
address _wNative
5456
) external reinitializer(2) {
5557
__KlerosCoreBase_initialize(
5658
_governor,
@@ -62,7 +64,8 @@ contract KlerosCoreNeo is KlerosCoreBase {
6264
_courtParameters,
6365
_timesPerPeriod,
6466
_sortitionExtraData,
65-
_sortitionModuleAddress
67+
_sortitionModuleAddress,
68+
_wNative
6669
);
6770
jurorNft = _jurorNft;
6871
}

contracts/src/arbitration/KlerosGovernor.sol

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
pragma solidity ^0.8.24;
44

55
import {IArbitrableV2, IArbitratorV2} from "./interfaces/IArbitrableV2.sol";
6+
import {SafeSend} from "../libraries/SafeSend.sol";
67
import "./interfaces/IDisputeTemplateRegistry.sol";
78

89
/// @title KlerosGovernor for V2. Note that appeal functionality and evidence submission will be handled by the court.
910
contract KlerosGovernor is IArbitrableV2 {
11+
using SafeSend for address payable;
12+
1013
// ************************************* //
1114
// * Enums / Structs * //
1215
// ************************************* //
@@ -46,6 +49,7 @@ contract KlerosGovernor is IArbitrableV2 {
4649

4750
IArbitratorV2 public arbitrator; // Arbitrator contract.
4851
bytes public arbitratorExtraData; // Extra data for arbitrator.
52+
address public wNative; // The wrapped native token for safeSend().
4953
IDisputeTemplateRegistry public templateRegistry; // The dispute template registry.
5054
uint256 public templateId; // The current dispute template identifier.
5155

@@ -111,6 +115,7 @@ contract KlerosGovernor is IArbitrableV2 {
111115
/// @param _submissionTimeout Time in seconds allocated for submitting transaction list.
112116
/// @param _executionTimeout Time in seconds after approval that allows to execute transactions of the approved list.
113117
/// @param _withdrawTimeout Time in seconds after submission that allows to withdraw submitted list.
118+
/// @param _wNative The wrapped native token address, typically wETH.
114119
constructor(
115120
IArbitratorV2 _arbitrator,
116121
bytes memory _arbitratorExtraData,
@@ -119,10 +124,12 @@ contract KlerosGovernor is IArbitrableV2 {
119124
uint256 _submissionBaseDeposit,
120125
uint256 _submissionTimeout,
121126
uint256 _executionTimeout,
122-
uint256 _withdrawTimeout
127+
uint256 _withdrawTimeout,
128+
address _wNative
123129
) {
124130
arbitrator = _arbitrator;
125131
arbitratorExtraData = _arbitratorExtraData;
132+
wNative = _wNative;
126133

127134
lastApprovalTime = block.timestamp;
128135
submissionBaseDeposit = _submissionBaseDeposit;
@@ -237,7 +244,7 @@ contract KlerosGovernor is IArbitrableV2 {
237244
emit ListSubmitted(submissions.length - 1, msg.sender, sessions.length - 1, _description);
238245

239246
uint256 remainder = msg.value - submission.deposit;
240-
if (remainder > 0) payable(msg.sender).send(remainder);
247+
if (remainder > 0) payable(msg.sender).safeSend(remainder, wNative);
241248

242249
reservedETH += submission.deposit;
243250
}
@@ -277,7 +284,7 @@ contract KlerosGovernor is IArbitrableV2 {
277284
submission.approvalTime = block.timestamp;
278285
uint256 sumDeposit = session.sumDeposit;
279286
session.sumDeposit = 0;
280-
submission.submitter.send(sumDeposit);
287+
submission.submitter.safeSend(sumDeposit, wNative);
281288
lastApprovalTime = block.timestamp;
282289
session.status = Status.Resolved;
283290
sessions.push();
@@ -311,7 +318,7 @@ contract KlerosGovernor is IArbitrableV2 {
311318
Submission storage submission = submissions[session.submittedLists[_ruling - 1]];
312319
submission.approved = true;
313320
submission.approvalTime = block.timestamp;
314-
submission.submitter.send(session.sumDeposit);
321+
submission.submitter.safeSend(session.sumDeposit, wNative);
315322
}
316323
// If the ruling is "0" the reserved funds of this session become expendable.
317324
reservedETH -= session.sumDeposit;

contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ contract DisputeKitClassic is DisputeKitClassicBase {
2525
/// @dev Initializer.
2626
/// @param _governor The governor's address.
2727
/// @param _core The KlerosCore arbitrator.
28-
function initialize(address _governor, KlerosCore _core) external reinitializer(1) {
29-
__DisputeKitClassicBase_initialize(_governor, _core);
28+
/// @param _wNative The wrapped native token address, typically wETH.
29+
function initialize(address _governor, KlerosCore _core, address _wNative) external reinitializer(1) {
30+
__DisputeKitClassicBase_initialize(_governor, _core, _wNative);
3031
}
3132

3233
function initialize7() external reinitializer(7) {

contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pragma solidity ^0.8.24;
55
import {KlerosCore, KlerosCoreBase, IDisputeKit, ISortitionModule} from "../KlerosCore.sol";
66
import {Initializable} from "../../proxy/Initializable.sol";
77
import {UUPSProxiable} from "../../proxy/UUPSProxiable.sol";
8+
import {SafeSend} from "../../libraries/SafeSend.sol";
89

910
/// @title DisputeKitClassicBase
1011
/// Abstract Dispute kit classic implementation of the Kleros v1 features including:
@@ -13,6 +14,8 @@ import {UUPSProxiable} from "../../proxy/UUPSProxiable.sol";
1314
/// - an incentive system: equal split between coherent votes,
1415
/// - an appeal system: fund 2 choices only, vote on any choice.
1516
abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxiable {
17+
using SafeSend for address payable;
18+
1619
// ************************************* //
1720
// * Structs * //
1821
// ************************************* //
@@ -64,6 +67,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
6467
mapping(uint256 localDisputeID => mapping(uint256 localRoundID => mapping(address drawnAddress => bool)))
6568
public alreadyDrawn; // True if the address has already been drawn, false by default. To be added to the Round struct when fully redeploying rather than upgrading.
6669
mapping(uint256 coreDisputeID => bool) public coreDisputeIDToActive; // True if this dispute kit is active for this core dispute ID.
70+
address public wNative; // The wrapped native token for safeSend().
6771

6872
// ************************************* //
6973
// * Events * //
@@ -142,9 +146,15 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
142146
/// @dev Initializer.
143147
/// @param _governor The governor's address.
144148
/// @param _core The KlerosCore arbitrator.
145-
function __DisputeKitClassicBase_initialize(address _governor, KlerosCore _core) internal onlyInitializing {
149+
/// @param _wNative The wrapped native token address, typically wETH.
150+
function __DisputeKitClassicBase_initialize(
151+
address _governor,
152+
KlerosCore _core,
153+
address _wNative
154+
) internal onlyInitializing {
146155
governor = _governor;
147156
core = _core;
157+
wNative = _wNative;
148158
}
149159

150160
// ************************ //
@@ -413,7 +423,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
413423
core.appeal{value: appealCost}(_coreDisputeID, dispute.numberOfChoices, dispute.extraData);
414424
}
415425

416-
if (msg.value > contribution) payable(msg.sender).send(msg.value - contribution);
426+
if (msg.value > contribution) payable(msg.sender).safeSend(msg.value - contribution, wNative);
417427
}
418428

419429
/// @dev Allows those contributors who attempted to fund an appeal round to withdraw any reimbursable fees or rewards after the dispute gets resolved.
@@ -458,7 +468,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
458468
round.contributions[_beneficiary][_choice] = 0;
459469

460470
if (amount != 0) {
461-
_beneficiary.send(amount); // Deliberate use of send to prevent reverting fallback. It's the user's responsibility to accept ETH.
471+
_beneficiary.safeSend(amount, wNative);
462472
emit Withdrawal(_coreDisputeID, _coreRoundID, _choice, _beneficiary, amount);
463473
}
464474
}

contracts/src/arbitration/dispute-kits/DisputeKitGated.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ contract DisputeKitGated is DisputeKitClassicBase {
4141
/// @dev Initializer.
4242
/// @param _governor The governor's address.
4343
/// @param _core The KlerosCore arbitrator.
44-
function initialize(address _governor, KlerosCore _core) external reinitializer(1) {
45-
__DisputeKitClassicBase_initialize(_governor, _core);
44+
/// @param _wNative The wrapped native token address, typically wETH.
45+
function initialize(address _governor, KlerosCore _core, address _wNative) external reinitializer(1) {
46+
__DisputeKitClassicBase_initialize(_governor, _core, _wNative);
4647
}
4748

4849
function initialize7() external reinitializer(7) {

0 commit comments

Comments
 (0)