diff --git a/contracts/contracts/FleekERC721.sol b/contracts/contracts/FleekERC721.sol index 71df46f..660a5ed 100644 --- a/contracts/contracts/FleekERC721.sol +++ b/contracts/contracts/FleekERC721.sol @@ -52,7 +52,6 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl { string ENS; // ENS ID uint256 currentBuild; // The current build number (Increments by one with each change, starts at zero) mapping(uint256 => Build) builds; // Mapping to build details for each build number - string[] accessPoints; // List of app AccessPoint string logo; uint24 color; // Color of the nft } @@ -70,7 +69,6 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl { */ struct AccessPoint { uint256 tokenId; - uint256 index; uint256 score; bool contentVerified; bool nameVerified; @@ -133,7 +131,6 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl { // The mint interaction is considered to be the first build of the site. Updates from now on all increment the currentBuild by one and update the mapping. app.currentBuild = 0; app.builds[0] = Build(commitHash, gitRepository); - app.accessPoints = new string[](0); return tokenId; } @@ -156,6 +153,29 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl { return string(abi.encodePacked(_baseURI(), app.toString(owner).toBase64())); } + /** + * @dev Returns the token metadata associated with the `tokenId`. + * + * Returns multiple string and uint values in relation to metadata fields of the App struct. + * + * Requirements: + * + * - the tokenId must be minted and valid. + * + */ + function getToken( + uint256 tokenId + ) + public + view + virtual + returns (string memory, string memory, string memory, string memory, uint256, string memory, uint24) + { + _requireMinted(tokenId); + App storage app = _apps[tokenId]; + return (app.name, app.description, app.externalURL, app.ENS, app.currentBuild, app.logo, app.color); + } + /** * @dev See {IERC165-supportsInterface}. */ @@ -347,8 +367,7 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl { _requireMinted(tokenId); require(_accessPoints[apName].owner == address(0), "FleekERC721: AP already exists"); - _accessPoints[apName] = AccessPoint(tokenId, _apps[tokenId].accessPoints.length, 0, false, false, msg.sender); - _apps[tokenId].accessPoints.push(apName); + _accessPoints[apName] = AccessPoint(tokenId, 0, false, false, msg.sender); emit NewAccessPoint(apName, tokenId, msg.sender); } @@ -367,18 +386,6 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl { function removeAccessPoint(string memory apName) public requireAP(apName) { require(msg.sender == _accessPoints[apName].owner, "FleekERC721: must be AP owner"); uint256 tokenId = _accessPoints[apName].tokenId; - App storage _app = _apps[tokenId]; - - // the index of the AP to remove - uint256 indexToRemove = _accessPoints[apName].index; - - // the last item is reposited in the index to remove - string memory lastAP = _app.accessPoints[_app.accessPoints.length - 1]; - _app.accessPoints[indexToRemove] = lastAP; - _accessPoints[lastAP].index = indexToRemove; - - // remove the last item - _app.accessPoints.pop(); delete _accessPoints[apName]; emit RemoveAccessPoint(apName, tokenId, msg.sender); @@ -479,19 +486,6 @@ contract FleekERC721 is Initializable, ERC721Upgradeable, FleekAccessControl { emit ChangeAccessPointNameVerify(apName, _accessPoints[apName].tokenId, verified, msg.sender); } - /** - * @dev A view function to gather the list of access points of a given app. - * - * Requirements: - * - * - the tokenId must be minted and valid. - * - */ - function appAccessPoints(uint256 tokenId) public view returns (string[] memory) { - _requireMinted(tokenId); - return _apps[tokenId].accessPoints; - } - /** * @dev Adds a new build to a minted `tokenId`'s builds mapping. * diff --git a/contracts/test/foundry/FleekERC721/AccessPoints.t.sol b/contracts/test/foundry/FleekERC721/AccessPoints.t.sol index 7795255..7e798e8 100644 --- a/contracts/test/foundry/FleekERC721/AccessPoints.t.sol +++ b/contracts/test/foundry/FleekERC721/AccessPoints.t.sol @@ -98,18 +98,6 @@ contract Test_FleekERC721_AccessPoint is Test_FleekERC721_Base { assertAccessPointJSON(accessPointName, "0", "0", "false", "false", deployer); } - function test_appAccessPoints() public { - CuT.addAccessPoint(tokenId, "accesspoint1.com"); - CuT.addAccessPoint(tokenId, "accesspoint2.com"); - CuT.addAccessPoint(tokenId, "accesspoint3.com"); - - string[] memory accessPoints = CuT.appAccessPoints(tokenId); - assertEq(accessPoints[0], "accesspoint1.com"); - assertEq(accessPoints[1], "accesspoint2.com"); - assertEq(accessPoints[2], "accesspoint3.com"); - assertEq(accessPoints.length, 3); - } - function test_cannotAddAccessPointToNonexistentToken() public { expectRevertWithInvalidTokenId(); CuT.addAccessPoint(1, "accesspoint.com"); diff --git a/contracts/test/foundry/FleekERC721/GetToken.t.sol b/contracts/test/foundry/FleekERC721/GetToken.t.sol new file mode 100644 index 0000000..0410be1 --- /dev/null +++ b/contracts/test/foundry/FleekERC721/GetToken.t.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.17; + +import "./TestBase.sol"; +import {TestConstants} from "./Constants.sol"; + +contract Test_FleekERC721_GetToken is Test_FleekERC721_Base { + uint256 internal tokenId; + + function setUp() public { + baseSetUp(); + tokenId = mintDefault(deployer); + } + + function test_getToken() public { + ( + string memory name, + string memory description, + string memory externalURL, + string memory ENS, + uint256 currentBuild, + string memory logo, + uint24 color + ) = CuT.getToken(tokenId); + assertEq(name, TestConstants.APP_NAME); + assertEq(description, TestConstants.APP_DESCRIPTION); + assertEq(externalURL, TestConstants.APP_EXTERNAL_URL); + assertEq(logo, TestConstants.LOGO_0); + assertEq(color, TestConstants.APP_COLOR); + assertEq(ENS, TestConstants.APP_ENS); + assertEq(currentBuild, 0); + } + + function test_getTokenAfterUpdate() public { + CuT.setTokenName(tokenId, "New App Name"); + CuT.setTokenDescription(tokenId, "New description for the app."); + CuT.setTokenExternalURL(tokenId, "https://new-url.com"); + CuT.setTokenENS(tokenId, "new-ens.eth"); + CuT.setTokenBuild(tokenId, "ce1a3fc141e29f8e1d00a654e156c4982d7711bf", "https://github.com/other/repo"); + CuT.setTokenLogoAndColor(tokenId, TestConstants.LOGO_1, 0x654321); + + ( + string memory name, + string memory description, + string memory externalURL, + string memory ENS, + uint256 currentBuild, + string memory logo, + uint24 color + ) = CuT.getToken(tokenId); + assertEq(name, "New App Name"); + assertEq(description, "New description for the app."); + assertEq(externalURL, "https://new-url.com"); + assertEq(logo, TestConstants.LOGO_1); + assertEq(color, 0x654321); + assertEq(ENS, "new-ens.eth"); + assertEq(currentBuild, 1); + } + + function test_getTokenForDifferentAddresses() public { + vm.prank(address(1)); + CuT.getToken(tokenId); + vm.prank(address(2)); + CuT.getToken(tokenId); + vm.prank(address(3)); + CuT.getToken(tokenId); + } + + function testFail_tokenURIForNonExistentId() public view { + CuT.getToken(1); + } +} diff --git a/contracts/test/hardhat/contracts/FleekERC721/access-points.t.ts b/contracts/test/hardhat/contracts/FleekERC721/access-points.t.ts index 3fb3f27..a4d084b 100644 --- a/contracts/test/hardhat/contracts/FleekERC721/access-points.t.ts +++ b/contracts/test/hardhat/contracts/FleekERC721/access-points.t.ts @@ -17,11 +17,6 @@ describe('AccessPoints', () => { await expect(contract.addAccessPoint(tokenId, 'random.com')) .to.emit(contract, 'NewAccessPoint') .withArgs('random.com', tokenId, owner.address); - - expect(await contract.appAccessPoints(tokenId)).eql([ - DefaultAP, - 'random.com', - ]); }); it('should return a AP json object', async () => { @@ -96,8 +91,6 @@ describe('AccessPoints', () => { await expect(contract.removeAccessPoint(DefaultAP)) .to.emit(contract, 'RemoveAccessPoint') .withArgs(DefaultAP, tokenId, owner.address); - - expect(await contract.appAccessPoints(tokenId)).eql([]); }); it('should allow only AP owner to remove it', async () => { @@ -169,43 +162,4 @@ describe('AccessPoints', () => { expect(parsedAp.nameVerified).to.be.false; }); - - it('should get a list of added APs for an app', async () => { - const { contract, tokenId } = fixture; - - await contract.addAccessPoint(tokenId, 'accesspoint1.com'); - await contract.addAccessPoint(tokenId, 'accesspoint2.com'); - await contract.addAccessPoint(tokenId, 'accesspoint3.com'); - await contract.addAccessPoint(tokenId, 'accesspoint4.com'); - - const aps = await contract.appAccessPoints(tokenId); - - expect(aps).to.eql([ - DefaultAP, - 'accesspoint1.com', - 'accesspoint2.com', - 'accesspoint3.com', - 'accesspoint4.com', - ]); - }); - - it('should get a list of added APs for an app after removing one', async () => { - const { contract, tokenId } = fixture; - - await contract.addAccessPoint(tokenId, 'accesspoint1.com'); - await contract.addAccessPoint(tokenId, 'accesspoint2.com'); - await contract.addAccessPoint(tokenId, 'accesspoint3.com'); - await contract.addAccessPoint(tokenId, 'accesspoint4.com'); - - await contract.removeAccessPoint('accesspoint2.com'); - - const aps = await contract.appAccessPoints(tokenId); - - expect(aps).to.eql([ - DefaultAP, - 'accesspoint1.com', - 'accesspoint4.com', - 'accesspoint3.com', - ]); - }); }); diff --git a/contracts/test/hardhat/contracts/FleekERC721/get-token.t.ts b/contracts/test/hardhat/contracts/FleekERC721/get-token.t.ts new file mode 100644 index 0000000..0b9d80e --- /dev/null +++ b/contracts/test/hardhat/contracts/FleekERC721/get-token.t.ts @@ -0,0 +1,28 @@ +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; +import { expect } from 'chai'; +import { TestConstants, Fixtures, parseTokenURI } from './helpers'; +import { ethers } from 'hardhat'; +const { MintParams } = TestConstants; + +describe('FleekERC721.GetToken', () => { + let fixture: Awaited>; + + beforeEach(async () => { + fixture = await loadFixture(Fixtures.withMint); + }); + + it('should return the token metadata without nested mappings', async () => { + const { contract, tokenId } = fixture; + const metadata = await contract.getToken(tokenId); + + expect(metadata).to.eql([ + MintParams.name, + MintParams.description, + MintParams.externalUrl, + MintParams.ens, + ethers.BigNumber.from(0), + MintParams.logo, + MintParams.color, + ]); + }); +});