Skip to content

Commit

Permalink
Misc fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
0xGh authored Dec 11, 2023
2 parents 26fb785 + 06d3977 commit 0cbfd7e
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 25 deletions.
12 changes: 6 additions & 6 deletions contracts/ERC721Baseline.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {Utils} from "./Utils.sol";
* @custom:version v0.1.0-alpha.3
* @notice A baseline ERC721 contract implementation that exposes internal methods to a proxy instance.
*/

contract ERC721Baseline is ERC721, IERC2981, IERC721Baseline {

/**
Expand All @@ -39,6 +38,9 @@ contract ERC721Baseline is ERC721, IERC2981, IERC721Baseline {
* Supported Interfaces
************************************************/

/**
* @inheritdoc IERC165
*/
function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC721) returns (bool) {
return (
interfaceId == /* NFT Royalty Standard */ type(IERC2981).interfaceId ||
Expand Down Expand Up @@ -105,8 +107,6 @@ contract ERC721Baseline is ERC721, IERC2981, IERC721Baseline {
return _symbol;
}

event MetadataUpdate(uint256 tokenId);

/**
* Metadata > Token URI
*/
Expand Down Expand Up @@ -199,7 +199,7 @@ contract ERC721Baseline is ERC721, IERC2981, IERC721Baseline {
function royaltyInfo(
uint256,
uint256
) external pure returns (address receiver, uint256 royaltyAmount) {
) external pure returns (address, uint256) {
return (address(0), 0);
}

Expand Down Expand Up @@ -488,14 +488,14 @@ contract ERC721Baseline is ERC721, IERC2981, IERC721Baseline {
/**
* @inheritdoc IERC721Baseline
*/
function recover(bytes32 hash, bytes memory signature) external view returns (address result) {
function recover(bytes32 hash, bytes memory signature) external view returns (address) {
return Utils.recover(Utils.toEthSignedMessageHash(hash), signature);
}

/**
* @inheritdoc IERC721Baseline
*/
function recoverCalldata(bytes32 hash, bytes calldata signature) external view returns (address result) {
function recoverCalldata(bytes32 hash, bytes calldata signature) external view returns (address) {
return Utils.recoverCalldata(Utils.toEthSignedMessageHash(hash), signature);
}

Expand Down
40 changes: 36 additions & 4 deletions contracts/IERC721Baseline.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
* @custom:version v0.1.0-alpha.3
* @notice A baseline ERC721 contract implementation that exposes internal methods to a proxy instance.
*/

interface IERC721Baseline is IERC721 {

/**
Expand Down Expand Up @@ -44,6 +43,29 @@ interface IERC721Baseline is IERC721 {
* Metadata
************************************************/

/**
* Metadata > ERC-4906 events
*/

/**
* @dev This event emits when the metadata of a token is changed.
* So that the third-party platforms such as NFT market could
* timely update the images and related attributes of the NFT.
*
* @param _tokenId the token ID being updated
*/
event MetadataUpdate(uint256 _tokenId);

/**
* @dev This event emits when the metadata of a range of tokens is changed.
* So that the third-party platforms such as NFT market could
* timely update the images and related attributes of the NFTs.
*
* @param _fromTokenId the starting token ID
* @param _toTokenId the ending token ID
*/
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);

/**
* @notice The total minted supply.
* @dev The supply is decreased when a token is burned.
Expand Down Expand Up @@ -72,6 +94,8 @@ interface IERC721Baseline is IERC721 {
/**
* @notice Sets the token URI for a token ID.
* @dev Emits EIP-4906's `MetadataUpdate` event with the `tokenId`.
* This method is internal and only the proxy contract can call it.
*
*
* @param tokenId token ID
* @param tokenURI URI pointing to the metadata
Expand All @@ -80,6 +104,7 @@ interface IERC721Baseline is IERC721 {

/**
* @notice Returns the shared URI for the tokens.
* @dev This method is internal and only the proxy contract can call it.
*/
function __sharedURI() external view returns (string memory);

Expand All @@ -89,6 +114,8 @@ interface IERC721Baseline is IERC721 {
* because ERC721Baseline allows to mint any token ID, starting at any index.
* The proxy should emit `BatchMetadataUpdate`.
*
* This method is internal and only the proxy contract can call it.
*
* @param sharedURI shared URI for the tokens
*/
function __setSharedURI(string calldata sharedURI) external;
Expand All @@ -105,6 +132,8 @@ interface IERC721Baseline is IERC721 {
* because ERC721Baseline allows to mint any token ID, starting at any index.
* The proxy should emit `BatchMetadataUpdate`.
*
* This method is internal and only the proxy contract can call it.
*
* @param baseURI shared base URI for the tokens
*/
function __setBaseURI(string calldata baseURI) external;
Expand Down Expand Up @@ -173,15 +202,13 @@ interface IERC721Baseline is IERC721 {

/**
* @dev See {ERC721-_checkOnERC721Received}.
* This method is internal and only the proxy contract can call it.
*
* @dev NOTE that this method accepts an additional first parameter that is the original transaction's `msg.sender`.
* NOTE: this method accepts an additional first parameter that is the original transaction's `msg.sender`.
*/
function __checkOnERC721Received(address sender, address from, address to, uint256 tokenId, bytes memory data) external;

/**
* @dev See {ERC721-_isAuthorized}.
* This method is internal and only the proxy contract can call it.
*/
function __isAuthorized(address owner, address spender, uint256 tokenId) external view returns (bool);

Expand Down Expand Up @@ -292,6 +319,11 @@ interface IERC721Baseline is IERC721 {
* Utils
************************************************/

/**
* @dev Indicates an invalid signature.
*/
error InvalidSignature();

/**
* @notice Recovers the signer's address from a message digest `hash`, and the `signature`.
*
Expand Down
3 changes: 0 additions & 3 deletions contracts/Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@ pragma solidity 0.8.21;
* @custom:version v0.1.0-alpha.3
* @notice Utilities used in ERC721Baseline.
*/

library Utils {
/************************************************
* ECDSA Utils
************************************************/

error InvalidSignature();

/**
* recover
*
Expand Down
1 change: 0 additions & 1 deletion contracts/mocks/ERC721ConstructorAttackerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {IERC721Baseline} from "../IERC721Baseline.sol";

/// @title {title}
/// @author {name}

contract ERC721ConstructorAttackerMock {
constructor(address ERC721BaselineImplementation) {
IERC721Baseline(ERC721BaselineImplementation).initialize("hack", "HACK");
Expand Down
3 changes: 0 additions & 3 deletions contracts/mocks/ERC721ProxyMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {IERC721Baseline} from "../IERC721Baseline.sol";

/// @title {title}
/// @author {name}

contract ERC721ProxyMock is Proxy {

IERC721Baseline baseline = IERC721Baseline(address(this));
Expand Down Expand Up @@ -78,8 +77,6 @@ contract ERC721ProxyMock is Proxy {

require(_beforeTokenTransferHookEnabled, 'not enabled');

// @todo Try to alter state and make sure it is not reflected in the implementation.

if (sender == to) {
revert('Call to self');
}
Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"truffle": "^5.11.2"
},
"dependencies": {
"@openzeppelin/contracts": "5.0.0"
"@openzeppelin/contracts": "5.0.1"
},
"prettier": {
"plugins": [
Expand Down
84 changes: 84 additions & 0 deletions test/ERC721Baseline.js
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,90 @@ contract(
});
});

describe("Metadata", () => {
it("sets name and symbols", async () => {
assert.equal("Test", await proxyDelegate.name());
assert.equal("TEST", await proxyDelegate.symbol());
});

it("updates totalSupply correctly", async () => {
await proxy.onlyProxy_mint(user, 3);
assert.equal(1, await proxyDelegate.totalSupply());
await proxy.onlyProxy_burn(3, { from: user });
assert.equal(0, await proxyDelegate.totalSupply());
});

describe("token URI", () => {
const tokenId = 3;

beforeEach(async () => {
await proxy.onlyProxy_mint(user, tokenId);
});

it("throws if the token does not exist", async () => {
await expectRevert(
proxyDelegate.tokenURI(100),
"ERC721NonexistentToken(uint256)",
);
});

it("returns empty string when nothing is set", async () => {
assert.equal("", await proxyDelegate.tokenURI(tokenId));
});

it("returns token-specific URI when set", async () => {
const anotherTokenId = tokenId + 1;
const uri = "ipfs://test";

await proxy.onlyProxy_mint(user, anotherTokenId, uri);

assert.equal(uri, await proxyDelegate.tokenURI(anotherTokenId));
assert.equal(uri, await proxyDelegate.__tokenURI(anotherTokenId));

assert.equal("", await proxyDelegate.tokenURI(tokenId));
});

it("can update token-specific URI and emits MetadataUpdate", async () => {
const uri = "ipfs://updated";
const receipt = await proxy.onlyProxy_setTokenURI(tokenId, uri);

await expectEvent.inTransaction(
receipt.tx,
proxyDelegate,
"MetadataUpdate",
{
_tokenId: String(tokenId),
},
);

assert.equal(uri, await proxyDelegate.tokenURI(tokenId));
assert.equal(uri, await proxyDelegate.__tokenURI(tokenId));
});

it("can define shared URI", async () => {
const uri = "ipfs://shared";

const anotherTokenId = tokenId + 1;
await proxy.onlyProxy_mint(user, anotherTokenId);

await proxy.onlyProxy_setSharedURI(uri);

assert.equal(uri, await proxyDelegate.tokenURI(anotherTokenId));
assert.equal(
await proxyDelegate.tokenURI(tokenId),
await proxyDelegate.tokenURI(anotherTokenId),
);
});

it("can set base URI", async () => {
const uri = "ipfs://base/";
await proxy.onlyProxy_setBaseURI(uri);

assert.equal(uri + tokenId, await proxyDelegate.tokenURI(tokenId));
});
});
});

describe("Utils", () => {
describe("recover", () => {
const signer = web3.eth.accounts.create();
Expand Down

0 comments on commit 0cbfd7e

Please sign in to comment.