Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add baseTokenURI to ERC721Metadata #1970

Merged
merged 15 commits into from
Nov 15, 2019
8 changes: 8 additions & 0 deletions contracts/mocks/ERC721FullMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,12 @@ contract ERC721FullMock is ERC721Full, ERC721Mintable, ERC721MetadataMintable, E
function setTokenURI(uint256 tokenId, string memory uri) public {
_setTokenURI(tokenId, uri);
}

function setBaseTokenURI(string memory baseURI) public {
_setBaseTokenURI(baseURI);
}

function baseTokenURI() public view returns (string memory) {
return _baseTokenURI();
}
}
30 changes: 29 additions & 1 deletion contracts/token/ERC721/ERC721Metadata.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
// Token symbol
string private _symbol;

// Base URI
string private _baseURI;

// Optional mapping for token URIs
mapping(uint256 => string) private _tokenURIs;

Expand Down Expand Up @@ -56,7 +59,16 @@ contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
* Throws if the token ID does not exist. May return an empty string.
nventuro marked this conversation as resolved.
Show resolved Hide resolved
* @param tokenId uint256 ID of the token to query
*/
function tokenURI(uint256 tokenId) external view returns (string memory) {
function tokenURI(uint256 tokenId) public view returns (string memory) {
return string(abi.encodePacked(_baseTokenURI(), _tokenURI(tokenId)));
nventuro marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* @dev Internal returns an URI for a given token ID.
* Throws if the token ID does not exist. May return an empty string.
* @param tokenId uint256 ID of the token to query
*/
function _tokenURI(uint256 tokenId) internal view returns (string memory) {
nventuro marked this conversation as resolved.
Show resolved Hide resolved
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
return _tokenURIs[tokenId];
}
Expand All @@ -72,6 +84,22 @@ contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
_tokenURIs[tokenId] = uri;
}

/**
* @dev Internal function to get the base token URI.
nventuro marked this conversation as resolved.
Show resolved Hide resolved
* @return string representing the base token URI
*/
function _baseTokenURI() internal view returns (string memory) {
return _baseURI;
}

/**
* @dev Internal function to set the base token URI.
* @param uri string base URI to assign
*/
function _setBaseTokenURI(string memory uri) internal {
_baseURI = uri;
}

/**
* @dev Internal function to burn a specific token.
* Reverts if the token does not exist.
Expand Down
23 changes: 22 additions & 1 deletion test/token/ERC721/ERC721Full.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ contract('ERC721Full', function ([
});

describe('metadata', function () {
const baseURI = 'https://api.com/v1/';
const sampleUri = 'mock://mytoken';

it('has a name', async function () {
expect(await this.token.name()).to.be.equal(name);
});
Expand All @@ -82,11 +82,32 @@ contract('ERC721Full', function ([
expect(await this.token.symbol()).to.be.equal(symbol);
});

it('sets and returns the base token URI', async function () {
await this.token.setBaseTokenURI(baseURI);
expect(await this.token.baseTokenURI()).to.be.equal(baseURI);
});

it('sets and returns metadata for a token id', async function () {
await this.token.setTokenURI(firstTokenId, sampleUri);
expect(await this.token.tokenURI(firstTokenId)).to.be.equal(sampleUri);
});

it('sets and returns metadata for a token id with base token URI set', async function () {
await this.token.setBaseTokenURI(baseURI);
await this.token.setTokenURI(firstTokenId, sampleUri);
expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + sampleUri);
});

it('changes base token URI set', async function () {
await this.token.setBaseTokenURI(baseURI);
await this.token.setTokenURI(firstTokenId, sampleUri);
expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + sampleUri);

const newBaseURI = 'https://api.com/v2/';
await this.token.setBaseTokenURI(newBaseURI);
expect(await this.token.tokenURI(firstTokenId)).to.be.equal(newBaseURI + sampleUri);
});

it('reverts when setting metadata for non existent token id', async function () {
await expectRevert(
this.token.setTokenURI(nonExistentTokenId, sampleUri), 'ERC721Metadata: URI set of nonexistent token'
Expand Down