feature: conditional payment as setting (#134)
* feat: add base contract for billing * feat: add withdraw function * feat: add billing requirement to mint * test: add foundry tests for minting with billing * refactor: remove transfer billing and add access point * test: add access point billing foundry tests * test: add test for billing value change * test: add hardhat test setup for billing * test: add hardhat tests for billing * feat: add withdrawn event and add public withdraw function * test: add tests for withdrawing founds and access control for billing * refactor: fix misspells and change variable names * feat: add initialize params for billing * feat: add gap to FleekBilling * fix: testname misspell
This commit is contained in:
parent
969cd12d92
commit
b8b8cb28ea
|
|
@ -0,0 +1,82 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.7;
|
||||
|
||||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||
|
||||
error RequiredPayment(uint requiredValue);
|
||||
|
||||
abstract contract FleekBilling is Initializable {
|
||||
/**
|
||||
* @dev Available billing values.
|
||||
*/
|
||||
enum Billing {
|
||||
Mint,
|
||||
AddAccessPoint
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Emitted when the billing value is changed.
|
||||
*/
|
||||
event BillingChanged(Billing key, uint256 price);
|
||||
|
||||
/**
|
||||
* @dev Emitted when contract is withdrawn.
|
||||
*/
|
||||
event Withdrawn(uint256 value, address indexed byAddress);
|
||||
|
||||
/**
|
||||
* @dev Mapping of billing values.
|
||||
*/
|
||||
mapping(Billing => uint256) public _billings;
|
||||
|
||||
/**
|
||||
* @dev Initializes the contract by setting default billing values.
|
||||
*/
|
||||
function __FleekBilling_init(uint256[] memory initialBillings) internal onlyInitializing {
|
||||
for (uint256 i = 0; i < initialBillings.length; i++) {
|
||||
_setBilling(Billing(i), initialBillings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the billing value for a given key.
|
||||
*/
|
||||
function getBilling(Billing key) public view returns (uint256) {
|
||||
return _billings[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the billing value for a given key.
|
||||
*/
|
||||
function _setBilling(Billing key, uint256 price) internal {
|
||||
_billings[key] = price;
|
||||
emit BillingChanged(key, price);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to require a payment value.
|
||||
*/
|
||||
function _requirePayment(Billing key) internal {
|
||||
uint256 requiredValue = _billings[key];
|
||||
if (msg.value != _billings[key]) revert RequiredPayment(requiredValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to withdraw the contract balance.
|
||||
*/
|
||||
function _withdraw() internal {
|
||||
address by = msg.sender;
|
||||
uint256 value = address(this).balance;
|
||||
|
||||
payable(by).transfer(value);
|
||||
emit Withdrawn(value, by);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev This empty reserved space is put in place to allow future versions to add new
|
||||
* variables without shifting down storage in the inheritance chain.
|
||||
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
||||
*/
|
||||
uint256[49] private __gap;
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
|
|||
import "@openzeppelin/contracts/utils/Base64.sol";
|
||||
import "@openzeppelin/contracts/utils/Strings.sol";
|
||||
import "./FleekAccessControl.sol";
|
||||
import "./FleekBilling.sol";
|
||||
import "./util/FleekStrings.sol";
|
||||
import "./FleekPausable.sol";
|
||||
|
||||
|
|
@ -18,7 +19,7 @@ error ThereIsNoTokenMinted();
|
|||
error InvalidTokenIdForAccessPoint();
|
||||
error AccessPointCreationStatusAlreadySet();
|
||||
|
||||
contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, FleekPausable {
|
||||
contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, FleekPausable, FleekBilling {
|
||||
using Strings for uint256;
|
||||
using FleekStrings for FleekERC721.App;
|
||||
using FleekStrings for FleekERC721.AccessPoint;
|
||||
|
|
@ -123,10 +124,14 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
|
|||
/**
|
||||
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
|
||||
*/
|
||||
function initialize(string memory _name, string memory _symbol) public initializer {
|
||||
function initialize(
|
||||
string memory _name,
|
||||
string memory _symbol,
|
||||
uint256[] memory initialBillings
|
||||
) public initializer {
|
||||
__ERC721_init(_name, _symbol);
|
||||
__FleekAccessControl_init();
|
||||
_appIds = 0;
|
||||
__FleekBilling_init(initialBillings);
|
||||
__FleekPausable_init();
|
||||
}
|
||||
|
||||
|
|
@ -146,6 +151,7 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
|
|||
* Requirements:
|
||||
*
|
||||
* - the caller must have ``collectionOwner``'s admin role.
|
||||
* - billing for the minting may be applied.
|
||||
* - the contract must be not paused.
|
||||
*
|
||||
*/
|
||||
|
|
@ -160,7 +166,7 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
|
|||
string memory logo,
|
||||
uint24 color,
|
||||
bool accessPointAutoApproval
|
||||
) public payable requireCollectionRole(CollectionRoles.Owner) returns (uint256) {
|
||||
) public payable requirePayment(Billing.Mint) requireCollectionRole(CollectionRoles.Owner) returns (uint256) {
|
||||
uint256 tokenId = _appIds;
|
||||
_mint(to, tokenId);
|
||||
|
||||
|
|
@ -448,11 +454,14 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
|
|||
* Requirements:
|
||||
*
|
||||
* - the tokenId must be minted and valid.
|
||||
* - billing for add acess point may be applied.
|
||||
* - the contract must be not paused.
|
||||
*
|
||||
* IMPORTANT: The payment is not set yet
|
||||
*/
|
||||
function addAccessPoint(uint256 tokenId, string memory apName) public payable whenNotPaused {
|
||||
function addAccessPoint(
|
||||
uint256 tokenId,
|
||||
string memory apName
|
||||
) public payable whenNotPaused requirePayment(Billing.AddAccessPoint) {
|
||||
// require(msg.value == 0.1 ether, "You need to pay at least 0.1 ETH"); // TODO: define a minimum price
|
||||
_requireMinted(tokenId);
|
||||
if (_accessPoints[apName].owner != address(0)) revert AccessPointAlreadyExists();
|
||||
|
|
@ -800,4 +809,44 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl, Fl
|
|||
function setPausable(bool pausable) public requireCollectionRole(CollectionRoles.Owner) {
|
||||
_setPausable(pausable);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////
|
||||
BILLING
|
||||
//////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @dev Modifier to require billing with a given key.
|
||||
*/
|
||||
modifier requirePayment(Billing key) {
|
||||
_requirePayment(key);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the billing value for a given key.
|
||||
*
|
||||
* May emit a {BillingChanged} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the sender must have the `collectionOwner` role.
|
||||
*
|
||||
*/
|
||||
function setBilling(Billing key, uint256 value) public requireCollectionRole(CollectionRoles.Owner) {
|
||||
_setBilling(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraws all the funds from contract.
|
||||
*
|
||||
* May emmit a {Withdrawn} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the sender must have the `collectionOwner` role.
|
||||
*
|
||||
*/
|
||||
function withdraw() public requireCollectionRole(CollectionRoles.Owner) {
|
||||
_withdraw();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ const { getProxyAddress, proxyStore } = require('./utils/proxy-store');
|
|||
const ARGUMENTS = [
|
||||
'FleekNFAs', // Collection name
|
||||
'FLKNFA', // Collection symbol
|
||||
[], // Billing values
|
||||
];
|
||||
|
||||
// --- Script Settings ---
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
pragma solidity ^0.8.17;
|
||||
|
||||
import "./TestBase.sol";
|
||||
import {FleekBilling} from "contracts/FleekBilling.sol";
|
||||
import "contracts/FleekAccessControl.sol";
|
||||
|
||||
contract Test_FleekERC721_AccessControlAssertions is Test {
|
||||
|
|
@ -17,10 +18,10 @@ contract Test_FleekERC721_AccessControlAssertions is Test {
|
|||
|
||||
contract Test_FleekERC721_AccessControl is Test_FleekERC721_Base, Test_FleekERC721_AccessControlAssertions {
|
||||
uint256 internal tokenId;
|
||||
address internal collectionOwner = address(1);
|
||||
address internal tokenOwner = address(3);
|
||||
address internal tokenController = address(4);
|
||||
address internal anyAddress = address(5);
|
||||
address internal collectionOwner = address(100);
|
||||
address internal tokenOwner = address(200);
|
||||
address internal tokenController = address(300);
|
||||
address internal anyAddress = address(400);
|
||||
|
||||
function setUp() public {
|
||||
baseSetUp();
|
||||
|
|
@ -357,6 +358,56 @@ contract Test_FleekERC721_AccessControl is Test_FleekERC721_Base, Test_FleekERC7
|
|||
CuT.burn(tokenId);
|
||||
}
|
||||
|
||||
function test_setBilling() public {
|
||||
// ColletionOwner
|
||||
vm.prank(collectionOwner);
|
||||
CuT.setBilling(FleekBilling.Billing.Mint, 1 ether);
|
||||
|
||||
// TokenOwner
|
||||
vm.prank(tokenOwner);
|
||||
expectRevertWithCollectionRole(FleekAccessControl.CollectionRoles.Owner);
|
||||
CuT.setBilling(FleekBilling.Billing.Mint, 2 ether);
|
||||
|
||||
// TokenController
|
||||
vm.prank(tokenController);
|
||||
expectRevertWithCollectionRole(FleekAccessControl.CollectionRoles.Owner);
|
||||
CuT.setBilling(FleekBilling.Billing.Mint, 2 ether);
|
||||
|
||||
// AnyAddress
|
||||
vm.prank(anyAddress);
|
||||
expectRevertWithCollectionRole(FleekAccessControl.CollectionRoles.Owner);
|
||||
CuT.setBilling(FleekBilling.Billing.Mint, 2 ether);
|
||||
}
|
||||
|
||||
function test_withdraw() public {
|
||||
// ColletionOwner
|
||||
vm.deal(address(CuT), 1 ether);
|
||||
vm.prank(collectionOwner);
|
||||
CuT.withdraw();
|
||||
|
||||
// TokenOwner
|
||||
vm.prank(tokenOwner);
|
||||
expectRevertWithCollectionRole(FleekAccessControl.CollectionRoles.Owner);
|
||||
CuT.withdraw();
|
||||
|
||||
// TokenController
|
||||
vm.prank(tokenController);
|
||||
expectRevertWithCollectionRole(FleekAccessControl.CollectionRoles.Owner);
|
||||
CuT.withdraw();
|
||||
|
||||
// AnyAddress
|
||||
vm.prank(anyAddress);
|
||||
expectRevertWithCollectionRole(FleekAccessControl.CollectionRoles.Owner);
|
||||
CuT.withdraw();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev `receive` and `fallback` are required for test contract receive ETH
|
||||
*/
|
||||
receive() external payable {}
|
||||
|
||||
fallback() external payable {}
|
||||
|
||||
function test_pauseAndUnpause() public {
|
||||
// ColletionOwner
|
||||
vm.startPrank(collectionOwner);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,164 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
import "./TestBase.sol";
|
||||
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
|
||||
import {FleekAccessControl} from "contracts/FleekAccessControl.sol";
|
||||
import "contracts/FleekBilling.sol";
|
||||
|
||||
contract Test_FleekERC721_BillingAssertions is Test {
|
||||
event BillingChanged(FleekBilling.Billing key, uint256 price);
|
||||
event Withdrawn(uint256 value, address indexed byAddress);
|
||||
|
||||
function expectRevertWithRequiredPayment(uint256 value) public {
|
||||
vm.expectRevert(abi.encodeWithSelector(RequiredPayment.selector, value));
|
||||
}
|
||||
|
||||
function expectEmitBillingChanged(FleekBilling.Billing key, uint256 price) public {
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit BillingChanged(key, price);
|
||||
}
|
||||
|
||||
function expectEmitWithdawn(uint256 value, address byAddress) public {
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit Withdrawn(value, byAddress);
|
||||
}
|
||||
}
|
||||
|
||||
contract Test_FleekERC721_Billing is Test_FleekERC721_Base, Test_FleekERC721_BillingAssertions {
|
||||
using Strings for address;
|
||||
uint256 internal tokenId;
|
||||
uint256 internal constant mintPrice = 1 ether;
|
||||
uint256 internal constant addAPPrice = 1 ether;
|
||||
|
||||
function setUp() public {
|
||||
baseSetUp();
|
||||
tokenId = mintDefault(deployer);
|
||||
CuT.setBilling(FleekBilling.Billing.Mint, mintPrice);
|
||||
CuT.setBilling(FleekBilling.Billing.AddAccessPoint, addAPPrice);
|
||||
}
|
||||
|
||||
function test_setUp() public {
|
||||
assertEq(CuT.getBilling(FleekBilling.Billing.Mint), mintPrice);
|
||||
assertEq(CuT.getBilling(FleekBilling.Billing.AddAccessPoint), addAPPrice);
|
||||
assertEq(address(CuT).balance, 0);
|
||||
}
|
||||
|
||||
function test_mint() public {
|
||||
CuT.mint{value: mintPrice}(
|
||||
deployer,
|
||||
TestConstants.APP_NAME,
|
||||
TestConstants.APP_DESCRIPTION,
|
||||
TestConstants.APP_EXTERNAL_URL,
|
||||
TestConstants.APP_ENS,
|
||||
TestConstants.APP_COMMIT_HASH,
|
||||
TestConstants.APP_GIT_REPOSITORY,
|
||||
TestConstants.LOGO_0,
|
||||
TestConstants.APP_COLOR,
|
||||
TestConstants.APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS
|
||||
);
|
||||
assertEq(CuT.ownerOf(tokenId), deployer);
|
||||
assertEq(address(CuT).balance, mintPrice);
|
||||
}
|
||||
|
||||
function testFuzz_cannotMintWithWrongValue(uint256 value) public {
|
||||
vm.assume(value != mintPrice);
|
||||
vm.deal(deployer, value);
|
||||
expectRevertWithRequiredPayment(mintPrice);
|
||||
CuT.mint{value: value}(
|
||||
deployer,
|
||||
TestConstants.APP_NAME,
|
||||
TestConstants.APP_DESCRIPTION,
|
||||
TestConstants.APP_EXTERNAL_URL,
|
||||
TestConstants.APP_ENS,
|
||||
TestConstants.APP_COMMIT_HASH,
|
||||
TestConstants.APP_GIT_REPOSITORY,
|
||||
TestConstants.LOGO_0,
|
||||
TestConstants.APP_COLOR,
|
||||
TestConstants.APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS
|
||||
);
|
||||
assertEq(address(CuT).balance, 0);
|
||||
}
|
||||
|
||||
function testFuzz_shouldChangeMintBillingValue(uint256 value) public {
|
||||
expectEmitBillingChanged(FleekBilling.Billing.Mint, value);
|
||||
CuT.setBilling(FleekBilling.Billing.Mint, value);
|
||||
|
||||
assertEq(CuT.getBilling(FleekBilling.Billing.Mint), value);
|
||||
|
||||
vm.deal(deployer, value);
|
||||
CuT.mint{value: value}(
|
||||
deployer,
|
||||
TestConstants.APP_NAME,
|
||||
TestConstants.APP_DESCRIPTION,
|
||||
TestConstants.APP_EXTERNAL_URL,
|
||||
TestConstants.APP_ENS,
|
||||
TestConstants.APP_COMMIT_HASH,
|
||||
TestConstants.APP_GIT_REPOSITORY,
|
||||
TestConstants.LOGO_0,
|
||||
TestConstants.APP_COLOR,
|
||||
TestConstants.APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS
|
||||
);
|
||||
assertEq(CuT.ownerOf(tokenId), deployer);
|
||||
assertEq(address(CuT).balance, value);
|
||||
}
|
||||
|
||||
function test_addAccessPoint() public {
|
||||
CuT.addAccessPoint{value: addAPPrice}(tokenId, "accesspoint.com");
|
||||
assertFalse(CuT.isAccessPointNameVerified("accesspoint.com"));
|
||||
assertEq(address(CuT).balance, addAPPrice);
|
||||
}
|
||||
|
||||
function testFuzz_cannotAddAccessPointWithWrongValue(uint256 value) public {
|
||||
vm.assume(value != addAPPrice);
|
||||
vm.deal(deployer, value);
|
||||
expectRevertWithRequiredPayment(addAPPrice);
|
||||
CuT.addAccessPoint{value: value}(tokenId, "accesspoint.com");
|
||||
assertEq(address(CuT).balance, 0);
|
||||
}
|
||||
|
||||
function testFuzz_shouldChangeAddAPBillingValue(uint256 value) public {
|
||||
expectEmitBillingChanged(FleekBilling.Billing.AddAccessPoint, value);
|
||||
CuT.setBilling(FleekBilling.Billing.AddAccessPoint, value);
|
||||
|
||||
assertEq(CuT.getBilling(FleekBilling.Billing.AddAccessPoint), value);
|
||||
|
||||
vm.deal(deployer, value);
|
||||
CuT.addAccessPoint{value: value}(tokenId, "accesspoint.com");
|
||||
assertFalse(CuT.isAccessPointNameVerified("accesspoint.com"));
|
||||
assertEq(address(CuT).balance, value);
|
||||
}
|
||||
|
||||
function testFuzz_shouldWithdrawAnyContractFunds(uint128 value) public {
|
||||
uint256 balanceBefore = address(this).balance;
|
||||
vm.deal(address(CuT), value);
|
||||
CuT.withdraw();
|
||||
assertEq(address(this).balance, value + balanceBefore);
|
||||
}
|
||||
|
||||
function testFuzz_shouldWithdrawAllContractFundsAfterPayableCall(uint8 iterations) public {
|
||||
// this test is going to add access points up to 256 times and then withdraw all funds
|
||||
uint256 balanceBefore = address(this).balance;
|
||||
address randomAddress = address(1);
|
||||
uint256 totalExpectedValue = iterations * addAPPrice;
|
||||
|
||||
vm.deal(randomAddress, totalExpectedValue);
|
||||
vm.startPrank(randomAddress);
|
||||
for (uint256 i = 0; i < iterations; i++) {
|
||||
CuT.addAccessPoint{value: addAPPrice}(tokenId, Strings.toString(i));
|
||||
}
|
||||
vm.stopPrank();
|
||||
|
||||
expectEmitWithdawn(totalExpectedValue, deployer);
|
||||
CuT.withdraw();
|
||||
assertEq(address(this).balance, totalExpectedValue + balanceBefore);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev `receive` and `fallback` are required for test contract receive ETH
|
||||
*/
|
||||
receive() external payable {}
|
||||
|
||||
fallback() external payable {}
|
||||
}
|
||||
|
|
@ -17,6 +17,8 @@ library TestConstants {
|
|||
|
||||
uint24 public constant APP_COLOR = 0x123456;
|
||||
|
||||
bool public constant APP_ACCESS_POINT_AUTO_APPROVAL_SETTINGS = true;
|
||||
|
||||
string public constant LOGO_0 =
|
||||
"data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI1MDAiIHdpZHRoPSIyMTgzIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjQgMTQxLjUzMTk5OTk5OTk5OTk4Ij48cGF0aCBkPSJNMTAuMzgzIDEyNi44OTRMMCAwbDEyNCAuMjU1LTEwLjk3OSAxMjYuNjM5LTUwLjU1MyAxNC42Mzh6IiBmaWxsPSIjZTM0ZjI2Ii8+PHBhdGggZD0iTTYyLjQ2OCAxMjkuMjc3VjEyLjA4NWw1MS4wNjQuMTctOS4xMDYgMTA0Ljg1MXoiIGZpbGw9IiNlZjY1MmEiLz48cGF0aCBkPSJNOTkuNDkgNDEuMzYybDEuNDQ2LTE1LjQ5SDIyLjM4M2w0LjM0IDQ3LjQ5aDU0LjIxM0w3OC44MSA5My42MTdsLTE3LjM2MiA0LjY4LTE3LjYxNy01LjEwNi0uOTM2LTEyLjA4NUgyNy4zMTlsMi4xMjggMjQuNjgxIDMyIDguOTM2IDMyLjI1NS04LjkzNiA0LjM0LTQ4LjE3SDQxLjEwN0wzOS40OSA0MS4zNjJ6IiBmaWxsPSIjZmZmIi8+PC9zdmc+";
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ contract Test_FleekERC721_Deploy is Test_FleekERC721_Base {
|
|||
|
||||
function testFuzz_nameAndSymbol(string memory _name, string memory _symbol) public {
|
||||
CuT = new FleekERC721();
|
||||
CuT.initialize(_name, _symbol);
|
||||
CuT.initialize(_name, _symbol, new uint256[](0));
|
||||
|
||||
assertEq(CuT.name(), _name);
|
||||
assertEq(CuT.symbol(), _symbol);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ abstract contract Test_FleekERC721_Base is Test, Test_FleekERC721_Assertions {
|
|||
|
||||
function baseSetUp() internal {
|
||||
CuT = new FleekERC721();
|
||||
CuT.initialize("Test Contract", "FLKAPS");
|
||||
CuT.initialize("Test Contract", "FLKAPS", new uint256[](0));
|
||||
deployer = address(this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
|
||||
import { ethers } from 'hardhat';
|
||||
import { expect } from 'chai';
|
||||
import { Fixtures, TestConstants, Errors } from './helpers';
|
||||
|
||||
const { Billing, MintParams } = TestConstants;
|
||||
|
||||
describe('FleekERC721.Billing', () => {
|
||||
let fixture: Awaited<ReturnType<typeof Fixtures.withMint>>;
|
||||
const mintPrice = ethers.utils.parseEther('1');
|
||||
const addAPPrice = ethers.utils.parseEther('1');
|
||||
|
||||
const mint = (value?: any) => {
|
||||
const { contract, owner } = fixture;
|
||||
return contract.mint(
|
||||
owner.address,
|
||||
MintParams.name,
|
||||
MintParams.description,
|
||||
MintParams.externalUrl,
|
||||
MintParams.ens,
|
||||
MintParams.commitHash,
|
||||
MintParams.gitRepository,
|
||||
MintParams.logo,
|
||||
MintParams.color,
|
||||
MintParams.accessPointAutoApprovalSettings,
|
||||
{ value }
|
||||
);
|
||||
};
|
||||
|
||||
const addAP = (value?: any) => {
|
||||
const { contract } = fixture;
|
||||
return contract.addAccessPoint(0, 'random.com', { value });
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
fixture = await loadFixture(Fixtures.withMint);
|
||||
const { contract } = fixture;
|
||||
await contract.setBilling(Billing.Mint, mintPrice);
|
||||
await contract.setBilling(Billing.AddAccessPoint, addAPPrice);
|
||||
});
|
||||
|
||||
it('should start with mint prices', async () => {
|
||||
const { contract } = fixture;
|
||||
expect(await contract.getBilling(Billing.Mint)).to.equal(mintPrice);
|
||||
expect(await contract.getBilling(Billing.AddAccessPoint)).to.equal(
|
||||
addAPPrice
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow mint with transfer', async () => {
|
||||
const { contract, owner } = fixture;
|
||||
await mint(mintPrice);
|
||||
console.log('hit');
|
||||
expect(await contract.ownerOf(0)).to.equal(owner.address);
|
||||
});
|
||||
|
||||
it('should not allow mint with empty value', async () => {
|
||||
const { contract } = fixture;
|
||||
await expect(mint())
|
||||
.to.be.revertedWithCustomError(contract, Errors.RequiredPayment)
|
||||
.withArgs(mintPrice);
|
||||
});
|
||||
|
||||
it('should not allow mint with different value', async () => {
|
||||
const { contract } = fixture;
|
||||
await expect(mint(ethers.utils.parseEther('2')))
|
||||
.to.be.revertedWithCustomError(contract, Errors.RequiredPayment)
|
||||
.withArgs(mintPrice);
|
||||
});
|
||||
|
||||
it('should allow add access point with transfer', async () => {
|
||||
const { contract } = fixture;
|
||||
await addAP(addAPPrice);
|
||||
expect(await contract.getAccessPointJSON('random.com')).to.exist;
|
||||
});
|
||||
|
||||
it('should not allow add access point with empty value', async () => {
|
||||
const { contract } = fixture;
|
||||
await expect(addAP())
|
||||
.to.be.revertedWithCustomError(contract, Errors.RequiredPayment)
|
||||
.withArgs(addAPPrice);
|
||||
});
|
||||
|
||||
it('should not allow add access point with different value', async () => {
|
||||
const { contract } = fixture;
|
||||
await expect(addAP(ethers.utils.parseEther('2')))
|
||||
.to.be.revertedWithCustomError(contract, Errors.RequiredPayment)
|
||||
.withArgs(addAPPrice);
|
||||
});
|
||||
});
|
||||
|
|
@ -11,6 +11,10 @@ export const TestConstants = Object.freeze({
|
|||
REJECTED: 2,
|
||||
REMOVED: 3,
|
||||
},
|
||||
Billing: {
|
||||
Mint: 0,
|
||||
AddAccessPoint: 1,
|
||||
},
|
||||
MintParams: {
|
||||
name: 'Fleek Test App',
|
||||
description: 'Fleek Test App Description',
|
||||
|
|
|
|||
|
|
@ -13,4 +13,5 @@ export const Errors = Object.freeze({
|
|||
ContractIsNotPausable: 'ContractIsNotPausable',
|
||||
PausableIsSetTo: 'PausableIsSetTo',
|
||||
ThereIsNoTokenMinted: 'ThereIsNoTokenMinted',
|
||||
RequiredPayment: 'RequiredPayment',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,11 +16,13 @@ export abstract class Fixtures {
|
|||
const Contract = await ethers.getContractFactory('FleekERC721', {
|
||||
libraries,
|
||||
});
|
||||
|
||||
const contract = await upgrades.deployProxy(
|
||||
Contract,
|
||||
[
|
||||
TestConstants.CollectionParams.name,
|
||||
TestConstants.CollectionParams.symbol,
|
||||
[], // Initial Billings
|
||||
],
|
||||
{
|
||||
unsafeAllow: ['external-library-linking'],
|
||||
|
|
|
|||
Loading…
Reference in New Issue