11// SPDX-FileCopyrightText: 2020-2024 IEXEC BLOCKCHAIN TECH <[email protected] > 22// SPDX-License-Identifier: Apache-2.0
33
4+ import { AddressZero } from '@ethersproject/constants' ;
45import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' ;
56import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' ;
67import { ethers , expect } from 'hardhat' ;
@@ -9,8 +10,11 @@ import {
910 IexecInterfaceNative ,
1011 IexecInterfaceNative__factory ,
1112 IexecPocoAccessors__factory ,
13+ TestClient ,
14+ TestClient__factory ,
1215} from '../../../typechain' ;
1316import {
17+ IexecOrders ,
1418 OrdersActors ,
1519 OrdersAssets ,
1620 OrdersPrices ,
@@ -21,7 +25,7 @@ import { getDealId, getIexecAccounts, setNextBlockTimestamp } from '../../../uti
2125import { IexecWrapper } from '../../utils/IexecWrapper' ;
2226
2327/*
24- * TODO add TEE tests
28+ * TODO add Standard tests.
2529 */
2630
2731const appPrice = 1000 ;
@@ -54,6 +58,9 @@ describe('IexecPoco1', () => {
5458 let ordersActors : OrdersActors ;
5559 let ordersAssets : OrdersAssets ;
5660 let ordersPrices : OrdersPrices ;
61+ let orders : IexecOrders ;
62+ let randomAddress : string ;
63+ let randomContract : TestClient ;
5764
5865 beforeEach ( 'Deploy' , async ( ) => {
5966 // Deploy all contracts
@@ -94,6 +101,23 @@ describe('IexecPoco1', () => {
94101 dataset : datasetPrice ,
95102 workerpool : workerpoolPrice ,
96103 } ;
104+ ( { orders } = buildOrders ( {
105+ assets : ordersAssets ,
106+ prices : ordersPrices ,
107+ requester : requester . address ,
108+ beneficiary : beneficiary . address ,
109+ tag : teeDealTag ,
110+ volume : volume ,
111+ callback : callback ,
112+ trust : trust ,
113+ category : category ,
114+ params : params ,
115+ } ) ) ;
116+ randomAddress = ethers . Wallet . createRandom ( ) . address ;
117+ randomContract = await new TestClient__factory ( )
118+ . connect ( anyone )
119+ . deploy ( )
120+ . then ( ( contract ) => contract . deployed ( ) ) ;
97121 // TODO check why this is done in 00_matchorders.js
98122 // await Workerpool__factory.connect(workerpoolAddress, scheduler)
99123 // .changePolicy(35, 5)
@@ -106,13 +130,15 @@ describe('IexecPoco1', () => {
106130 describe ( 'Verify presignature or signature' , ( ) => { } ) ;
107131
108132 describe ( 'Match orders' , ( ) => {
109- it ( 'Should match orders with all assets (Standard)' , async ( ) => {
133+ it ( '[TEE] Should match orders with all assets, callback, and BoT' , async ( ) => {
134+ // Recreate orders here instead of using the default ones created
135+ // in beforeEach to make this test as explicit as possible.
110136 const { orders } = buildOrders ( {
111137 assets : ordersAssets ,
138+ prices : ordersPrices ,
112139 requester : requester . address ,
113140 beneficiary : beneficiary . address ,
114- tag : standardDealTag ,
115- prices : ordersPrices ,
141+ tag : teeDealTag ,
116142 volume : volume ,
117143 callback : callback ,
118144 trust : trust ,
@@ -158,16 +184,6 @@ describe('IexecPoco1', () => {
158184 dealId ,
159185 ) ;
160186 const tx = iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ;
161- await expect ( tx )
162- . to . emit ( iexecPoco , 'OrdersMatched' )
163- . withArgs (
164- dealId ,
165- appOrderHash ,
166- datasetOrderHash ,
167- workerpoolOrderHash ,
168- requestOrderHash ,
169- volume ,
170- ) ;
171187 // Check balances and frozen after.
172188 await expect ( tx ) . to . changeTokenBalances (
173189 iexecPoco ,
@@ -178,6 +194,17 @@ describe('IexecPoco1', () => {
178194 // See https://github.com/NomicFoundation/hardhat/blob/main/packages/hardhat-chai-matchers/src/internal/changeTokenBalance.ts#L42
179195 expect ( await iexecPoco . frozenOf ( requester . address ) ) . to . equal ( dealPrice ) ;
180196 expect ( await iexecPoco . frozenOf ( scheduler . address ) ) . to . equal ( schedulerStake ) ;
197+ // Check events.
198+ await expect ( tx )
199+ . to . emit ( iexecPoco , 'OrdersMatched' )
200+ . withArgs (
201+ dealId ,
202+ appOrderHash ,
203+ datasetOrderHash ,
204+ workerpoolOrderHash ,
205+ requestOrderHash ,
206+ volume ,
207+ ) ;
181208 // Check deal
182209 const deal = await iexecPoco . viewDeal ( dealId ) ;
183210 expect ( deal . app . pointer ) . to . equal ( appAddress ) ;
@@ -191,7 +218,7 @@ describe('IexecPoco1', () => {
191218 expect ( deal . workerpool . price . toNumber ( ) ) . to . equal ( workerpoolPrice ) ;
192219 expect ( deal . trust . toNumber ( ) ) . to . equal ( trust ) ;
193220 expect ( deal . category . toNumber ( ) ) . to . equal ( category ) ;
194- expect ( deal . tag ) . to . equal ( standardDealTag ) ;
221+ expect ( deal . tag ) . to . equal ( teeDealTag ) ;
195222 expect ( deal . requester ) . to . equal ( requester . address ) ;
196223 expect ( deal . beneficiary ) . to . equal ( beneficiary . address ) ;
197224 expect ( deal . callback ) . to . equal ( callback ) ;
@@ -204,10 +231,222 @@ describe('IexecPoco1', () => {
204231 expect ( deal . sponsor ) . to . equal ( requester . address ) ;
205232 } ) ;
206233
207- it ( '[TODO] Should match orders with all assets and callback (Standard)' , ( ) => { } ) ;
208- it ( '[TODO] Should match orders without dataset (Standard)' , ( ) => { } ) ;
209- it ( '[TODO] Should match orders without dataset and with callback (Standard)' , ( ) => { } ) ;
234+ it ( '[TEE] Should match orders without callback' , async ( ) => {
235+ orders . requester . callback = AddressZero ;
236+ await depositForRequesterAndSchedulerWithDefaultPrices ( ) ;
237+ // Sign and match orders.
238+ await signOrders ( iexecWrapper . getDomain ( ) , orders , ordersActors ) ;
239+ const dealId = getDealId ( iexecWrapper . getDomain ( ) , orders . requester , taskIndex ) ;
240+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . emit (
241+ iexecPoco ,
242+ 'OrdersMatched' ,
243+ ) ;
244+ // Check deal
245+ const deal = await iexecPoco . viewDeal ( dealId ) ;
246+ expect ( deal . callback ) . to . equal ( AddressZero ) ;
247+ } ) ;
248+
249+ it ( '[TEE] Should match orders without dataset' , async ( ) => {
250+ orders . dataset . dataset = AddressZero ;
251+ orders . requester . dataset = AddressZero ;
252+ // Set dataset volume lower than other assets to make sure
253+ // it does not impact final volume computation.
254+ orders . dataset . volume = volume - 1 ;
255+ // Compute prices, stakes, rewards, ...
256+ const dealPrice = ( appPrice + workerpoolPrice ) * volume ; // no dataset price
257+ const schedulerStake = await iexecWrapper . computeSchedulerDealStake (
258+ workerpoolPrice ,
259+ volume ,
260+ ) ;
261+ // Deposit required amounts.
262+ await iexecWrapper . depositInIexecAccount ( requester , dealPrice ) ;
263+ await iexecWrapper . depositInIexecAccount ( scheduler , schedulerStake ) ;
264+ // Sign and match orders.
265+ await signOrders ( iexecWrapper . getDomain ( ) , orders , ordersActors ) ;
266+ const dealId = getDealId ( iexecWrapper . getDomain ( ) , orders . requester , taskIndex ) ;
267+ const tx = iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ;
268+ // Check balances and frozen.
269+ // Dataset price shouldn't be included.
270+ await expect ( tx ) . to . changeTokenBalances (
271+ iexecPoco ,
272+ [ iexecPoco , requester , scheduler ] ,
273+ [ dealPrice + schedulerStake , - dealPrice , - schedulerStake ] ,
274+ ) ;
275+ expect ( await iexecPoco . frozenOf ( requester . address ) ) . to . equal ( dealPrice ) ;
276+ // Check events.
277+ await expect ( tx ) . to . emit ( iexecPoco , 'OrdersMatched' ) ;
278+ // Check deal
279+ const deal = await iexecPoco . viewDeal ( dealId ) ;
280+ expect ( deal . dataset . pointer ) . to . equal ( AddressZero ) ;
281+ expect ( deal . dataset . owner ) . to . equal ( AddressZero ) ;
282+ expect ( deal . dataset . price . toNumber ( ) ) . to . equal ( 0 ) ;
283+ // BoT size should not be impacted even if the dataset order is the order with the lowest volume
284+ expect ( deal . botSize . toNumber ( ) ) . to . equal ( volume ) ;
285+ } ) ;
286+
287+ it ( '[TODO][TEE] Should match orders with restrictions' , async ( ) => { } ) ;
288+
289+ it ( '[TEE] Should fail when categories are different' , async ( ) => {
290+ orders . requester . category = category + 1 ; // Valid but different category.
291+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
292+ 'iExecV5-matchOrders-0x00' ,
293+ ) ;
294+ } ) ;
295+
296+ it ( '[TEE] Should fail when category is unknown' , async ( ) => {
297+ const lastCategoryIndex = ( await iexecPoco . countCategory ( ) ) . toNumber ( ) - 1 ;
298+ orders . requester . category = lastCategoryIndex + 1 ;
299+ orders . workerpool . category = lastCategoryIndex + 1 ;
300+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
301+ 'iExecV5-matchOrders-0x01' ,
302+ ) ;
303+ } ) ;
304+
305+ it ( '[TEE] Should fail when requested trust is above workerpool trust' , async ( ) => {
306+ orders . requester . trust = Number ( orders . workerpool . trust ) + 1 ;
307+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
308+ 'iExecV5-matchOrders-0x02' ,
309+ ) ;
310+ } ) ;
311+
312+ it ( '[TEE] Should fail when app max price is less than app price' , async ( ) => {
313+ orders . requester . appmaxprice = Number ( orders . app . appprice ) - 1 ;
314+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
315+ 'iExecV5-matchOrders-0x03' ,
316+ ) ;
317+ } ) ;
318+
319+ it ( '[TEE] Should fail when dataset max price is less than dataset price' , async ( ) => {
320+ orders . requester . datasetmaxprice = Number ( orders . dataset . datasetprice ) - 1 ;
321+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
322+ 'iExecV5-matchOrders-0x04' ,
323+ ) ;
324+ } ) ;
325+
326+ it ( '[TEE] Should fail when workerpool max price is less than workerpool price' , async ( ) => {
327+ orders . requester . workerpoolmaxprice = Number ( orders . workerpool . workerpoolprice ) - 1 ;
328+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
329+ 'iExecV5-matchOrders-0x05' ,
330+ ) ;
331+ } ) ;
332+
333+ it ( '[TEE] Should fail when workerpool tag does not satisfy app, dataset and request requirements' , async ( ) => {
334+ orders . app . tag = '0x0000000000000000000000000000000000000000000000000000000000000001' ; // 0b0001
335+ orders . dataset . tag =
336+ '0x0000000000000000000000000000000000000000000000000000000000000002' ; // 0b0010
337+ orders . requester . tag =
338+ '0x0000000000000000000000000000000000000000000000000000000000000003' ; // 0b0011
339+ // Workerpool order is supposed to satisfy conditions of all actors.
340+ // Bad tag, correct tag should be 0b0011.
341+ orders . workerpool . tag =
342+ '0x0000000000000000000000000000000000000000000000000000000000000004' ; // 0b0100
343+ // Match orders.
344+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
345+ 'iExecV5-matchOrders-0x06' ,
346+ ) ;
347+ } ) ;
348+
349+ it ( '[TEE] Should fail when the last bit of app tag does not satisfy dataset or request requirements' , async ( ) => {
350+ // The last bit of dataset and request tag is 1, but app tag does not set it
351+ orders . app . tag = '0x0000000000000000000000000000000000000000000000000000000000000002' ; // 0b0010
352+ orders . dataset . tag =
353+ '0x0000000000000000000000000000000000000000000000000000000000000003' ; // 0b0011
354+ orders . requester . tag =
355+ '0x0000000000000000000000000000000000000000000000000000000000000003' ; // 0b0011
356+ // Set the workerpool tag in a way to pass first tag check.
357+ orders . workerpool . tag =
358+ '0x0000000000000000000000000000000000000000000000000000000000000003' ; // 0b0011
359+ // Match orders.
360+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
361+ 'iExecV5-matchOrders-0x07' ,
362+ ) ;
363+ } ) ;
364+
365+ it ( '[TEE] Should fail when apps are different' , async ( ) => {
366+ orders . requester . app = randomAddress ;
367+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
368+ 'iExecV5-matchOrders-0x10' ,
369+ ) ;
370+ } ) ;
371+
372+ it ( '[TEE] Should fail when datasets are different' , async ( ) => {
373+ orders . requester . dataset = randomAddress ;
374+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
375+ 'iExecV5-matchOrders-0x11' ,
376+ ) ;
377+ } ) ;
378+
379+ it ( '[TEE] Should fail when request order workerpool mismatches workerpool order workerpool (EOA, SC)' , async ( ) => {
380+ orders . requester . workerpool = randomAddress ;
381+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
382+ 'iExecV5-matchOrders-0x12' ,
383+ ) ;
384+ orders . requester . workerpool = randomContract . address ;
385+ await expect ( iexecPocoAsRequester . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
386+ 'iExecV5-matchOrders-0x12' ,
387+ ) ;
388+ } ) ;
389+
390+ /**
391+ * Dynamically generated tests for all different restrictions in orders
392+ * (requesterrestrict, apprestrict, workerpoolrestrict, datasetrestrict).
393+ */
394+ const revertMessages : { [ key : string ] : { [ key : string ] : string } } = {
395+ app : {
396+ dataset : 'iExecV5-matchOrders-0x13' ,
397+ workerpool : 'iExecV5-matchOrders-0x14' ,
398+ requester : 'iExecV5-matchOrders-0x15' ,
399+ } ,
400+ dataset : {
401+ app : 'iExecV5-matchOrders-0x16' ,
402+ workerpool : 'iExecV5-matchOrders-0x17' ,
403+ requester : 'iExecV5-matchOrders-0x18' ,
404+ } ,
405+ workerpool : {
406+ app : 'iExecV5-matchOrders-0x19' ,
407+ dataset : 'iExecV5-matchOrders-0x1a' ,
408+ requester : 'iExecV5-matchOrders-0x1b' ,
409+ } ,
410+ } ;
411+ [ 'app' , 'workerpool' , 'dataset' ] . forEach ( ( orderName ) => {
412+ // No request order
413+ [ 'requester' , 'app' , 'workerpool' , 'dataset' ] . forEach ( ( assetName ) => {
414+ // Filter irrelevant cases. E.g. no need to change the app address in the app order.
415+ if ( orderName . includes ( assetName ) ) {
416+ return ;
417+ }
418+ it ( `[TEE] Should fail when ${ orderName } order mismatch ${ assetName } restriction (EOA, SC)` , async function ( ) {
419+ const message = revertMessages [ orderName ] [ assetName ] ;
420+ // EOA
421+ orders [ orderName ] [ assetName + 'restrict' ] = randomAddress ; // e.g. orders['app']['apprestrict'] = 0xEOA
422+ await expect ( iexecPoco . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
423+ message ,
424+ ) ;
425+ // SC
426+ orders [ orderName ] [ assetName + 'restrict' ] = randomContract . address ; // e.g. orders['app']['apprestrict'] = 0xSC
427+ await expect ( iexecPoco . matchOrders ( ...orders . toArray ( ) ) ) . to . be . revertedWith (
428+ message ,
429+ ) ;
430+ } ) ;
431+ } ) ;
432+ } ) ;
433+
210434 it ( '[TODO] Should match orders with replication' , ( ) => { } ) ;
211435 } ) ;
212436 describe ( '[TODO] Sponsor match orders' , ( ) => { } ) ;
437+
438+ /**
439+ * Helper function to deposit requester and scheduler stakes with
440+ * default prices for tests that do not rely on price changes.
441+ */
442+ async function depositForRequesterAndSchedulerWithDefaultPrices ( ) {
443+ const dealPrice = ( appPrice + datasetPrice + workerpoolPrice ) * volume ;
444+ const schedulerStake = await iexecWrapper . computeSchedulerDealStake (
445+ workerpoolPrice ,
446+ volume ,
447+ ) ;
448+ // Deposit required amounts.
449+ await iexecWrapper . depositInIexecAccount ( requester , dealPrice ) ;
450+ await iexecWrapper . depositInIexecAccount ( scheduler , schedulerStake ) ;
451+ }
213452} ) ;
0 commit comments