diff --git a/src/main/java/io/nfteam/nftlab/hotmoka/erc721/ERC721.java b/src/main/java/io/nfteam/nftlab/hotmoka/erc721/ERC721.java index b242a85..5a1e1a0 100644 --- a/src/main/java/io/nfteam/nftlab/hotmoka/erc721/ERC721.java +++ b/src/main/java/io/nfteam/nftlab/hotmoka/erc721/ERC721.java @@ -6,8 +6,6 @@ import io.takamaka.code.util.StorageMapView; import io.takamaka.code.util.StorageTreeMap; -import java.util.function.Supplier; - public class ERC721 extends Contract implements IERC721Metadata { private final String name; private final String symbol; @@ -36,51 +34,44 @@ public class ERC721 extends Contract implements IERC721Metadata { // ============ Getters ============ - @Override - public final @View - String name() { + @Override @View + public final String name() { return name; } - @Override - public final @View - String symbol() { + @Override @View + public final String symbol() { return symbol; } // ============ Transfer ============ - @Override - public @FromContract - void safeTransferFrom(Contract from, Contract to, UnsignedBigInteger tokenId) { + @Override @FromContract + public void safeTransferFrom(Contract from, Contract to, UnsignedBigInteger tokenId) { safeTransferFrom(from, to, tokenId, "".getBytes()); } - @Override - public @FromContract - void transferFrom(Contract from, Contract to, UnsignedBigInteger tokenId) { + @Override @FromContract + public void transferFrom(Contract from, Contract to, UnsignedBigInteger tokenId) { Takamaka.require(_isApprovedOrOwner(caller(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); } - @Override - public @FromContract - void safeTransferFrom(Contract from, Contract to, UnsignedBigInteger tokenId, byte[] data) { + @Override @FromContract + public void safeTransferFrom(Contract from, Contract to, UnsignedBigInteger tokenId, byte[] data) { Takamaka.require(_isApprovedOrOwner(caller(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransfer(from, to, tokenId, data); } - protected - void _safeTransfer(Contract from, Contract to, UnsignedBigInteger tokenId, byte[] data) { + protected void _safeTransfer(Contract from, Contract to, UnsignedBigInteger tokenId, byte[] data) { _transfer(from, to, tokenId); // TODO: Call to _checkOnERC721Received } protected void _beforeTokenTransfer(Contract from, Contract to, UnsignedBigInteger tokenId) { } - protected - void _transfer(Contract from, Contract to, UnsignedBigInteger tokenId) { + protected void _transfer(Contract from, Contract to, UnsignedBigInteger tokenId) { Takamaka.require(ownerOf(tokenId).equals(from), "ERC721: transfer of token that is not own"); Takamaka.require(to != null, "ERC721: transfer to the zero address"); @@ -98,9 +89,8 @@ void _transfer(Contract from, Contract to, UnsignedBigInteger tokenId) { // ============ Approvals ============ - @Override - public @FromContract - void approve(Contract to, UnsignedBigInteger tokenId) { + @Override @FromContract + public void approve(Contract to, UnsignedBigInteger tokenId) { Contract owner = ownerOf(tokenId); Takamaka.require(!owner.equals(to), "ERC721: approval to current owner"); @@ -112,40 +102,35 @@ void approve(Contract to, UnsignedBigInteger tokenId) { _approve(to, tokenId); } - private - void _approve(Contract to, UnsignedBigInteger tokenId) { + private void _approve(Contract to, UnsignedBigInteger tokenId) { tokenApprovals.put(tokenId, to); event(new Approval(ownerOf(tokenId), to, tokenId)); } - @Override - public @FromContract - void setApprovalForAll(Contract operator, boolean _approved) { + @Override @FromContract + public void setApprovalForAll(Contract operator, boolean _approved) { Takamaka.require(operator != caller(), "ERC721: approve to caller"); - operatorApprovals - .computeIfAbsent(caller(), (Supplier>) StorageTreeMap::new) - .put(operator, _approved); + operatorApprovals.putIfAbsent(caller(), new StorageTreeMap<>()); + + operatorApprovals.get(caller()).put(operator, _approved); event(new ApprovalForAll(caller(), operator, _approved)); } - @Override - public @View - Contract getApproved(UnsignedBigInteger tokenId) { + @Override @View + public Contract getApproved(UnsignedBigInteger tokenId) { Takamaka.require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return tokenApprovals.get(tokenId); } - @Override - public final @View - boolean isApprovedForAll(Contract owner, Contract operator) { + @Override @View + public final boolean isApprovedForAll(Contract owner, Contract operator) { return operatorApprovals.getOrDefault(owner, StorageTreeMap::new).getOrDefault(operator, false); } - protected - boolean _isApprovedOrOwner(Contract spender, UnsignedBigInteger tokenId) { + protected boolean _isApprovedOrOwner(Contract spender, UnsignedBigInteger tokenId) { Takamaka.require(_exists(tokenId), "ERC721: operator query for nonexistent token"); Contract owner = ownerOf(tokenId); @@ -154,19 +139,16 @@ boolean _isApprovedOrOwner(Contract spender, UnsignedBigInteger tokenId) { // ============ MINT ============ - protected - void _safeMint(Contract to, UnsignedBigInteger tokenId) { + protected void _safeMint(Contract to, UnsignedBigInteger tokenId) { _safeMint(to, tokenId, "".getBytes()); } - protected - void _safeMint(Contract to, UnsignedBigInteger tokenId, byte[] data) { + protected void _safeMint(Contract to, UnsignedBigInteger tokenId, byte[] data) { _mint(to, tokenId); // TODO: _checkOnERC721Received call } - protected - void _mint(Contract to, UnsignedBigInteger tokenId) { + protected void _mint(Contract to, UnsignedBigInteger tokenId) { Takamaka.require(to != null, "ERC721: mint to the zero address"); Takamaka.require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(null, to, tokenId); @@ -179,9 +161,8 @@ void _mint(Contract to, UnsignedBigInteger tokenId) { // ============ Token URI ============ - @Override - public @View - String tokenURI(UnsignedBigInteger tokenId) { + @Override @View + public String tokenURI(UnsignedBigInteger tokenId) { Takamaka.require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); String baseURI = _baseURI(); @@ -190,16 +171,15 @@ String tokenURI(UnsignedBigInteger tokenId) { : ""; } - protected @View - String _baseURI() { + @View + protected String _baseURI() { return ""; } // ============ Balance of ============ - @Override - public @View - UnsignedBigInteger balanceOf(Contract owner) { + @Override @View + public UnsignedBigInteger balanceOf(Contract owner) { Takamaka.require(owner != null, "ERC721: balance query for the zero address"); return balances.getOrDefault(owner, ZERO); @@ -207,9 +187,8 @@ UnsignedBigInteger balanceOf(Contract owner) { // ============ Owner of ============ - @Override - public @View - Contract ownerOf(UnsignedBigInteger tokenId) { + @Override @View + public Contract ownerOf(UnsignedBigInteger tokenId) { Contract owner = owners.get(tokenId); Takamaka.require(owner != null, "ERC721: owner query for nonexistent token"); @@ -226,15 +205,13 @@ protected class ERC721Snapshot extends Storage implements IERC721View { private final StorageMapView tokenApprovals = ERC721.this.tokenApprovals.snapshot(); private final StorageMapView> operatorApprovals = ERC721.this.operatorApprovals.snapshot(); - @Override - public @View - UnsignedBigInteger balanceOf(Contract owner) { + @Override @View + public UnsignedBigInteger balanceOf(Contract owner) { return balances.getOrDefault(owner, ZERO); } - @Override - public @View - Contract ownerOf(UnsignedBigInteger tokenId) { + @Override @View + public Contract ownerOf(UnsignedBigInteger tokenId) { Contract owner = owners.get(tokenId); Takamaka.require(owner != null, "ERC721: owner query for nonexistent token"); @@ -242,36 +219,32 @@ Contract ownerOf(UnsignedBigInteger tokenId) { return owner; } - @Override - public @View - Contract getApproved(UnsignedBigInteger tokenId) { + @Override @View + public Contract getApproved(UnsignedBigInteger tokenId) { Takamaka.require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return tokenApprovals.get(tokenId); } - @Override - public @View - boolean isApprovedForAll(Contract owner, Contract operator) { + @Override @View + public boolean isApprovedForAll(Contract owner, Contract operator) { return operatorApprovals.getOrDefault(owner, StorageTreeMap::new).getOrDefault(operator, false); } - @Override - public @View - IERC721View snapshot() { + @Override @View + public IERC721View snapshot() { return this; } } - @Override + @Override @View public IERC721View snapshot() { return new ERC721Snapshot(); } // ============ Burn ============ - protected - void _burn(UnsignedBigInteger tokenId) { + protected void _burn(UnsignedBigInteger tokenId) { Contract owner = ownerOf(tokenId); _beforeTokenTransfer(owner, null, tokenId); @@ -287,8 +260,8 @@ void _burn(UnsignedBigInteger tokenId) { // ============ Exists ============ - protected final @View - boolean _exists(UnsignedBigInteger tokenId) { + @View + protected final boolean _exists(UnsignedBigInteger tokenId) { return owners.get(tokenId) != null; } @@ -299,8 +272,7 @@ boolean _exists(UnsignedBigInteger tokenId) { * * @param event the event to generate */ - protected final - void event(Event event) { + protected final void event(Event event) { if (generateEvents) { Takamaka.event(event); } diff --git a/src/main/java/io/nfteam/nftlab/hotmoka/erc721/IERC721View.java b/src/main/java/io/nfteam/nftlab/hotmoka/erc721/IERC721View.java index 6fa12d4..407e235 100644 --- a/src/main/java/io/nfteam/nftlab/hotmoka/erc721/IERC721View.java +++ b/src/main/java/io/nfteam/nftlab/hotmoka/erc721/IERC721View.java @@ -34,5 +34,6 @@ public interface IERC721View { @View boolean isApprovedForAll(Contract owner, Contract operator); + @View IERC721View snapshot(); } diff --git a/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721Burnable.java b/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721Burnable.java index 6fd834d..346ee12 100644 --- a/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721Burnable.java +++ b/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721Burnable.java @@ -7,13 +7,11 @@ abstract public class ERC721Burnable extends ERC721 { - public - ERC721Burnable(String name, String symbol) { + public ERC721Burnable(String name, String symbol) { super(name, symbol); } - public - ERC721Burnable(String name, String symbol, boolean generateEvents) { + public ERC721Burnable(String name, String symbol, boolean generateEvents) { super(name, symbol, generateEvents); } @@ -24,8 +22,8 @@ abstract public class ERC721Burnable extends ERC721 * * - The caller must own (@code tokenId) or be an approved operator. */ - public @FromContract - void burn(UnsignedBigInteger tokenId) { + @FromContract + public void burn(UnsignedBigInteger tokenId) { Takamaka.require(_isApprovedOrOwner(caller(), tokenId), "ERC721Burnable: caller is not owner nor approved"); _burn(tokenId); diff --git a/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721Enumerable.java b/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721Enumerable.java index 68eae89..bbb990a 100644 --- a/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721Enumerable.java +++ b/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721Enumerable.java @@ -31,22 +31,23 @@ public ERC721Enumerable(String name, String symbol, boolean generateEvents) { } - @Override - public @View - UnsignedBigInteger totalSupply() { + @Override @View + public UnsignedBigInteger totalSupply() { return UnsignedBigInteger.valueOf(allTokens.size()); } - @Override - public @View - UnsignedBigInteger tokenOfOwnerByIndex(Contract owner, UnsignedBigInteger index) { - Takamaka.require(index.compareTo(balanceOf(owner)) < 0, "ERC721Enumerable: owner index out of bounds"); + @Override @View + public UnsignedBigInteger tokenOfOwnerByIndex(Contract owner, UnsignedBigInteger index) { + Takamaka.require( + index.compareTo(balanceOf(owner)) < 0, + "ERC721Enumerable: owner index out of bounds" + ); + return ownedTokens.getOrDefault(owner, StorageTreeMap::new).getOrDefault(index, (UnsignedBigInteger) null); } - @Override - public @View - UnsignedBigInteger tokenByIndex(UnsignedBigInteger index) { + @Override @View + public UnsignedBigInteger tokenByIndex(UnsignedBigInteger index) { Takamaka.require(index.compareTo(totalSupply()) < 0, "ERC721Enumerable: global index out of bounds"); return allTokens.get(index.toBigInteger().intValue()); @@ -68,24 +69,25 @@ protected void _beforeTokenTransfer(Contract from, Contract to, UnsignedBigInteg /** * Private function to add a token to this extension's ownership-tracking data structures. - * @param to address representing the new owner of the given token ID + * + * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ - private - void _addTokenToOwnerEnumeration(Contract to, UnsignedBigInteger tokenId) { + private void _addTokenToOwnerEnumeration(Contract to, UnsignedBigInteger tokenId) { UnsignedBigInteger length = balanceOf(to); - ownedTokens - .computeIfAbsent(to, (Supplier>) StorageTreeMap::new) - .put(length, tokenId); + + ownedTokens.putIfAbsent(to, new StorageTreeMap<>()); + ownedTokens.get(to).put(length, tokenId); + ownedTokensIndex.put(tokenId, length); } /** * Private function to add a token to this extension's token tracking data structures. + * * @param tokenId uint256 ID of the token to be added to the tokens list */ - private - void _addTokenToAllTokensEnumeration(UnsignedBigInteger tokenId) { + private void _addTokenToAllTokensEnumeration(UnsignedBigInteger tokenId) { UnsignedBigInteger index = UnsignedBigInteger.valueOf(allTokens.size()); allTokensIndex.put(tokenId, UnsignedBigInteger.valueOf(allTokens.size())); allTokens.put(index, tokenId); @@ -96,11 +98,11 @@ void _addTokenToAllTokensEnumeration(UnsignedBigInteger tokenId) { * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. - * @param from address representing the previous owner of the given token ID + * + * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address */ - private - void _removeTokenFromOwnerEnumeration(Contract from, UnsignedBigInteger tokenId) { + private void _removeTokenFromOwnerEnumeration(Contract from, UnsignedBigInteger tokenId) { // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). @@ -111,9 +113,9 @@ void _removeTokenFromOwnerEnumeration(Contract from, UnsignedBigInteger tokenId) if (!tokenIndex.equals(lastTokenIndex)) { UnsignedBigInteger lastTokenId = ownedTokens.getOrDefault(from, StorageTreeMap::new).getOrDefault(lastTokenIndex, ZERO); - ownedTokens - .computeIfAbsent(from, (Supplier>) StorageTreeMap::new) - .put(tokenIndex, lastTokenId); // Move the last token to the slot of the to-delete token + ownedTokens.putIfAbsent(from, new StorageTreeMap<>()); + ownedTokens.get(from).put(tokenIndex, lastTokenId); // Move the last token to the slot of the to-delete token + ownedTokensIndex.put(lastTokenId, tokenIndex); // Update the moved token's index } @@ -125,10 +127,10 @@ void _removeTokenFromOwnerEnumeration(Contract from, UnsignedBigInteger tokenId) /** * Private function to remove a token from this extension's token tracking data structures. * This has O(1) time complexity, but alters the order of the _allTokens array. + * * @param tokenId uint256 ID of the token to be removed from the tokens list */ - private - void _removeTokenFromAllTokensEnumeration(UnsignedBigInteger tokenId) { + private void _removeTokenFromAllTokensEnumeration(UnsignedBigInteger tokenId) { // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). @@ -183,15 +185,14 @@ public UnsignedBigInteger tokenByIndex(UnsignedBigInteger index) { return allTokens.get(index.toBigInteger().intValue()); } - @Override - public @View - IERC721EnumerableView snapshot() { + @Override @View + public IERC721EnumerableView snapshot() { return this; } } - public @View - IERC721EnumerableView snapshot() { + @View + public IERC721EnumerableView snapshot() { return new ERC721EnumerableSnapshot(); } } diff --git a/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721URIStorage.java b/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721URIStorage.java index ef19b01..c48fda0 100644 --- a/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721URIStorage.java +++ b/src/main/java/io/nfteam/nftlab/hotmoka/erc721/extensions/ERC721URIStorage.java @@ -10,18 +10,16 @@ abstract public class ERC721URIStorage extends ERC721 implements IERC721URIStorageView { private final StorageMap tokenURIs = new StorageTreeMap<>(); - public - ERC721URIStorage(String name, String symbol) { + public ERC721URIStorage(String name, String symbol) { super(name, symbol); } - public - ERC721URIStorage(String name, String symbol, boolean generateEvents) { + public ERC721URIStorage(String name, String symbol, boolean generateEvents) { super(name, symbol, generateEvents); } - public @View - String tokenURI(UnsignedBigInteger tokenId) { + @View + public String tokenURI(UnsignedBigInteger tokenId) { Takamaka.require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token"); String tokenURI = tokenURIs.getOrDefault(tokenId, ""); @@ -44,8 +42,7 @@ String tokenURI(UnsignedBigInteger tokenId) { * * - (@code tokenId) must exist. */ - protected - void _setTokenURI(UnsignedBigInteger tokenId, String tokenURI) { + protected void _setTokenURI(UnsignedBigInteger tokenId, String tokenURI) { Takamaka.require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token"); tokenURIs.put(tokenId, tokenURI); } @@ -60,8 +57,7 @@ void _setTokenURI(UnsignedBigInteger tokenId, String tokenURI) { * Emits a (@link ERC721.Transfer) event. */ @Override - protected - void _burn(UnsignedBigInteger tokenId) { + protected void _burn(UnsignedBigInteger tokenId) { super._burn(tokenId); tokenURIs.remove(tokenId); @@ -71,9 +67,8 @@ void _burn(UnsignedBigInteger tokenId) { protected class ERC721URIStorageSnapshot extends ERC721.ERC721Snapshot implements IERC721URIStorageView { private final StorageMapView tokenURIs = ERC721URIStorage.this.tokenURIs; - @Override - public @View - String tokenURI(UnsignedBigInteger tokenId) { + @Override @View + public String tokenURI(UnsignedBigInteger tokenId) { Takamaka.require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token"); String tokenURI = tokenURIs.getOrDefault(tokenId, ""); @@ -89,14 +84,13 @@ String tokenURI(UnsignedBigInteger tokenId) { return _baseURI() + tokenId.toString(); } - @Override - public @View - IERC721URIStorageView snapshot() { + @Override @View + public IERC721URIStorageView snapshot() { return this; } } - @Override + @Override @View public IERC721URIStorageView snapshot() { return new ERC721URIStorageSnapshot(); }