11import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs" ;
22import { deployments , ethers , getNamedAccounts , network } from "hardhat" ;
3- import { BigNumber , ContractTransaction , Wallet } from "ethers" ;
3+ import { BigNumber , ContractReceipt , ContractTransaction , Wallet } from "ethers" ;
44import {
55 PNK ,
66 KlerosCore ,
77 ArbitrableExample ,
88 HomeGateway ,
99 DisputeKitClassic ,
10- RandomizerRNG ,
11- RandomizerMock ,
1210 SortitionModule ,
1311} from "../../typechain-types" ;
1412import { expect } from "chai" ;
13+ import { DrawEvent } from "../../typechain-types/src/kleros-v1/kleros-liquid-xdai/XKlerosLiquidV2" ;
1514
1615/* eslint-disable no-unused-vars */
1716/* eslint-disable no-unused-expressions */ // https://github.com/standard/standard/issues/690#issuecomment-278533482
@@ -49,7 +48,11 @@ describe("Draw Benchmark", async () => {
4948 let homeGateway ;
5049 let sortitionModule ;
5150 let rng ;
52- let randomizer ;
51+ let parentCourtMinStake : BigNumber ;
52+ let childCourtMinStake : BigNumber ;
53+ const RANDOM = BigNumber . from ( "61688911660239508166491237672720926005752254046266901728404745669596507231249" ) ;
54+ const PARENT_COURT = 1 ;
55+ const CHILD_COURT = 2 ;
5356
5457 beforeEach ( "Setup" , async ( ) => {
5558 ( { deployer, relayer } = await getNamedAccounts ( ) ) ;
@@ -63,11 +66,25 @@ describe("Draw Benchmark", async () => {
6366 core = ( await ethers . getContract ( "KlerosCore" ) ) as KlerosCore ;
6467 homeGateway = ( await ethers . getContract ( "HomeGatewayToEthereum" ) ) as HomeGateway ;
6568 arbitrable = ( await ethers . getContract ( "ArbitrableExample" ) ) as ArbitrableExample ;
66- rng = ( await ethers . getContract ( "RandomizerRNG" ) ) as RandomizerRNG ;
67- randomizer = ( await ethers . getContract ( "RandomizerMock" ) ) as RandomizerMock ;
6869 sortitionModule = ( await ethers . getContract ( "SortitionModule" ) ) as SortitionModule ;
6970
70- // CourtId 2
71+ parentCourtMinStake = await core
72+ . GENERAL_COURT ( )
73+ . then ( ( courtId ) => core . courts ( courtId ) )
74+ . then ( ( court ) => court . minStake ) ;
75+
76+ childCourtMinStake = BigNumber . from ( 10 ) . pow ( 20 ) . mul ( 3 ) ; // 300 PNK
77+
78+ // Make the tests more deterministic with this dummy RNG
79+ rng = await deployments . deploy ( "IncrementalNG" , {
80+ from : deployer ,
81+ args : [ RANDOM ] ,
82+ log : true ,
83+ } ) ;
84+
85+ await sortitionModule . changeRandomNumberGenerator ( rng . address , 20 ) ;
86+
87+ // CourtId 2 = CHILD_COURT
7188 const minStake = BigNumber . from ( 10 ) . pow ( 20 ) . mul ( 3 ) ; // 300 PNK
7289 const alpha = 10000 ;
7390 const feeForJuror = BigNumber . from ( 10 ) . pow ( 17 ) ;
@@ -84,16 +101,24 @@ describe("Draw Benchmark", async () => {
84101 ) ;
85102 } ) ;
86103
104+ type CountedDraws = { [ address : string ] : number } ;
87105 type SetStake = ( wallet : Wallet ) => Promise < void > ;
88106 type ExpectFromDraw = ( drawTx : Promise < ContractTransaction > ) => Promise < void > ;
89107
90- const draw = async ( setStake : SetStake , createDisputeCourtId : string , expectFromDraw : ExpectFromDraw ) => {
108+ const draw = async (
109+ stake : SetStake ,
110+ createDisputeCourtId : number ,
111+ expectFromDraw : ExpectFromDraw ,
112+ unstake : SetStake
113+ ) => {
91114 const arbitrationCost = ONE_TENTH_ETH . mul ( 3 ) ;
92115 const [ bridger ] = await ethers . getSigners ( ) ;
116+ const wallets : Wallet [ ] = [ ] ;
93117
94118 // Stake some jurors
95119 for ( let i = 0 ; i < 16 ; i ++ ) {
96120 const wallet = ethers . Wallet . createRandom ( ) . connect ( ethers . provider ) ;
121+ wallets . push ( wallet ) ;
97122
98123 await bridger . sendTransaction ( {
99124 to : wallet . address ,
@@ -106,7 +131,7 @@ describe("Draw Benchmark", async () => {
106131
107132 await pnk . connect ( wallet ) . approve ( core . address , ONE_THOUSAND_PNK . mul ( 10 ) , { gasLimit : 300000 } ) ;
108133
109- await setStake ( wallet ) ;
134+ await stake ( wallet ) ;
110135 }
111136
112137 // Create a dispute
@@ -144,75 +169,227 @@ describe("Draw Benchmark", async () => {
144169 await network . provider . send ( "evm_mine" ) ;
145170 }
146171
147- await randomizer . relay ( rng . address , 0 , ethers . utils . randomBytes ( 32 ) ) ;
148172 await sortitionModule . passPhase ( ) ; // Generating -> Drawing
149173
150174 await expectFromDraw ( core . draw ( 0 , 1000 , { gasLimit : 1000000 } ) ) ;
175+
176+ await network . provider . send ( "evm_increaseTime" , [ 2000 ] ) ; // Wait for maxDrawingTime
177+ await sortitionModule . passPhase ( ) ; // Drawing -> Staking
178+ expect ( await sortitionModule . phase ( ) ) . to . equal ( Phase . staking ) ;
179+
180+ // Unstake jurors
181+ for ( const wallet of wallets ) {
182+ await unstake ( wallet ) ;
183+ }
184+ } ;
185+
186+ const countDraws = async ( blockNumber : number ) => {
187+ const draws : Array < DrawEvent > = await core . queryFilter ( core . filters . Draw ( ) , blockNumber , blockNumber ) ;
188+ return draws . reduce ( ( acc : { [ address : string ] : number } , draw ) => {
189+ const address = draw . args . _address ;
190+ acc [ address ] = acc [ address ] ? acc [ address ] + 1 : 1 ;
191+ return acc ;
192+ } , { } ) ;
151193 } ;
152194
153195 it ( "Stakes in parent court and should draw jurors in parent court" , async ( ) => {
154- const setStake = async ( wallet : Wallet ) => {
155- await core . connect ( wallet ) . setStake ( 1 , ONE_THOUSAND_PNK . mul ( 5 ) , { gasLimit : 5000000 } ) ;
196+ const stake = async ( wallet : Wallet ) => {
197+ await core . connect ( wallet ) . setStake ( PARENT_COURT , ONE_THOUSAND_PNK . mul ( 5 ) , { gasLimit : 5000000 } ) ;
198+
199+ expect ( await core . getJurorBalance ( wallet . address , 1 ) ) . to . deep . equal ( [
200+ ONE_THOUSAND_PNK . mul ( 5 ) , // stakedInCourt
201+ 0 , // lockedInCourt
202+ PARENT_COURT , // nbOfCourts
203+ ] ) ;
156204 } ;
157-
205+ let countedDraws : CountedDraws ;
158206 const expectFromDraw = async ( drawTx : Promise < ContractTransaction > ) => {
159- await expect ( drawTx )
207+ const tx = await ( await drawTx ) . wait ( ) ;
208+ expect ( tx )
160209 . to . emit ( core , "Draw" )
161210 . withArgs ( anyValue , 0 , 0 , 0 )
162211 . to . emit ( core , "Draw" )
163212 . withArgs ( anyValue , 0 , 0 , 1 )
164213 . to . emit ( core , "Draw" )
165214 . withArgs ( anyValue , 0 , 0 , 2 ) ;
215+
216+ countedDraws = await countDraws ( tx . blockNumber ) ;
217+ for ( const [ address , draws ] of Object . entries ( countedDraws ) ) {
218+ expect ( await core . getJurorBalance ( address , PARENT_COURT ) ) . to . deep . equal ( [
219+ ONE_THOUSAND_PNK . mul ( 5 ) , // stakedInCourt
220+ parentCourtMinStake . mul ( draws ) , // lockedInCourt
221+ 1 , // nbOfCourts
222+ ] ) ;
223+ expect ( await core . getJurorBalance ( address , CHILD_COURT ) ) . to . deep . equal ( [
224+ 0 , // stakedInCourt
225+ 0 , // lockedInCourt
226+ 1 , // nbOfCourts
227+ ] ) ;
228+ }
166229 } ;
167230
168- await draw ( setStake , "1" , expectFromDraw ) ;
231+ const unstake = async ( wallet : Wallet ) => {
232+ await core . connect ( wallet ) . setStake ( PARENT_COURT , 0 , { gasLimit : 5000000 } ) ;
233+ const locked = parentCourtMinStake . mul ( countedDraws [ wallet . address ] ?? 0 ) ;
234+ expect (
235+ await core . getJurorBalance ( wallet . address , PARENT_COURT ) ,
236+ "Drawn jurors have a locked stake in the parent court"
237+ ) . to . deep . equal ( [
238+ 0 , // stakedInCourt
239+ locked , // lockedInCourt
240+ 0 , // nbOfCourts
241+ ] ) ;
242+ expect (
243+ await core . getJurorBalance ( wallet . address , CHILD_COURT ) ,
244+ "No locked stake in the child court"
245+ ) . to . deep . equal ( [
246+ 0 , // stakedInCourt
247+ 0 , // lockedInCourt
248+ 0 , // nbOfCourts
249+ ] ) ;
250+ } ;
251+
252+ await draw ( stake , PARENT_COURT , expectFromDraw , unstake ) ;
169253 } ) ;
170254
171255 it ( "Stakes in parent court and should draw nobody in subcourt" , async ( ) => {
172- const setStake = async ( wallet : Wallet ) => {
173- await core . connect ( wallet ) . setStake ( 1 , ONE_THOUSAND_PNK . mul ( 5 ) , { gasLimit : 5000000 } ) ;
256+ const stake = async ( wallet : Wallet ) => {
257+ await core . connect ( wallet ) . setStake ( PARENT_COURT , ONE_THOUSAND_PNK . mul ( 5 ) , { gasLimit : 5000000 } ) ;
174258 } ;
175259
176260 const expectFromDraw = async ( drawTx : Promise < ContractTransaction > ) => {
177261 await expect ( drawTx ) . to . not . emit ( core , "Draw" ) ;
178262 } ;
179263
180- await draw ( setStake , "2" , expectFromDraw ) ;
264+ const unstake = async ( wallet : Wallet ) => {
265+ await core . connect ( wallet ) . setStake ( PARENT_COURT , 0 , { gasLimit : 5000000 } ) ;
266+ expect (
267+ await core . getJurorBalance ( wallet . address , PARENT_COURT ) ,
268+ "No locked stake in the parent court"
269+ ) . to . deep . equal ( [
270+ 0 , // stakedInCourt
271+ 0 , // lockedInCourt
272+ 0 , // nbOfCourts
273+ ] ) ;
274+ expect (
275+ await core . getJurorBalance ( wallet . address , CHILD_COURT ) ,
276+ "No locked stake in the child court"
277+ ) . to . deep . equal ( [
278+ 0 , // stakedInCourt
279+ 0 , // lockedInCourt
280+ 0 , // nbOfCourts
281+ ] ) ;
282+ } ;
283+
284+ await draw ( stake , CHILD_COURT , expectFromDraw , unstake ) ;
181285 } ) ;
182286
183287 it ( "Stakes in subcourt and should draw jurors in parent court" , async ( ) => {
184- const setStake = async ( wallet : Wallet ) => {
185- await core . connect ( wallet ) . setStake ( 2 , ONE_THOUSAND_PNK . mul ( 5 ) , { gasLimit : 5000000 } ) ;
288+ const stake = async ( wallet : Wallet ) => {
289+ await core . connect ( wallet ) . setStake ( CHILD_COURT , ONE_THOUSAND_PNK . mul ( 5 ) , { gasLimit : 5000000 } ) ;
186290 } ;
187-
291+ let countedDraws : CountedDraws ;
188292 const expectFromDraw = async ( drawTx : Promise < ContractTransaction > ) => {
189- await expect ( drawTx )
293+ const tx = await ( await drawTx ) . wait ( ) ;
294+ expect ( tx )
190295 . to . emit ( core , "Draw" )
191296 . withArgs ( anyValue , 0 , 0 , 0 )
192297 . to . emit ( core , "Draw" )
193298 . withArgs ( anyValue , 0 , 0 , 1 )
194299 . to . emit ( core , "Draw" )
195300 . withArgs ( anyValue , 0 , 0 , 2 ) ;
301+
302+ countedDraws = await countDraws ( tx . blockNumber ) ;
303+ for ( const [ address , draws ] of Object . entries ( countedDraws ) ) {
304+ expect ( await core . getJurorBalance ( address , PARENT_COURT ) ) . to . deep . equal ( [
305+ 0 , // stakedInCourt
306+ parentCourtMinStake . mul ( draws ) , // lockedInCourt
307+ 1 , // nbOfCourts
308+ ] ) ;
309+ expect ( await core . getJurorBalance ( address , CHILD_COURT ) ) . to . deep . equal ( [
310+ ONE_THOUSAND_PNK . mul ( 5 ) , // stakedInCourt
311+ 0 , // lockedInCourt
312+ 1 , // nbOfCourts
313+ ] ) ;
314+ }
196315 } ;
197316
198- await draw ( setStake , "1" , expectFromDraw ) ;
317+ const unstake = async ( wallet : Wallet ) => {
318+ await core . connect ( wallet ) . setStake ( CHILD_COURT , 0 , { gasLimit : 5000000 } ) ;
319+ const locked = parentCourtMinStake . mul ( countedDraws [ wallet . address ] ?? 0 ) ;
320+ console . log ( `draws for ${ wallet . address } : ${ countedDraws [ wallet . address ] ?? 0 } , locked: ${ locked } ` ) ;
321+ expect (
322+ await core . getJurorBalance ( wallet . address , PARENT_COURT ) ,
323+ "No locked stake in the parent court"
324+ ) . to . deep . equal ( [
325+ 0 , // stakedInCourt
326+ 0 , // lockedInCourt
327+ 0 , // nbOfCourts
328+ ] ) ;
329+ expect (
330+ await core . getJurorBalance ( wallet . address , CHILD_COURT ) ,
331+ "Drawn jurors have a locked stake in the child court"
332+ ) . to . deep . equal ( [
333+ 0 , // stakedInCourt
334+ locked , // lockedInCourt
335+ 0 , // nbOfCourts
336+ ] ) ;
337+ } ;
338+
339+ await draw ( stake , PARENT_COURT , expectFromDraw , unstake ) ;
199340 } ) ;
200341
201342 it ( "Stakes in subcourt and should draw jurors in subcourt" , async ( ) => {
202- const setStake = async ( wallet : Wallet ) => {
203- await core . connect ( wallet ) . setStake ( 2 , ONE_THOUSAND_PNK . mul ( 5 ) , { gasLimit : 5000000 } ) ;
343+ const stake = async ( wallet : Wallet ) => {
344+ await core . connect ( wallet ) . setStake ( CHILD_COURT , ONE_THOUSAND_PNK . mul ( 5 ) , { gasLimit : 5000000 } ) ;
204345 } ;
205-
346+ let countedDraws : CountedDraws ;
206347 const expectFromDraw = async ( drawTx : Promise < ContractTransaction > ) => {
207- await expect ( drawTx )
348+ const tx = await ( await drawTx ) . wait ( ) ;
349+ expect ( tx )
208350 . to . emit ( core , "Draw" )
209351 . withArgs ( anyValue , 0 , 0 , 0 )
210352 . to . emit ( core , "Draw" )
211353 . withArgs ( anyValue , 0 , 0 , 1 )
212354 . to . emit ( core , "Draw" )
213355 . withArgs ( anyValue , 0 , 0 , 2 ) ;
356+
357+ countedDraws = await countDraws ( tx . blockNumber ) ;
358+ for ( const [ address , draws ] of Object . entries ( countedDraws ) ) {
359+ expect ( await core . getJurorBalance ( address , PARENT_COURT ) ) . to . deep . equal ( [
360+ 0 , // stakedInCourt
361+ 0 , // lockedInCourt
362+ 1 , // nbOfCourts
363+ ] ) ;
364+ expect ( await core . getJurorBalance ( address , CHILD_COURT ) ) . to . deep . equal ( [
365+ ONE_THOUSAND_PNK . mul ( 5 ) , // stakedInCourt
366+ childCourtMinStake . mul ( draws ) , // lockedInCourt
367+ 1 , // nbOfCourts
368+ ] ) ;
369+ }
370+ } ;
371+
372+ const unstake = async ( wallet : Wallet ) => {
373+ await core . connect ( wallet ) . setStake ( CHILD_COURT , 0 , { gasLimit : 5000000 } ) ;
374+ const locked = childCourtMinStake . mul ( countedDraws [ wallet . address ] ?? 0 ) ;
375+ expect (
376+ await core . getJurorBalance ( wallet . address , PARENT_COURT ) ,
377+ "No locked stake in the parent court"
378+ ) . to . deep . equal ( [
379+ 0 , // stakedInCourt
380+ 0 , // lockedInCourt
381+ 0 , // nbOfCourts
382+ ] ) ;
383+ expect (
384+ await core . getJurorBalance ( wallet . address , CHILD_COURT ) ,
385+ "Drawn jurors have a locked stake in the child court"
386+ ) . to . deep . equal ( [
387+ 0 , // stakedInCourt
388+ locked , // lockedInCourt
389+ 0 , // nbOfCourts
390+ ] ) ;
214391 } ;
215392
216- await draw ( setStake , "2" , expectFromDraw ) ;
393+ await draw ( stake , CHILD_COURT , expectFromDraw , unstake ) ;
217394 } ) ;
218395} ) ;
0 commit comments