Skip to content

Commit 1dbfedf

Browse files
committed
feat: multi-dimensional degree of coherence for reward/penalties/pnk/eth
1 parent be33847 commit 1dbfedf

File tree

6 files changed

+130
-46
lines changed

6 files changed

+130
-46
lines changed

contracts/src/arbitration/KlerosCoreBase.sol

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
767767
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
768768

769769
// [0, 1] value that determines how coherent the juror was in this round, in basis points.
770-
uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(
770+
uint256 coherence = disputeKit.getDegreeOfCoherencePenalty(
771771
_params.disputeID,
772772
_params.round,
773773
_params.repartition,
@@ -776,12 +776,12 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
776776
);
777777

778778
// Guard against degree exceeding 1, though it should be ensured by the dispute kit.
779-
if (degreeOfCoherence > ONE_BASIS_POINT) {
780-
degreeOfCoherence = ONE_BASIS_POINT;
779+
if (coherence > ONE_BASIS_POINT) {
780+
coherence = ONE_BASIS_POINT;
781781
}
782782

783783
// Fully coherent jurors won't be penalized.
784-
uint256 penalty = (round.pnkAtStakePerJuror * (ONE_BASIS_POINT - degreeOfCoherence)) / ONE_BASIS_POINT;
784+
uint256 penalty = (round.pnkAtStakePerJuror * (ONE_BASIS_POINT - coherence)) / ONE_BASIS_POINT;
785785

786786
// Unlock the PNKs affected by the penalty
787787
address account = round.drawnJurors[_params.repartition];
@@ -794,7 +794,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
794794
account,
795795
_params.disputeID,
796796
_params.round,
797-
degreeOfCoherence,
797+
coherence,
798798
-int256(availablePenalty),
799799
0,
800800
round.feeToken
@@ -826,7 +826,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
826826
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
827827

828828
// [0, 1] value that determines how coherent the juror was in this round, in basis points.
829-
uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(
829+
(uint256 pnkCoherence, uint256 feeCoherence) = disputeKit.getDegreeOfCoherenceReward(
830830
_params.disputeID,
831831
_params.round,
832832
_params.repartition % _params.numberOfVotesInRound,
@@ -835,28 +835,31 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
835835
);
836836

837837
// Guard against degree exceeding 1, though it should be ensured by the dispute kit.
838-
if (degreeOfCoherence > ONE_BASIS_POINT) {
839-
degreeOfCoherence = ONE_BASIS_POINT;
838+
if (pnkCoherence > ONE_BASIS_POINT) {
839+
pnkCoherence = ONE_BASIS_POINT;
840+
}
841+
if (feeCoherence > ONE_BASIS_POINT) {
842+
feeCoherence = ONE_BASIS_POINT;
840843
}
841844

842845
address account = round.drawnJurors[_params.repartition % _params.numberOfVotesInRound];
843-
uint256 pnkLocked = _applyCoherence(round.pnkAtStakePerJuror, degreeOfCoherence);
846+
uint256 pnkLocked = _applyCoherence(round.pnkAtStakePerJuror, pnkCoherence);
844847

845848
// Release the rest of the PNKs of the juror for this round.
846849
sortitionModule.unlockStake(account, pnkLocked);
847850

848851
// Transfer the rewards
849-
uint256 pnkReward = _applyCoherence(_params.pnkPenaltiesInRound / _params.coherentCount, degreeOfCoherence);
852+
uint256 pnkReward = _applyCoherence(_params.pnkPenaltiesInRound / _params.coherentCount, pnkCoherence);
850853
round.sumPnkRewardPaid += pnkReward;
851-
uint256 feeReward = _applyCoherence(round.totalFeesForJurors / _params.coherentCount, degreeOfCoherence);
854+
uint256 feeReward = _applyCoherence(round.totalFeesForJurors / _params.coherentCount, feeCoherence);
852855
round.sumFeeRewardPaid += feeReward;
853856
pinakion.safeTransfer(account, pnkReward);
854857
_transferFeeToken(round.feeToken, payable(account), feeReward);
855858
emit TokenAndETHShift(
856859
account,
857860
_params.disputeID,
858861
_params.round,
859-
degreeOfCoherence,
862+
pnkCoherence,
860863
int256(pnkReward),
861864
int256(feeReward),
862865
round.feeToken
@@ -1059,10 +1062,10 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
10591062

10601063
/// @dev Applies degree of coherence to an amount
10611064
/// @param _amount The base amount to apply coherence to.
1062-
/// @param _degreeOfCoherence The degree of coherence in basis points.
1065+
/// @param _coherence The degree of coherence in basis points.
10631066
/// @return The amount after applying the degree of coherence.
1064-
function _applyCoherence(uint256 _amount, uint256 _degreeOfCoherence) internal pure returns (uint256) {
1065-
return (_amount * _degreeOfCoherence) / ONE_BASIS_POINT;
1067+
function _applyCoherence(uint256 _amount, uint256 _coherence) internal pure returns (uint256) {
1068+
return (_amount * _coherence) / ONE_BASIS_POINT;
10661069
}
10671070

10681071
/// @dev Calculates PNK at stake per juror based on court parameters

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

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -526,14 +526,39 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
526526
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
527527
/// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
528528
/// @param _voteID The ID of the vote.
529-
/// @return The degree of coherence in basis points.
530-
function getDegreeOfCoherence(
529+
/// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.
530+
/// @return feeCoherence The degree of coherence in basis points for the dispute fee reward.
531+
function getDegreeOfCoherenceReward(
531532
uint256 _coreDisputeID,
532533
uint256 _coreRoundID,
533534
uint256 _voteID,
534535
uint256 /* _feePerJuror */,
535536
uint256 /* _pnkAtStakePerJuror */
536-
) external view override returns (uint256) {
537+
) external view override returns (uint256 pnkCoherence, uint256 feeCoherence) {
538+
uint256 coherence = _getDegreeOfCoherence(_coreDisputeID, _coreRoundID, _voteID);
539+
return (coherence, coherence);
540+
}
541+
542+
/// @dev Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the penalty.
543+
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
544+
/// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
545+
/// @param _voteID The ID of the vote.
546+
/// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.
547+
function getDegreeOfCoherencePenalty(
548+
uint256 _coreDisputeID,
549+
uint256 _coreRoundID,
550+
uint256 _voteID,
551+
uint256 /* _feePerJuror */,
552+
uint256 /* _pnkAtStakePerJuror */
553+
) external view override returns (uint256 pnkCoherence) {
554+
return _getDegreeOfCoherence(_coreDisputeID, _coreRoundID, _voteID);
555+
}
556+
557+
function _getDegreeOfCoherence(
558+
uint256 _coreDisputeID,
559+
uint256 _coreRoundID,
560+
uint256 _voteID
561+
) internal view returns (uint256 coherence) {
537562
// In this contract this degree can be either 0 or 1, but in other dispute kits this value can be something in between.
538563
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
539564
Vote storage vote = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]].votes[_voteID];

contracts/src/arbitration/interfaces/IDisputeKit.sol

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,30 @@ interface IDisputeKit {
6767
/// @param _voteID The ID of the vote.
6868
/// @param _feePerJuror The fee per juror.
6969
/// @param _pnkAtStakePerJuror The PNK at stake per juror.
70-
/// @return The degree of coherence in basis points.
71-
function getDegreeOfCoherence(
70+
/// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.
71+
/// @return feeCoherence The degree of coherence in basis points for the dispute fee reward.
72+
function getDegreeOfCoherenceReward(
7273
uint256 _coreDisputeID,
7374
uint256 _coreRoundID,
7475
uint256 _voteID,
7576
uint256 _feePerJuror,
7677
uint256 _pnkAtStakePerJuror
77-
) external view returns (uint256);
78+
) external view returns (uint256 pnkCoherence, uint256 feeCoherence);
79+
80+
/// @dev Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the penalty.
81+
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
82+
/// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
83+
/// @param _voteID The ID of the vote.
84+
/// @param _feePerJuror The fee per juror.
85+
/// @param _pnkAtStakePerJuror The PNK at stake per juror.
86+
/// @return pnkCoherence The degree of coherence in basis points for the dispute PNK reward.
87+
function getDegreeOfCoherencePenalty(
88+
uint256 _coreDisputeID,
89+
uint256 _coreRoundID,
90+
uint256 _voteID,
91+
uint256 _feePerJuror,
92+
uint256 _pnkAtStakePerJuror
93+
) external view returns (uint256 pnkCoherence);
7894

7995
/// @dev Gets the number of jurors who are eligible to a reward in this round.
8096
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.

contracts/src/arbitration/university/KlerosCoreUniversity.sol

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import {IArbitrableV2, IArbitratorV2} from "../interfaces/IArbitratorV2.sol";
66
import {IDisputeKit} from "../interfaces/IDisputeKit.sol";
77
import {ISortitionModuleUniversity} from "./ISortitionModuleUniversity.sol";
88
import {SafeERC20, IERC20} from "../../libraries/SafeERC20.sol";
9-
import "../../libraries/Constants.sol";
109
import {UUPSProxiable} from "../../proxy/UUPSProxiable.sol";
1110
import {Initializable} from "../../proxy/Initializable.sol";
11+
import "../../libraries/Constants.sol";
1212

1313
/// @title KlerosCoreUniversity
1414
/// Core arbitrator contract for educational purposes.
@@ -87,7 +87,6 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
8787
// * Storage * //
8888
// ************************************* //
8989

90-
uint256 private constant ALPHA_DIVISOR = 1e4; // The number to divide `Court.alpha` by.
9190
uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.
9291

9392
address public governor; // The governor of the contract.
@@ -526,7 +525,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
526525
: convertEthToTokenAmount(_feeToken, court.feeForJuror);
527526
round.nbVotes = _feeAmount / feeForJuror;
528527
round.disputeKitID = disputeKitID;
529-
round.pnkAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;
528+
round.pnkAtStakePerJuror = (court.minStake * court.alpha) / ONE_BASIS_POINT;
530529
round.totalFeesForJurors = _feeAmount;
531530
round.feeToken = IERC20(_feeToken);
532531

@@ -655,7 +654,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
655654

656655
Court storage court = courts[newCourtID];
657656
extraRound.nbVotes = msg.value / court.feeForJuror; // As many votes that can be afforded by the provided funds.
658-
extraRound.pnkAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;
657+
extraRound.pnkAtStakePerJuror = (court.minStake * court.alpha) / ONE_BASIS_POINT;
659658
extraRound.totalFeesForJurors = msg.value;
660659
extraRound.disputeKitID = newDisputeKitID;
661660

@@ -754,20 +753,21 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
754753
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
755754

756755
// [0, 1] value that determines how coherent the juror was in this round, in basis points.
757-
uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(
756+
uint256 coherence = disputeKit.getDegreeOfCoherencePenalty(
758757
_params.disputeID,
759758
_params.round,
760759
_params.repartition,
761760
_params.feePerJurorInRound,
762761
_params.pnkAtStakePerJurorInRound
763762
);
764-
if (degreeOfCoherence > ALPHA_DIVISOR) {
765-
// Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.
766-
degreeOfCoherence = ALPHA_DIVISOR;
763+
764+
// Guard against degree exceeding 1, though it should be ensured by the dispute kit.
765+
if (coherence > ONE_BASIS_POINT) {
766+
coherence = ONE_BASIS_POINT;
767767
}
768768

769769
// Fully coherent jurors won't be penalized.
770-
uint256 penalty = (round.pnkAtStakePerJuror * (ALPHA_DIVISOR - degreeOfCoherence)) / ALPHA_DIVISOR;
770+
uint256 penalty = (round.pnkAtStakePerJuror * (ONE_BASIS_POINT - coherence)) / ONE_BASIS_POINT;
771771

772772
// Unlock the PNKs affected by the penalty
773773
address account = round.drawnJurors[_params.repartition];
@@ -780,7 +780,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
780780
account,
781781
_params.disputeID,
782782
_params.round,
783-
degreeOfCoherence,
783+
coherence,
784784
-int256(availablePenalty),
785785
0,
786786
round.feeToken
@@ -818,29 +818,32 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
818818
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
819819

820820
// [0, 1] value that determines how coherent the juror was in this round, in basis points.
821-
uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(
821+
(uint256 pnkCoherence, uint256 feeCoherence) = disputeKit.getDegreeOfCoherenceReward(
822822
_params.disputeID,
823823
_params.round,
824824
_params.repartition % _params.numberOfVotesInRound,
825825
_params.feePerJurorInRound,
826826
_params.pnkAtStakePerJurorInRound
827827
);
828828

829-
// Make sure the degree doesn't exceed 1, though it should be ensured by the dispute kit.
830-
if (degreeOfCoherence > ALPHA_DIVISOR) {
831-
degreeOfCoherence = ALPHA_DIVISOR;
829+
// Guard against degree exceeding 1, though it should be ensured by the dispute kit.
830+
if (pnkCoherence > ONE_BASIS_POINT) {
831+
pnkCoherence = ONE_BASIS_POINT;
832+
}
833+
if (feeCoherence > ONE_BASIS_POINT) {
834+
feeCoherence = ONE_BASIS_POINT;
832835
}
833836

834837
address account = round.drawnJurors[_params.repartition % _params.numberOfVotesInRound];
835-
uint256 pnkLocked = (round.pnkAtStakePerJuror * degreeOfCoherence) / ALPHA_DIVISOR;
838+
uint256 pnkLocked = (round.pnkAtStakePerJuror * pnkCoherence) / ONE_BASIS_POINT;
836839

837840
// Release the rest of the PNKs of the juror for this round.
838841
sortitionModule.unlockStake(account, pnkLocked);
839842

840843
// Transfer the rewards
841-
uint256 pnkReward = ((_params.pnkPenaltiesInRound / _params.coherentCount) * degreeOfCoherence) / ALPHA_DIVISOR;
844+
uint256 pnkReward = ((_params.pnkPenaltiesInRound / _params.coherentCount) * pnkCoherence) / ONE_BASIS_POINT;
842845
round.sumPnkRewardPaid += pnkReward;
843-
uint256 feeReward = ((round.totalFeesForJurors / _params.coherentCount) * degreeOfCoherence) / ALPHA_DIVISOR;
846+
uint256 feeReward = ((round.totalFeesForJurors / _params.coherentCount) * feeCoherence) / ONE_BASIS_POINT;
844847
round.sumFeeRewardPaid += feeReward;
845848
pinakion.safeTransfer(account, pnkReward);
846849
if (round.feeToken == NATIVE_CURRENCY) {
@@ -854,7 +857,7 @@ contract KlerosCoreUniversity is IArbitratorV2, UUPSProxiable, Initializable {
854857
account,
855858
_params.disputeID,
856859
_params.round,
857-
degreeOfCoherence,
860+
pnkCoherence,
858861
int256(pnkReward),
859862
int256(feeReward),
860863
round.feeToken

contracts/src/kleros-v1/kleros-liquid-xdai/xKlerosLiquidV2.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,6 @@ contract xKlerosLiquidV2 is Initializable, ITokenController, IArbitratorV2 {
141141
uint256 public constant MAX_STAKE_PATHS = 4; // The maximum number of stake paths a juror can have.
142142
uint256 public constant DEFAULT_NB_OF_JURORS = 3; // The default number of jurors in a dispute.
143143
uint256 public constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.
144-
uint256 public constant ALPHA_DIVISOR = 1e4; // The number to divide `Court.alpha` by.
145144
// General Contracts
146145
address public governor; // The governor of the contract.
147146
WrappedPinakion public pinakion; // The Pinakion token contract.

contracts/test/foundry/KlerosCore.t.sol

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,10 +2311,33 @@ contract KlerosCoreTest is Test {
23112311
core.unpause();
23122312

23132313
assertEq(disputeKit.getCoherentCount(disputeID, 0), 2, "Wrong coherent count");
2314+
2315+
uint256 pnkCoherence;
2316+
uint256 feeCoherence;
23142317
// dispute, round, voteID, feeForJuror (not used in classic DK), pnkPerJuror (not used in classic DK)
2315-
assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 0, 0, 0), 0, "Wrong degree of coherence 0 vote ID");
2316-
assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 1, 0, 0), 10000, "Wrong degree of coherence 1 vote ID");
2317-
assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 2, 0, 0), 10000, "Wrong degree of coherence 2 vote ID");
2318+
(pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 0, 0, 0);
2319+
assertEq(pnkCoherence, 0, "Wrong reward pnk coherence 0 vote ID");
2320+
assertEq(feeCoherence, 0, "Wrong reward fee coherence 0 vote ID");
2321+
2322+
(pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 1, 0, 0);
2323+
assertEq(pnkCoherence, 10000, "Wrong reward pnk coherence 1 vote ID");
2324+
assertEq(feeCoherence, 10000, "Wrong reward fee coherence 1 vote ID");
2325+
2326+
(pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 2, 0, 0);
2327+
assertEq(pnkCoherence, 10000, "Wrong reward pnk coherence 2 vote ID");
2328+
assertEq(feeCoherence, 10000, "Wrong reward fee coherence 2 vote ID");
2329+
2330+
assertEq(disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 0, 0, 0), 0, "Wrong penalty coherence 0 vote ID");
2331+
assertEq(
2332+
disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 1, 0, 0),
2333+
10000,
2334+
"Wrong penalty coherence 1 vote ID"
2335+
);
2336+
assertEq(
2337+
disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 2, 0, 0),
2338+
10000,
2339+
"Wrong penalty coherence 2 vote ID"
2340+
);
23182341

23192342
vm.expectEmit(true, true, true, true);
23202343
emit SortitionModuleBase.StakeLocked(staker1, 1000, true);
@@ -2398,10 +2421,25 @@ contract KlerosCoreTest is Test {
23982421
core.passPeriod(disputeID); // Execution
23992422

24002423
assertEq(disputeKit.getCoherentCount(disputeID, 0), 0, "Wrong coherent count");
2424+
2425+
uint256 pnkCoherence;
2426+
uint256 feeCoherence;
24012427
// dispute, round, voteID, feeForJuror (not used in classic DK), pnkPerJuror (not used in classic DK)
2402-
assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 0, 0, 0), 0, "Wrong degree of coherence 0 vote ID");
2403-
assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 1, 0, 0), 0, "Wrong degree of coherence 1 vote ID");
2404-
assertEq(disputeKit.getDegreeOfCoherence(disputeID, 0, 2, 0, 0), 0, "Wrong degree of coherence 2 vote ID");
2428+
(pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 0, 0, 0);
2429+
assertEq(pnkCoherence, 0, "Wrong reward pnk coherence 0 vote ID");
2430+
assertEq(feeCoherence, 0, "Wrong reward fee coherence 0 vote ID");
2431+
2432+
(pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 1, 0, 0);
2433+
assertEq(pnkCoherence, 0, "Wrong reward pnk coherence 1 vote ID");
2434+
assertEq(feeCoherence, 0, "Wrong reward fee coherence 1 vote ID");
2435+
2436+
(pnkCoherence, feeCoherence) = disputeKit.getDegreeOfCoherenceReward(disputeID, 0, 2, 0, 0);
2437+
assertEq(pnkCoherence, 0, "Wrong reward pnk coherence 2 vote ID");
2438+
assertEq(feeCoherence, 0, "Wrong reward fee coherence 2 vote ID");
2439+
2440+
assertEq(disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 0, 0, 0), 0, "Wrong penalty coherence 0 vote ID");
2441+
assertEq(disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 1, 0, 0), 0, "Wrong penalty coherence 1 vote ID");
2442+
assertEq(disputeKit.getDegreeOfCoherencePenalty(disputeID, 0, 2, 0, 0), 0, "Wrong penalty coherence 2 vote ID");
24052443

24062444
uint256 governorBalance = governor.balance;
24072445
uint256 governorTokenBalance = pinakion.balanceOf(governor);

0 commit comments

Comments
 (0)