Skip to content

Commit

Permalink
Add unit tests and get/set minter
Browse files Browse the repository at this point in the history
  • Loading branch information
motechFR committed Oct 22, 2024
1 parent 9b567cd commit 5856f15
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 3 deletions.
18 changes: 18 additions & 0 deletions __test__/contracts/BuilderNFTImplementation/read.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,3 +381,21 @@ describe('isValidUUID()', function () {
expect(isValid).toBe(false);
});
});

describe('read', function () {
describe('getMinter()', function () {
it('Should return the correct minter address', async function () {
const {
builderNft: { builderNftContract }
} = await loadContractFixtures();

const { userAccount } = await generateWallets();
const newMinter = userAccount.account.address;

await builderNftContract.write.setMinter([newMinter]);

const minter = await builderNftContract.read.getMinter();
expect(getAddress(minter)).toBe(getAddress(newMinter));
});
});
});
79 changes: 78 additions & 1 deletion __test__/contracts/BuilderNFTImplementation/write.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ describe('mintTo()', function () {
});

describe('permissions', function () {
it('Only admin can mint tokens to an account', async function () {
it('Admin can mint tokens to an account', async function () {
const {
builderNft: { builderNftContract }
} = await loadContractFixtures();
Expand All @@ -685,6 +685,38 @@ describe('mintTo()', function () {
})
).rejects.toThrow('Proxy: caller is not the admin');
});

it('Minter can mint tokens to an account', async function () {
const {
builderNft: { builderNftContract, builderNftAdminAccount }
} = await loadContractFixtures();

const { secondUserAccount, thirdUserAccount: minterAccount } = await generateWallets();
const testUserAddress = secondUserAccount.account.address;

const builderId = uuid();
await builderNftContract.write.registerBuilderToken([builderId]);

const scoutId = uuid();

await builderNftContract.write.setMinter([minterAccount.account.address]);

await expect(
builderNftContract.write.mintTo([testUserAddress, BigInt(1), BigInt(5), scoutId], {
account: builderNftAdminAccount.account
})
).resolves.toBeDefined();

await expect(
builderNftContract.write.mintTo([testUserAddress, BigInt(1), BigInt(10), scoutId], {
account: minterAccount.account
})
).resolves.toBeDefined();

const balance = await builderNftContract.read.balanceOf([testUserAddress, BigInt(1)]);

expect(balance).toBe(BigInt(15));
});
});

describe('validations', function () {
Expand Down Expand Up @@ -883,3 +915,48 @@ describe('setUriPrefixAndSuffix()', function () {
});
});
});

describe('setMinter()', function () {
describe('effects', function () {
it('Should set the minter address correctly', async function () {
const {
builderNft: { builderNftContract }
} = await loadContractFixtures();

const { userAccount } = await generateWallets();
const newMinter = userAccount.account.address;

await builderNftContract.write.setMinter([newMinter]);

const minter = await builderNftContract.read.getMinter();
expect(getAddress(minter)).toBe(getAddress(newMinter));
});
});

describe('permissions', function () {
it('Only admin can set the minter', async function () {
const {
builderNft: { builderNftContract }
} = await loadContractFixtures();

const { userAccount } = await generateWallets();
const newMinter = userAccount.account.address;

await expect(builderNftContract.write.setMinter([newMinter], { account: userAccount.account })).rejects.toThrow(
'Proxy: caller is not the admin'
);
});
});

describe('validations', function () {
it('Reverts when setting minter to zero address', async function () {
const {
builderNft: { builderNftContract }
} = await loadContractFixtures();

const zeroAddress = '0x0000000000000000000000000000000000000000';

await expect(builderNftContract.write.setMinter([zeroAddress])).rejects.toThrow('Invalid address');
});
});
});
26 changes: 26 additions & 0 deletions abis/BuilderNFTSeasonOneImplementation01.json
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getMinter",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getPriceIncrement",
Expand Down Expand Up @@ -560,6 +573,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "minter",
"type": "address"
}
],
"name": "setMinter",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
18 changes: 16 additions & 2 deletions contracts/BuilderNFTSeasonOneImplementation01.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ contract BuilderNFTSeasonOneImplementation01 is Context, ERC165, IERC1155, IERC1
_;
}

modifier onlyAdminOrMinter() {
require(MemoryUtils.isAdmin(msg.sender) || MemoryUtils.isMinter(msg.sender), "Proxy: caller is not the admin or minter");
_;
}

constructor () {}


Expand All @@ -55,7 +60,7 @@ contract BuilderNFTSeasonOneImplementation01 is Context, ERC165, IERC1155, IERC1
ImplementationStorage.layout().baseUri = newBaseUri;
}

function registerBuilderToken(string calldata builderId) external onlyAdmin() {
function registerBuilderToken(string calldata builderId) external onlyAdminOrMinter {
_registerBuilderToken(builderId);
}

Expand Down Expand Up @@ -148,8 +153,17 @@ contract BuilderNFTSeasonOneImplementation01 is Context, ERC165, IERC1155, IERC1
emit TransferSingle(msg.sender, account, address(0), tokenId, amount);
}

function setMinter(address minter) external onlyAdmin {
require(minter != address(0), "Invalid address");
MemoryUtils.setAddress(MemoryUtils.MINTER_SLOT, minter);
}

function getMinter() external view returns (address) {
return MemoryUtils.getAddress(MemoryUtils.MINTER_SLOT);
}


function mintTo(address account, uint256 tokenId, uint256 amount, string calldata scout) external onlyAdmin {
function mintTo(address account, uint256 tokenId, uint256 amount, string calldata scout) external onlyAdminOrMinter {
_validateMint(account, tokenId, scout);
_mintTo(account, tokenId, amount, scout);
}
Expand Down
5 changes: 5 additions & 0 deletions contracts/libs/MemoryUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ library MemoryUtils {
bytes32 internal constant NEXT_TOKEN_ID_SLOT = keccak256("builderNFT.nextTokenId");
bytes32 internal constant LOCK_STATUS_SLOT = keccak256("builderNFT.lockStatus");
bytes32 internal constant ADMIN_SLOT = keccak256("builderNFT.admin");
bytes32 internal constant MINTER_SLOT = keccak256("builderNFT.minterSlot");

bytes32 internal constant TOKEN_NAME = keccak256("token.name");
bytes32 internal constant TOKEN_SYMBOL = keccak256("token.symbol");
Expand Down Expand Up @@ -91,4 +92,8 @@ library MemoryUtils {
function isAdmin(address caller) internal view returns (bool) {
return caller == getAddress(ADMIN_SLOT);
}

function isMinter(address caller) internal view returns (bool) {
return caller == getAddress(MINTER_SLOT);
}
}

0 comments on commit 5856f15

Please sign in to comment.