Skip to content

Commit 66c5e8f

Browse files
thasmi21jaybuidl
authored andcommitted
feat(arbitration): implement SafeSend library for secure ETH transfers
1 parent e9ed4ba commit 66c5e8f

17 files changed

+114
-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-ruler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
3232
deployer, // governor
3333
pnk.target,
3434
[minStake, alpha, feeForJuror, jurorsForCourtJump],
35+
weth.target,
3536
],
3637
log: true,
3738
});

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

Lines changed: 2 additions & 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

@@ -59,6 +59,7 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
5959
[minStake, alpha, feeForJuror, jurorsForCourtJump],
6060
[0, 0, 0, 10], // evidencePeriod, commitPeriod, votePeriod, appealPeriod
6161
sortitionModule.address,
62+
weth.target,
6263
],
6364
log: true,
6465
}); // nonce+2 (implementation), nonce+3 (proxy)

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 address for WETH tranfers.
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 address for WETH tranfers.
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 address for WETH tranfers.
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,12 @@
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;
1012
// ************************************* //
1113
// * Enums / Structs * //
1214
// ************************************* //
@@ -60,6 +62,8 @@ contract KlerosGovernor is IArbitrableV2 {
6062
Submission[] public submissions; // Stores all created transaction lists. submissions[_listID].
6163
Session[] public sessions; // Stores all submitting sessions. sessions[_session].
6264

65+
address public wNative; // The address for WETH tranfers.
66+
6367
// ************************************* //
6468
// * Function Modifiers * //
6569
// ************************************* //
@@ -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 address of the WETH used by SafeSend for fallback transfers.
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/devtools/KlerosCoreRuler.sol

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pragma solidity ^0.8.24;
44

55
import {IArbitrableV2, IArbitratorV2} from "../interfaces/IArbitratorV2.sol";
66
import {SafeERC20, IERC20} from "../../libraries/SafeERC20.sol";
7+
import {SafeSend} from "../../libraries/SafeSend.sol";
78
import {UUPSProxiable} from "../../proxy/UUPSProxiable.sol";
89
import {Initializable} from "../../proxy/Initializable.sol";
910
import "../../libraries/Constants.sol";
@@ -12,6 +13,7 @@ import "../../libraries/Constants.sol";
1213
/// Core arbitrator contract for development and testing purposes.
1314
contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
1415
using SafeERC20 for IERC20;
16+
using SafeSend for address payable;
1517

1618
string public constant override version = "0.8.0";
1719

@@ -93,6 +95,7 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
9395
mapping(IArbitrableV2 arbitrable => address ruler) public rulers; // The ruler of each arbitrable contract.
9496
mapping(IArbitrableV2 arbitrable => RulerSettings) public settings; // The settings of each arbitrable contract.
9597
mapping(uint256 disputeID => RulingResult) public rulingResults; // The ruling results of each dispute.
98+
address public wNative; // The address for WETH tranfers.
9699

97100
// ************************************* //
98101
// * Events * //
@@ -175,13 +178,16 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
175178
/// @param _governor The governor's address.
176179
/// @param _pinakion The address of the token contract.
177180
/// @param _courtParameters Numeric parameters of General court (minStake, alpha, feeForJuror and jurorsForCourtJump respectively).
181+
/// @param _wNative The address of the WETH used by SafeSend for fallback transfers.
178182
function initialize(
179183
address _governor,
180184
IERC20 _pinakion,
181-
uint256[4] memory _courtParameters
185+
uint256[4] memory _courtParameters,
186+
address _wNative
182187
) external reinitializer(1) {
183188
governor = _governor;
184189
pinakion = _pinakion;
190+
wNative = _wNative;
185191

186192
// FORKING_COURT
187193
// TODO: Fill the properties for the Forking court, emit CourtCreated.
@@ -525,7 +531,7 @@ contract KlerosCoreRuler is IArbitratorV2, UUPSProxiable, Initializable {
525531
round.sumFeeRewardPaid += feeReward;
526532
if (round.feeToken == NATIVE_CURRENCY) {
527533
// The dispute fees were paid in ETH
528-
payable(account).send(feeReward);
534+
payable(account).safeSend(feeReward, wNative);
529535
} else {
530536
// The dispute fees were paid in ERC20
531537
round.feeToken.safeTransfer(account, feeReward);

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 address for WETH tranfers.
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) {

0 commit comments

Comments
 (0)