diff --git a/contracts/beacon/Voucher.sol b/contracts/beacon/Voucher.sol index 944809f..eda87c6 100644 --- a/contracts/beacon/Voucher.sol +++ b/contracts/beacon/Voucher.sol @@ -373,7 +373,9 @@ contract Voucher is Initializable, IVoucher { // If the deal was not sponsored or partially sponsored // by the voucher then send the non-sponsored part back // to the requester. - IERC20(iexecPoco).transfer(requester, taskPrice - taskSponsoredAmount); + if (!IERC20(iexecPoco).transfer(requester, taskPrice - taskSponsoredAmount)) { + revert("Voucher: transfer to requester failed"); + } } } } @@ -432,11 +434,16 @@ contract Voucher is Initializable, IVoucher { if (sponsoredAmount != dealPrice) { // Transfer non-sponsored amount from the iExec account of the // requester to the iExec account of the voucher - IERC20(iexecPoco).transferFrom( - requestOrder.requester, - address(this), - dealPrice - sponsoredAmount - ); + if ( + !IERC20(iexecPoco).transferFrom( + requestOrder.requester, + address(this), + dealPrice - sponsoredAmount + ) + ) { + // SRLC + revert("Voucher: Transfer of non-sponsored amount failed"); + } } } } diff --git a/test/beacon/Voucher.test.ts b/test/beacon/Voucher.test.ts index 73cf1f6..df9bf02 100644 --- a/test/beacon/Voucher.test.ts +++ b/test/beacon/Voucher.test.ts @@ -644,6 +644,28 @@ describe('Voucher', function () { ), ).to.be.revertedWith('IexecPocoMock: Failed to sponsorMatchOrdersBoost'); }); + + it('Should not match orders boost when SRLC transfer fails', async () => { + const noSponsoredValue = appPrice * volume; + await addEligibleAssets([dataset, workerpool]); + await iexecPocoInstance + .transfer(requester, noSponsoredValue) + .then((tx) => tx.wait()); + + await iexecPocoInstance + .connect(requester) + .approve(await voucherAsOwner.getAddress(), noSponsoredValue) + .then((tx) => tx.wait()); + await iexecPocoInstance.willRevertOnTransferFrom().then((tx) => tx.wait()); + await expect( + voucherAsOwner.matchOrdersBoost( + appOrder, + datasetOrder, + workerpoolOrder, + requestOrder, + ), + ).to.be.revertedWith('Voucher: Transfer of non-sponsored amount failed'); + }); }); }); @@ -1049,6 +1071,28 @@ describe('Voucher', function () { ); }); }); + describe('Should not claim task when SLRC transfer fails', async () => { + it('Classic', async () => await runTest(voucherMatchOrders, claim)); + it('Boost', async () => await runTest(voucherMatchOrdersBoost, claimBoost)); + + async function runTest(matchOrdersBoostOrClassic: any, claimBoostOrClassic: any) { + await addEligibleAssets([app, dataset]); // workerpool not eligible. + const dealNonSponsoredAmount = workerpoolPrice * volume; + // Deposit non-sponsored amount for requester and approve voucher. + await iexecPocoInstance + .transfer(requester, dealNonSponsoredAmount) + .then((tx) => tx.wait()); + await iexecPocoInstance + .connect(requester) + .approve(voucherAddress, dealNonSponsoredAmount) + .then((tx) => tx.wait()); + await matchOrdersBoostOrClassic(); + await iexecPocoInstance.willRevertOnTransfer().then((tx) => tx.wait()); + await expect(claimBoostOrClassic()).to.be.revertedWith( + 'Voucher: transfer to requester failed', + ); + } + }); }); async function addEligibleAssets(assets: string[]) {