-
Notifications
You must be signed in to change notification settings - Fork 11.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add ERC721URIStorage-like extension for ERC1155 * Add tests for ERC1155URIStorage extension * add changelog entry for ERC721URIStorage * Fix linting errors * Emit URI event in ERC1155URIStorage * Remove exists check and ERC1155Supply dependency * Fix lint error * Overwrite ERC1155 uri method * Update ERC1155URIStorage specs * Fix ERC1155URIStorageMock * Rename _setTokenURI => _setURI in ERC1155URIStorage * Add baseURI to ERC1155URIStorage * Move super.uri call in ERC1155URIStorage * Clearify ERC1155URIStorage description in change log * reorder changelog & add documentation * improve documentation * fix typo Co-authored-by: Hadrien Croubois <[email protected]>
- Loading branch information
Showing
5 changed files
with
157 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
import "./ERC1155Mock.sol"; | ||
import "../token/ERC1155/extensions/ERC1155URIStorage.sol"; | ||
|
||
contract ERC1155URIStorageMock is ERC1155Mock, ERC1155URIStorage { | ||
constructor(string memory _uri) ERC1155Mock(_uri) {} | ||
|
||
function uri(uint256 tokenId) public view virtual override(ERC1155, ERC1155URIStorage) returns (string memory) { | ||
return ERC1155URIStorage.uri(tokenId); | ||
} | ||
|
||
function setURI(uint256 tokenId, string memory _tokenURI) public { | ||
_setURI(tokenId, _tokenURI); | ||
} | ||
|
||
function setBaseURI(string memory baseURI) public { | ||
_setBaseURI(baseURI); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
import "../../../utils/Strings.sol"; | ||
import "../ERC1155.sol"; | ||
|
||
/** | ||
* @dev ERC1155 token with storage based token URI management. | ||
* Inspired by the ERC721URIStorage extension | ||
* | ||
* _Available since v4.6._ | ||
*/ | ||
abstract contract ERC1155URIStorage is ERC1155 { | ||
using Strings for uint256; | ||
|
||
// Optional base URI | ||
string private _baseURI = ""; | ||
|
||
// Optional mapping for token URIs | ||
mapping(uint256 => string) private _tokenURIs; | ||
|
||
/** | ||
* @dev See {IERC1155MetadataURI-uri}. | ||
* | ||
* This implementation returns the concatenation of the `_baseURI` | ||
* and the token-specific uri if the latter is set | ||
* | ||
* This enables the following behaviors: | ||
* | ||
* - if `_tokenURIs[tokenId]` is set, then the result is the concatenation | ||
* of `_baseURI` and `_tokenURIs[tokenId]` (keep in mind that `_baseURI` | ||
* is empty per default); | ||
* | ||
* - if `_tokenURIs[tokenId]` is NOT set then we fallback to `super.uri()` | ||
* which in most cases will contain `ERC1155._uri`; | ||
* | ||
* - if `_tokenURIs[tokenId]` is NOT set, and if the parents do not have a | ||
* uri value set, then the result is empty. | ||
*/ | ||
function uri(uint256 tokenId) public view virtual override returns (string memory) { | ||
string memory tokenURI = _tokenURIs[tokenId]; | ||
|
||
// If token URI is set, concatenate base URI and tokenURI (via abi.encodePacked). | ||
return bytes(tokenURI).length > 0 ? string(abi.encodePacked(_baseURI, tokenURI)) : super.uri(tokenId); | ||
} | ||
|
||
/** | ||
* @dev Sets `tokenURI` as the tokenURI of `tokenId`. | ||
*/ | ||
function _setURI(uint256 tokenId, string memory tokenURI) internal virtual { | ||
_tokenURIs[tokenId] = tokenURI; | ||
emit URI(uri(tokenId), tokenId); | ||
} | ||
|
||
/** | ||
* @dev Sets `baseURI` as the `_baseURI` for all tokens | ||
*/ | ||
function _setBaseURI(string memory baseURI) internal virtual { | ||
_baseURI = baseURI; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
const { BN, expectEvent } = require('@openzeppelin/test-helpers'); | ||
|
||
const { expect } = require('chai'); | ||
const { artifacts } = require('hardhat'); | ||
|
||
const ERC1155URIStorageMock = artifacts.require('ERC1155URIStorageMock'); | ||
|
||
contract(['ERC1155URIStorage'], function (accounts) { | ||
const [ holder ] = accounts; | ||
|
||
const erc1155Uri = 'https://token.com/nfts/'; | ||
const baseUri = 'https://token.com/'; | ||
|
||
const tokenId = new BN('1'); | ||
const amount = new BN('3000'); | ||
|
||
describe('with base uri set', function () { | ||
beforeEach(async function () { | ||
this.token = await ERC1155URIStorageMock.new(erc1155Uri); | ||
this.token.setBaseURI(baseUri); | ||
|
||
await this.token.mint(holder, tokenId, amount, '0x'); | ||
}); | ||
|
||
it('can request the token uri, returning the erc1155 uri if no token uri was set', async function () { | ||
const receivedTokenUri = await this.token.uri(tokenId); | ||
|
||
expect(receivedTokenUri).to.be.equal(erc1155Uri); | ||
}); | ||
|
||
it('can request the token uri, returning the concatenated uri if a token uri was set', async function () { | ||
const tokenUri = '1234/'; | ||
const receipt = await this.token.setURI(tokenId, tokenUri); | ||
|
||
const receivedTokenUri = await this.token.uri(tokenId); | ||
|
||
const expectedUri = `${baseUri}${tokenUri}`; | ||
expect(receivedTokenUri).to.be.equal(expectedUri); | ||
expectEvent(receipt, 'URI', { value: expectedUri, id: tokenId }); | ||
}); | ||
}); | ||
|
||
describe('with base uri set to the empty string', function () { | ||
beforeEach(async function () { | ||
this.token = await ERC1155URIStorageMock.new(''); | ||
|
||
await this.token.mint(holder, tokenId, amount, '0x'); | ||
}); | ||
|
||
it('can request the token uri, returning an empty string if no token uri was set', async function () { | ||
const receivedTokenUri = await this.token.uri(tokenId); | ||
|
||
expect(receivedTokenUri).to.be.equal(''); | ||
}); | ||
|
||
it('can request the token uri, returning the token uri if a token uri was set', async function () { | ||
const tokenUri = 'ipfs://1234/'; | ||
const receipt = await this.token.setURI(tokenId, tokenUri); | ||
|
||
const receivedTokenUri = await this.token.uri(tokenId); | ||
|
||
expect(receivedTokenUri).to.be.equal(tokenUri); | ||
expectEvent(receipt, 'URI', { value: tokenUri, id: tokenId }); | ||
}); | ||
}); | ||
}); |