Skip to content

Commit

Permalink
feat: including ReentrancyAttack contract to test if the offer can be…
Browse files Browse the repository at this point in the history
… accept twice in the same tx
  • Loading branch information
EduardoMelo00 committed Aug 13, 2024
1 parent e5c211d commit 6d0d99f
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 0 deletions.
21 changes: 21 additions & 0 deletions contracts/mocks/ReentrancyAttack.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import '../OriumSftMarketplace.sol';

contract ReentrancyAttack {
OriumSftMarketplace public marketplace;

constructor(OriumSftMarketplace _marketplace) {
marketplace = _marketplace;
}

receive() external payable {}

function attemptDoubleAccept(RentalOffer calldata _offer, uint64 _duration) external payable {
// First accept call
marketplace.acceptRentalOffer{ value: msg.value / 2 }(_offer, _duration);
// Second accept call in the same transaction
marketplace.acceptRentalOffer{ value: msg.value / 2 }(_offer, _duration);
}
}
32 changes: 32 additions & 0 deletions test/OriumSftMarketplace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
OriumSftMarketplace,
SftRolesRegistrySingleRole,
SftRolesRegistrySingleRoleLegacy,
ReentrancyAttack,
} from '../typechain-types'

describe('OriumSftMarketplace', () => {
Expand All @@ -27,6 +28,7 @@ describe('OriumSftMarketplace', () => {
let secondMockERC1155: MockERC1155
let wearableToken: MockERC1155
let mockERC20: MockERC20
let attackContract: ReentrancyAttack

// We are disabling this rule because hardhat uses first account as deployer by default, and we are separating deployer and operator
// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down Expand Up @@ -721,6 +723,36 @@ describe('OriumSftMarketplace', () => {
).to.be.revertedWith('OriumSftMarketplace: Insufficient native token amount')
})

it('should prevent double accept in the same transaction', async () => {
const AttackContract = await ethers.getContractFactory('ReentrancyAttack')
attackContract = (await AttackContract.deploy(marketplace)) as ReentrancyAttack
await attackContract.waitForDeployment()

await marketplaceRoyalties
.connect(operator)
.setTrustedFeeTokenForToken([rentalOffer.tokenAddress], [AddressZero], [true])

rentalOffer.feeTokenAddress = AddressZero
rentalOffer.feeAmountPerSecond = toWei('0.0000001')
const totalFeeAmount = rentalOffer.feeAmountPerSecond * BigInt(duration)
rentalOffer.nonce = `0x${randomBytes(32).toString('hex')}`
await marketplace.connect(lender).createRentalOffer({ ...rentalOffer, commitmentId: BigInt(0) })
rentalOffer.commitmentId = BigInt(2)

await borrower.sendTransaction({
to: attackContract.getAddress(),
value: totalFeeAmount,
})

const doubleTotalFeeAmount = totalFeeAmount * BigInt(2)

await expect(
attackContract
.connect(borrower)
.attemptDoubleAccept(rentalOffer, duration, { value: doubleTotalFeeAmount.toString() }),
).to.be.revertedWith('OriumSftMarketplace: This offer has an ongoing rental')
})

describe('Fees', async function () {
const feeAmountPerSecond = toWei('1')
const feeAmount = feeAmountPerSecond * BigInt(duration)
Expand Down

0 comments on commit 6d0d99f

Please sign in to comment.