Skip to content

Commit

Permalink
feat: Accept offer to pay with native token
Browse files Browse the repository at this point in the history
  • Loading branch information
EduardoMelo00 committed Aug 5, 2024
1 parent f274403 commit e23cd0d
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 14 deletions.
38 changes: 25 additions & 13 deletions contracts/OriumSftMarketplace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pragma solidity 0.8.9;
import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import { Initializable } from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import { PausableUpgradeable } from '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol';
import { ReentrancyGuardUpgradeable } from '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
import { IERC1155 } from '@openzeppelin/contracts/token/ERC1155/IERC1155.sol';
import { IERC7589 } from './interfaces/IERC7589.sol';
import { IERC7589Legacy } from './interfaces/IERC7589Legacy.sol';
Expand All @@ -16,7 +17,7 @@ import { IOriumMarketplaceRoyalties } from './interfaces/IOriumMarketplaceRoyalt
* @dev This contract is used to manage SFTs rentals, powered by ERC-7589 Semi-Fungible Token Roles
* @author Orium Network Team - [email protected]
*/
contract OriumSftMarketplace is Initializable, OwnableUpgradeable, PausableUpgradeable {
contract OriumSftMarketplace is Initializable, OwnableUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable {
/** ######### Global Variables ########### **/

/// @dev oriumMarketplaceRoyalties stores the collection royalties and fees
Expand Down Expand Up @@ -110,6 +111,7 @@ contract OriumSftMarketplace is Initializable, OwnableUpgradeable, PausableUpgra
function initialize(address _owner, address _oriumMarketplaceRoyalties) public initializer {
__Pausable_init();
__Ownable_init();
__ReentrancyGuard_init();

oriumMarketplaceRoyalties = _oriumMarketplaceRoyalties;

Expand All @@ -124,7 +126,6 @@ contract OriumSftMarketplace is Initializable, OwnableUpgradeable, PausableUpgra
* @dev To optimize for gas, only the offer hash is stored on-chain
* @param _offer The rental offer struct.
*/

function createRentalOffer(RentalOffer memory _offer) external whenNotPaused {
address _rolesRegistryAddress = IOriumMarketplaceRoyalties(oriumMarketplaceRoyalties).sftRolesRegistryOf(
_offer.tokenAddress
Expand Down Expand Up @@ -168,8 +169,10 @@ contract OriumSftMarketplace is Initializable, OwnableUpgradeable, PausableUpgra
* @param _offer The rental offer struct. It should be the same as the one used to create the offer.
* @param _duration The duration of the rental.
*/

function acceptRentalOffer(RentalOffer calldata _offer, uint64 _duration) external whenNotPaused {
function acceptRentalOffer(
RentalOffer calldata _offer,
uint64 _duration
) external payable whenNotPaused nonReentrant {
bytes32 _offerHash = LibOriumSftMarketplace.hashRentalOffer(_offer);
uint64 _expirationDate = uint64(block.timestamp + _duration);
LibOriumSftMarketplace.validateAcceptRentalOffer(
Expand Down Expand Up @@ -441,15 +444,23 @@ contract OriumSftMarketplace is Initializable, OwnableUpgradeable, PausableUpgra
);
uint256 _lenderAmount = _feeAmount - _royaltyAmount - _marketplaceFeeAmount;

LibOriumSftMarketplace.transferFees(
_feeTokenAddress,
_marketplaceFeeAmount,
_royaltyAmount,
_lenderAmount,
owner(),
_royaltyInfo.treasury,
_lenderAddress
);
// Check if the fee token address is zero address (i.e., native token)
if (_feeTokenAddress == address(0)) {
require(msg.value == _feeAmount, 'OriumSftMarketplace: Incorrect native token amount');
payable(owner()).transfer(_marketplaceFeeAmount);
payable(_royaltyInfo.treasury).transfer(_royaltyAmount);
payable(_lenderAddress).transfer(_lenderAmount);
} else {
LibOriumSftMarketplace.transferFees(
_feeTokenAddress,
_marketplaceFeeAmount,
_royaltyAmount,
_lenderAmount,
owner(),
_royaltyInfo.treasury,
_lenderAddress
);
}
}

/**
Expand Down Expand Up @@ -496,5 +507,6 @@ contract OriumSftMarketplace is Initializable, OwnableUpgradeable, PausableUpgra
function setOriumMarketplaceRoyalties(address _oriumMarketplaceRoyalties) external onlyOwner {
oriumMarketplaceRoyalties = _oriumMarketplaceRoyalties;
}

/** ######### Getters ########### **/
}
41 changes: 40 additions & 1 deletion test/OriumSftMarketplace.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable no-unexpected-multiline */
// SPDX-License-Identifier: CC0-1.0

import { ethers } from 'hardhat'
import { loadFixture, time } from '@nomicfoundation/hardhat-network-helpers'
import { deploySftMarketplaceContracts } from './fixtures/OriumSftMarketplaceFixture'
Expand Down Expand Up @@ -143,6 +144,7 @@ describe('OriumSftMarketplace', () => {
.connect(lender)
.setApprovalForAll(await SftRolesRegistrySingleRoleLegacy.getAddress(), true)
})

describe('When Rental Offer is not created', async () => {
describe('Create Rental Offer', async () => {
describe("When commitmentId doesn't exist", async () => {
Expand Down Expand Up @@ -674,6 +676,43 @@ describe('OriumSftMarketplace', () => {
marketplace.connect(borrower).acceptRentalOffer(rentalOffer, maxDuration),
).to.be.revertedWith('OriumSftMarketplace: expiration date is greater than offer deadline')
})
// New test case for accepting rental offer with native tokens
it('Should accept a rental offer with native tokens', async () => {
await marketplaceRoyalties
.connect(operator)
.setTrustedFeeTokenForToken([rentalOffer.tokenAddress], [AddressZero], [true])

rentalOffer.feeTokenAddress = AddressZero
rentalOffer.feeAmountPerSecond = toWei('0.0000001')
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)

// Check the borrower's balance before the transaction
const borrowerBalanceBefore = await ethers.provider.getBalance(borrower.address)
console.log('BEFORE')
console.log(borrowerBalanceBefore)

const blockTimestamp = (await ethers.provider.getBlock('latest'))?.timestamp
const expirationDate = Number(blockTimestamp) + duration + 1

await expect(
marketplace.connect(borrower).acceptRentalOffer(rentalOffer, duration, {
value: totalFeeAmount.toString(),
}),
)
.to.emit(marketplace, 'RentalStarted')
.withArgs(rentalOffer.lender, rentalOffer.nonce, borrower.address, expirationDate)

// Check the borrower's balance after the transaction
const borrowerBalanceAfter = await ethers.provider.getBalance(borrower.address)
expect(borrowerBalanceAfter).to.be.lt(borrowerBalanceBefore)

console.log('AFTER')
console.log(borrowerBalanceAfter)
})

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

0 comments on commit e23cd0d

Please sign in to comment.